You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

231 lines
4.9 KiB

  1. package nanoleaf
  2. import (
  3. "encoding/binary"
  4. "time"
  5. )
  6. type EffectInfo struct {
  7. EffectsList []string `json:"effectsList"`
  8. Select string `json:"select"`
  9. }
  10. type PanelLayout struct {
  11. GlobalOrientation GlobalOrientation `json:"globalOrientation"`
  12. Data PanelLayoutData `json:"layout"`
  13. }
  14. type GlobalOrientation struct {
  15. Value int `json:"value"`
  16. Max int `json:"max"`
  17. Min int `json:"min"`
  18. }
  19. type PanelLayoutData struct {
  20. NumPanels int `json:"numPanels"`
  21. SideLength int `json:"sideLength"`
  22. PositionData []PositionData `json:"positionData"`
  23. }
  24. type PositionData struct {
  25. PanelID uint16 `json:"panelId"`
  26. X int `json:"x"`
  27. Y int `json:"y"`
  28. O int `json:"o"`
  29. ShapeType int `json:"shapeType"`
  30. }
  31. type StateBool struct {
  32. Value bool `json:"value"`
  33. }
  34. type StateInt struct {
  35. Value int `json:"value"`
  36. Max int `json:"max"`
  37. Min int `json:"min"`
  38. }
  39. type State struct {
  40. Brightness StateInt `json:"brightness"`
  41. ColorMode string `json:"colorMode"`
  42. Ct StateInt `json:"ct"`
  43. Hue StateInt `json:"hue"`
  44. On StateBool `json:"on"`
  45. Sat StateInt `json:"sat"`
  46. }
  47. type Overview struct {
  48. Name string `json:"name"`
  49. SerialNumber string `json:"serialNo"`
  50. Manufacturer string `json:"manufacturer"`
  51. FirmwareVersion string `json:"firmwareVersion"`
  52. HardwareVersion string `json:"hardwareVersion"`
  53. Model string `json:"model"`
  54. Effects EffectInfo `json:"effects"`
  55. PanelLayout PanelLayout `json:"panelLayout"`
  56. State State `json:"state"`
  57. }
  58. type DeviceInfo struct {
  59. SerialNumber string `json:"serialNumber"`
  60. HardwareVersion string `json:"hardwareVersion"`
  61. FirmwareVersion string `json:"firmwareVersion"`
  62. BootloaderVersion string `json:"bootloaderVersion"`
  63. ModelNumber string `json:"modelNumber"`
  64. }
  65. type TokenResponse struct {
  66. Token string `json:"auth_token"`
  67. }
  68. type PanelUpdate []byte
  69. func (u *PanelUpdate) Add(message [8]byte) {
  70. if len(*u) < 2 {
  71. *u = make([]byte, 2, 10)
  72. }
  73. binary.BigEndian.PutUint16(*u, binary.BigEndian.Uint16(*u)+1)
  74. *u = append(*u, message[:]...)
  75. }
  76. func (u *PanelUpdate) Len() int {
  77. if len(*u) < 2 {
  78. return 0
  79. }
  80. return int(binary.BigEndian.Uint16(*u))
  81. }
  82. type PanelEventMessage []byte
  83. func (remote PanelEventMessage) Count() int {
  84. return int(binary.BigEndian.Uint16(remote[0:]))
  85. }
  86. func (remote PanelEventMessage) ValidateLength() bool {
  87. return len(remote) >= (2 + remote.Count()*5)
  88. }
  89. func (remote PanelEventMessage) PanelID(idx int) uint16 {
  90. return binary.BigEndian.Uint16(remote[2+(idx*5):])
  91. }
  92. func (remote PanelEventMessage) TouchType(idx int) int {
  93. value := int(remote[2+(idx*5)])
  94. return (value & 0b11100000) >> 5
  95. }
  96. func (remote PanelEventMessage) TouchStrength(idx int) int {
  97. value := int(remote[2+(idx*5)])
  98. return (value & 0b00011110) >> 1
  99. }
  100. func (remote PanelEventMessage) SwipedFromPanelID(idx int) uint16 {
  101. return binary.BigEndian.Uint16(remote[2+(idx*5)+3:])
  102. }
  103. var shapeTypeMap = map[int]string{
  104. 0: "Legacy Triangle",
  105. 1: "Rhythm",
  106. 2: "Square",
  107. 3: "Control Square Master",
  108. 4: "Control Square Passive",
  109. 7: "Hexagon",
  110. 8: "Triangle",
  111. 9: "Mini Triangle",
  112. 12: "Shapes Controller",
  113. }
  114. var shapeIconMap = map[int]string{
  115. 0: "triangle",
  116. 1: "rhythm",
  117. 2: "Square",
  118. 3: "square",
  119. 4: "square",
  120. 7: "hexagon",
  121. 8: "triangle",
  122. 9: "triangle-small",
  123. 12: "hexagon",
  124. }
  125. var shapeWidthMap = map[int]int{
  126. 0: 150,
  127. 1: -1,
  128. 2: 100,
  129. 3: 100,
  130. 4: 100,
  131. 7: 67,
  132. 8: 134,
  133. 9: 67,
  134. 12: -1,
  135. }
  136. var httpMessage = []byte(`{ "write": { "command": "display", "animType": "extControl", "extControlVersion": "v2" }}`)
  137. type panel struct {
  138. ID uint16
  139. FullID string
  140. On bool
  141. Intensity float64
  142. ColorRGBA [4]byte
  143. TransitionAt time.Time
  144. O int
  145. X int
  146. Y int
  147. ShapeType int
  148. Stale bool
  149. SlowUpdates int
  150. TicksUntilSlowUpdate int
  151. }
  152. func (p *panel) message() (message [8]byte) {
  153. transitionTime := p.TransitionAt.Sub(time.Now()).Round(time.Millisecond * 100)
  154. if transitionTime > maxTransitionTime {
  155. transitionTime = maxTransitionTime
  156. } else if transitionTime < 0 {
  157. transitionTime = 0
  158. }
  159. binary.BigEndian.PutUint16(message[0:], p.ID)
  160. copy(message[2:], p.ColorRGBA[:])
  161. binary.BigEndian.PutUint16(message[6:], uint16(transitionTime/(time.Millisecond*100)))
  162. return
  163. }
  164. func (p *panel) update(colorRGBA [4]byte, transitionAt time.Time) {
  165. if p.ColorRGBA != colorRGBA {
  166. p.ColorRGBA = colorRGBA
  167. p.Stale = true
  168. p.SlowUpdates = 3
  169. p.TicksUntilSlowUpdate = 10
  170. }
  171. p.TransitionAt = transitionAt
  172. }
  173. type panelUpdate []byte
  174. func (u *panelUpdate) Add(message [8]byte) {
  175. if len(*u) < 2 {
  176. *u = make([]byte, 2, 10)
  177. }
  178. binary.BigEndian.PutUint16(*u, binary.BigEndian.Uint16(*u)+1)
  179. *u = append(*u, message[:]...)
  180. }
  181. func (u *panelUpdate) Len() int {
  182. if len(*u) < 2 {
  183. return 0
  184. }
  185. return int(binary.BigEndian.Uint16(*u))
  186. }
  187. const maxTransitionTime = time.Minute * 109