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.

280 lines
7.3 KiB

  1. package hue2
  2. import (
  3. "encoding/json"
  4. "encoding/xml"
  5. "fmt"
  6. "git.aiterp.net/lucifer/new-server/internal/color"
  7. "strings"
  8. "time"
  9. )
  10. type DeviceData struct {
  11. ID string `json:"id"`
  12. LegacyID string `json:"id_v1"`
  13. Metadata DeviceMetadata `json:"metadata"`
  14. Type string `json:"type"`
  15. ProductData DeviceProductData `json:"product_data"`
  16. Services []ResourceLink `json:"services"`
  17. }
  18. type DeviceMetadata struct {
  19. Archetype string `json:"archetype"`
  20. Name string `json:"name"`
  21. }
  22. type DeviceProductData struct {
  23. Certified bool `json:"certified"`
  24. ManufacturerName string `json:"manufacturer_name"`
  25. ModelID string `json:"model_id"`
  26. ProductArchetype string `json:"product_archetype"`
  27. ProductName string `json:"product_name"`
  28. SoftwareVersion string `json:"software_version"`
  29. }
  30. type SSEUpdate struct {
  31. CreationTime time.Time `json:"creationTime"`
  32. ID string `json:"id"`
  33. Type string `json:"type"`
  34. Data []ResourceData `json:"data"`
  35. }
  36. type ResourceData struct {
  37. ID string `json:"id"`
  38. LegacyID string `json:"id_v1"`
  39. Metadata DeviceMetadata `json:"metadata"`
  40. Type string `json:"type"`
  41. Mode *string `json:"mode"`
  42. Owner *ResourceLink `json:"owner"`
  43. ProductData *DeviceProductData `json:"product_data"`
  44. Services []ResourceLink `json:"services"`
  45. Button *SensorButton `json:"button"`
  46. Power *LightPower `json:"on"`
  47. Color *LightColor `json:"color"`
  48. ColorTemperature *LightCT `json:"color_temperature"`
  49. Dimming *LightDimming `json:"dimming"`
  50. Dynamics *LightDynamics `json:"dynamics"`
  51. Alert *LightAlert `json:"alert"`
  52. PowerState *PowerState `json:"power_state"`
  53. Temperature *SensorTemperature `json:"temperature"`
  54. Motion *SensorMotion `json:"motion"`
  55. Status *string `json:"status"`
  56. }
  57. func (res *ResourceData) ServiceID(kind string) *string {
  58. for _, ptr := range res.Services {
  59. if ptr.Kind == kind {
  60. return &ptr.ID
  61. }
  62. }
  63. return nil
  64. }
  65. func (res *ResourceData) ServiceIndex(kind string, id string) int {
  66. idx := 0
  67. for _, link := range res.Services {
  68. if link.ID == id {
  69. return idx
  70. } else if link.Kind == kind {
  71. idx += 1
  72. }
  73. }
  74. return -1
  75. }
  76. func (res *ResourceData) WithUpdate(update ResourceUpdate) *ResourceData {
  77. resCopy := *res
  78. if update.Name != nil {
  79. resCopy.Metadata.Name = *update.Name
  80. }
  81. if update.Power != nil {
  82. cp := *resCopy.Power
  83. resCopy.Power = &cp
  84. resCopy.Power.On = *update.Power
  85. }
  86. if update.ColorXY != nil {
  87. cp := *resCopy.Color
  88. resCopy.Color = &cp
  89. resCopy.Color.XY = *update.ColorXY
  90. if resCopy.ColorTemperature != nil {
  91. cp := *resCopy.ColorTemperature
  92. resCopy.ColorTemperature = &cp
  93. resCopy.ColorTemperature.Mirek = nil
  94. }
  95. }
  96. if update.Mirek != nil {
  97. cp := *resCopy.ColorTemperature
  98. resCopy.ColorTemperature = &cp
  99. mirek := *update.Mirek
  100. resCopy.ColorTemperature.Mirek = &mirek
  101. }
  102. if update.Brightness != nil {
  103. cp := *resCopy.Dimming
  104. resCopy.Dimming = &cp
  105. resCopy.Dimming.Brightness = *update.Brightness
  106. }
  107. return &resCopy
  108. }
  109. type SensorButton struct {
  110. LastEvent string `json:"last_event"`
  111. }
  112. type SensorMotion struct {
  113. Motion bool `json:"motion"`
  114. Valid bool `json:"motion_valid"`
  115. }
  116. type SensorTemperature struct {
  117. Temperature float64 `json:"temperature"`
  118. Valid bool `json:"temperature_valid"`
  119. }
  120. type PowerState struct {
  121. BatteryState string `json:"battery_state"`
  122. BatteryLevel float64 `json:"battery_level"`
  123. }
  124. type LightPower struct {
  125. On bool `json:"on"`
  126. }
  127. type LightDimming struct {
  128. Brightness float64 `json:"brightness"`
  129. }
  130. type LightColor struct {
  131. Gamut color.Gamut `json:"gamut"`
  132. GamutType string `json:"gamut_type"`
  133. XY color.XY `json:"xy"`
  134. }
  135. type LightCT struct {
  136. Mirek *int `json:"mirek"`
  137. MirekSchema LightCTMirekSchema `json:"mirek_schema"`
  138. MirekValid bool `json:"mirek_valid"`
  139. }
  140. type LightCTMirekSchema struct {
  141. MirekMaximum int `json:"mirek_maximum"`
  142. MirekMinimum int `json:"mirek_minimum"`
  143. }
  144. type LightDynamics struct {
  145. Speed float64 `json:"speed"`
  146. SpeedValid bool `json:"speed_valid"`
  147. Status string `json:"status"`
  148. StatusValues []string `json:"status_values"`
  149. }
  150. type LightAlert struct {
  151. ActionValues []string `json:"action_values"`
  152. }
  153. type ResourceUpdate struct {
  154. Name *string
  155. Power *bool
  156. ColorXY *color.XY
  157. Brightness *float64
  158. Mirek *int
  159. TransitionDuration *time.Duration
  160. }
  161. func (r ResourceUpdate) MarshalJSON() ([]byte, error) {
  162. chunks := make([]string, 0, 4)
  163. if r.Name != nil {
  164. s, _ := json.Marshal(*r.Name)
  165. chunks = append(chunks, fmt.Sprintf(`"metadata":{"name":%s}`, string(s)))
  166. }
  167. if r.Power != nil {
  168. chunks = append(chunks, fmt.Sprintf(`"on":{"on":%v}`, *r.Power))
  169. }
  170. if r.ColorXY != nil {
  171. chunks = append(chunks, fmt.Sprintf(`"color":{"xy":{"x":%f,"y":%f}}`, r.ColorXY.X, r.ColorXY.Y))
  172. }
  173. if r.Brightness != nil {
  174. chunks = append(chunks, fmt.Sprintf(`"dimming":{"brightness":%f}`, *r.Brightness))
  175. }
  176. if r.Mirek != nil {
  177. chunks = append(chunks, fmt.Sprintf(`"color_temperature":{"mirek":%d}`, *r.Mirek))
  178. }
  179. if r.TransitionDuration != nil {
  180. chunks = append(chunks, fmt.Sprintf(`"dynamics":{"duration":%d}`, r.TransitionDuration.Truncate(time.Millisecond*100).Milliseconds()))
  181. }
  182. return []byte(fmt.Sprintf("{%s}", strings.Join(chunks, ","))), nil
  183. }
  184. type ResourceLink struct {
  185. ID string `json:"rid"`
  186. Kind string `json:"rtype"`
  187. }
  188. func (rl *ResourceLink) Path() string {
  189. return fmt.Sprintf("/clip/v2/resource/%s/%s", rl.Kind, rl.ID)
  190. }
  191. type CreateUserInput struct {
  192. DeviceType string `json:"devicetype"`
  193. }
  194. type CreateUserResponse struct {
  195. Success *struct {
  196. Username string `json:"username"`
  197. } `json:"success"`
  198. Error *struct {
  199. Type int `json:"type"`
  200. Address string `json:"address"`
  201. Description string `json:"description"`
  202. } `json:"error"`
  203. }
  204. type DiscoveryEntry struct {
  205. Id string `json:"id"`
  206. InternalIPAddress string `json:"internalipaddress"`
  207. }
  208. type BridgeDeviceInfo struct {
  209. XMLName xml.Name `xml:"root"`
  210. Text string `xml:",chardata"`
  211. Xmlns string `xml:"xmlns,attr"`
  212. SpecVersion struct {
  213. Text string `xml:",chardata"`
  214. Major string `xml:"major"`
  215. Minor string `xml:"minor"`
  216. } `xml:"specVersion"`
  217. URLBase string `xml:"URLBase"`
  218. Device struct {
  219. Text string `xml:",chardata"`
  220. DeviceType string `xml:"deviceType"`
  221. FriendlyName string `xml:"friendlyName"`
  222. Manufacturer string `xml:"manufacturer"`
  223. ManufacturerURL string `xml:"manufacturerURL"`
  224. ModelDescription string `xml:"modelDescription"`
  225. ModelName string `xml:"modelName"`
  226. ModelNumber string `xml:"modelNumber"`
  227. ModelURL string `xml:"modelURL"`
  228. SerialNumber string `xml:"serialNumber"`
  229. UDN string `xml:"UDN"`
  230. PresentationURL string `xml:"presentationURL"`
  231. IconList struct {
  232. Text string `xml:",chardata"`
  233. Icon struct {
  234. Text string `xml:",chardata"`
  235. Mimetype string `xml:"mimetype"`
  236. Height string `xml:"height"`
  237. Width string `xml:"width"`
  238. Depth string `xml:"depth"`
  239. URL string `xml:"url"`
  240. } `xml:"icon"`
  241. } `xml:"iconList"`
  242. } `xml:"device"`
  243. }