noolite.go 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. /*
  2. Copyright 2016 Denis V. Dedkov (denis.v.dedkov@gmail.com)
  3. This file is part of Noolite Go bindings.
  4. Noolite Go bindings is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. Noolite Go bindings is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with Noolite Go bindings. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. // Package noolite provide class for control Noolite Adapters PC11xx.
  16. // Protocol described on url:
  17. // http://www.noo.com.by/assets/files/software/PC11xx_HID_API.pdf
  18. package noolite
  19. import (
  20. "errors"
  21. "github.com/tonymagro/usb"
  22. )
  23. const (
  24. VID = 5824 // Vendor ID
  25. PID = 1503 // Product ID
  26. )
  27. // Available commands
  28. type command byte
  29. const (
  30. off command = iota
  31. decBrightnes
  32. on
  33. incBrightnes
  34. cSwitch
  35. invertBrightnes
  36. set
  37. callScenario
  38. saveScenario
  39. unbind
  40. stopColorSelection
  41. bind = iota + 0x04
  42. // Commands for SD111-180 only
  43. colorSelection
  44. colorSwitch
  45. modeSwitch
  46. effectSpeed
  47. )
  48. // Noolite Adapter class as USB HID
  49. type NooliteAdapter struct {
  50. *usb.Device
  51. mode byte
  52. }
  53. // Return NooliteAdapter object.
  54. //
  55. // work mode: range 0..7
  56. // bitrate: range 0..3
  57. // command repeats: range 0..7
  58. func NewNooliteAdapter(mode, bitrate, repeats uint) (*NooliteAdapter, error) {
  59. usb.Init()
  60. d := usb.Open(VID, PID)
  61. if d == nil {
  62. return nil, errors.New("Device not found")
  63. }
  64. if mode > 7 {
  65. return nil, errors.New("Mode must be in 0..7 range")
  66. }
  67. if bitrate > 3 {
  68. return nil, errors.New("Bitrate must be in 0..3 range")
  69. }
  70. if repeats > 7 {
  71. return nil, errors.New("Repeats must be in 0..7 range")
  72. }
  73. m := (byte(repeats) << 5) | (byte(bitrate) << 3) | byte(mode)
  74. d.Interface(0)
  75. if d.LastError() != "No error" {
  76. defer d.Close()
  77. return nil, errors.New(d.LastError())
  78. }
  79. return &NooliteAdapter{d, m}, nil
  80. }
  81. // Return NooliteAdapter object with default work mode values:
  82. //
  83. // work mode: 0
  84. // bitrate: 2 (for 1000 bit/sec)
  85. // command repeats: 2
  86. func DefaultNooliteAdapter() (*NooliteAdapter, error) { // Default constructor
  87. return NewNooliteAdapter(0, 2, 2)
  88. }
  89. // Return NooliteAdapter method for string command
  90. //
  91. // Set command must be separately processed because have different signature
  92. func (n *NooliteAdapter) FindCommand(command string) (func(int) error, bool) {
  93. m := map[string]func(int) error {
  94. "on": n.On,
  95. "off": n.Off,
  96. "switch": n.Switch,
  97. "decraseBrightnes": n.DecraseBrightnes,
  98. "incraseBrightnes": n.IncraseBrightnes,
  99. "invertBrightnes": n.InvertBrightnes,
  100. "callScenario": n.CallScenario,
  101. "saveScenario": n.SaveScenario,
  102. "unbind": n.UnbindChannel,
  103. "stopColorSelection": n.StopColorSelection,
  104. "bind": n.BindChannel,
  105. "colorSelection": n.ColorSelection,
  106. "colorSwitch": n.ColorSwitch,
  107. "modeSwitch": n.ModeSwitch,
  108. "effectSpeed": n.EffectSpeed,
  109. }
  110. cmd, ok := m[command]
  111. return cmd, ok
  112. }
  113. func (n *NooliteAdapter) composeCommand(cmd command, channel int, args ...int) []byte {
  114. c := make([]byte, 8)
  115. c[0] = n.mode
  116. c[1] = byte(cmd)
  117. c[4] = byte(channel)
  118. if cmd == set {
  119. l := len(args)
  120. switch l {
  121. case 1:
  122. {
  123. c[2] = 0x01
  124. c[5] = byte(args[0])
  125. }
  126. case 3:
  127. {
  128. c[2] = 0x03
  129. for i, v := range args {
  130. c[5+i] = byte(v)
  131. }
  132. }
  133. default:
  134. panic("Bad arguments for SET command")
  135. }
  136. }
  137. return c
  138. }
  139. func (n *NooliteAdapter) sendCommand(command []byte) error {
  140. n.ControlMsg(0x21, 0x09, 0x300, 0, command)
  141. if n.LastError() != "No error" {
  142. return errors.New(n.LastError())
  143. }
  144. return nil
  145. }
  146. // Turn power OFF for specified channel
  147. func (n *NooliteAdapter) Off(channel int) error {
  148. cmd := n.composeCommand(off, channel)
  149. return n.sendCommand(cmd)
  150. }
  151. // Smooth brightnes decrase for specified channel
  152. func (n *NooliteAdapter) DecraseBrightnes(channel int) error {
  153. cmd := n.composeCommand(decBrightnes, channel)
  154. return n.sendCommand(cmd)
  155. }
  156. // Turn power ON for specified channel
  157. func (n *NooliteAdapter) On(channel int) error {
  158. cmd := n.composeCommand(on, channel)
  159. return n.sendCommand(cmd)
  160. }
  161. // Smooth brightnes incrase for specified channel
  162. func (n *NooliteAdapter) IncraseBrightnes(channel int) error {
  163. cmd := n.composeCommand(incBrightnes, channel)
  164. return n.sendCommand(cmd)
  165. }
  166. // Switch power state between off and on for specified channel
  167. func (n *NooliteAdapter) Switch(channel int) error {
  168. cmd := n.composeCommand(cSwitch, channel)
  169. return n.sendCommand(cmd)
  170. }
  171. // Smooth brightnes incrase or decrase for specified channel
  172. func (n *NooliteAdapter) InvertBrightnes(channel int) error {
  173. cmd := n.composeCommand(invertBrightnes, channel)
  174. return n.sendCommand(cmd)
  175. }
  176. // Set brightnes value for specified channel
  177. //
  178. // Value must be in range 35..155.
  179. // When value == 0 lights off.
  180. // When value > 155 lights on for full brightness.
  181. func (n *NooliteAdapter) SetBrightnesValue(channel, value int) error {
  182. cmd := n.composeCommand(set, channel, value)
  183. return n.sendCommand(cmd)
  184. }
  185. // Set brightnes values for independens channels
  186. //
  187. // Available for SD111-180 only
  188. func (n *NooliteAdapter) SetBrightnesValues(channel, val1, val2, val3 int) error {
  189. cmd := n.composeCommand(set, channel, val1, val2, val3)
  190. return n.sendCommand(cmd)
  191. }
  192. // Call scenario for specified channel
  193. func (n *NooliteAdapter) CallScenario(channel int) error {
  194. cmd := n.composeCommand(callScenario, channel)
  195. return n.sendCommand(cmd)
  196. }
  197. // Save scenario for specified channel
  198. func (n *NooliteAdapter) SaveScenario(channel int) error {
  199. cmd := n.composeCommand(saveScenario, channel)
  200. return n.sendCommand(cmd)
  201. }
  202. // Unbind signal for specified channel
  203. func (n *NooliteAdapter) UnbindChannel(channel int) error {
  204. cmd := n.composeCommand(unbind, channel)
  205. return n.sendCommand(cmd)
  206. }
  207. // Stop color selection for specified channel
  208. //
  209. // Available for SD111-180 only
  210. func (n *NooliteAdapter) StopColorSelection(channel int) error {
  211. cmd := n.composeCommand(stopColorSelection, channel)
  212. return n.sendCommand(cmd)
  213. }
  214. // Set binding for specified channel
  215. func (n *NooliteAdapter) BindChannel(channel int) error {
  216. cmd := n.composeCommand(bind, channel)
  217. return n.sendCommand(cmd)
  218. }
  219. // Smooth color changing for specified channel
  220. //
  221. // Stop with StopColorSelection method
  222. //
  223. // Avialable for SD111-180 only
  224. func (n *NooliteAdapter) ColorSelection(channel int) error {
  225. cmd := n.composeCommand(colorSelection, channel)
  226. return n.sendCommand(cmd)
  227. }
  228. // Switch color for specified channel
  229. //
  230. // Avialable for SD111-180 only
  231. func (n *NooliteAdapter) ColorSwitch(channel int) error {
  232. cmd := n.composeCommand(colorSwitch, channel)
  233. return n.sendCommand(cmd)
  234. }
  235. // Switch work mode for specified channel
  236. //
  237. // Avialable for SD111-180 only
  238. func (n *NooliteAdapter) ModeSwitch(channel int) error {
  239. cmd := n.composeCommand(modeSwitch, channel)
  240. return n.sendCommand(cmd)
  241. }
  242. // Set change color speed for specified channel
  243. //
  244. // Avialable for SD111-180 only
  245. func (n *NooliteAdapter) EffectSpeed(channel int) error {
  246. cmd := n.composeCommand(effectSpeed, channel)
  247. return n.sendCommand(cmd)
  248. }