go.charczuk.com@v0.0.0-20240327042549-bc490516bd1a/experiments/huectl/pkg/hue/light.go (about) 1 /* 2 3 Copyright (c) 2023 - Present. Will Charczuk. All rights reserved. 4 Use of this source code is governed by a MIT license that can be found in the LICENSE file at the root of the repository. 5 6 */ 7 8 package hue 9 10 import ( 11 "context" 12 "fmt" 13 ) 14 15 // Light represents a bridge light https://developers.meethue.com/documentation/lights-api 16 type Light struct { 17 bridge Bridge 18 19 ID int `json:"id,omitempty"` 20 Config LightConfig `json:"config,omitempty"` 21 Capabilities LightCapabilities `json:"capabilities,omitempty"` 22 ManufacturerName string `json:"manufacturername,omitempty"` 23 ModelID string `json:"modelid,omitempty"` 24 Name string `json:"name,omitempty"` 25 ProductName string `json:"productname,omitempty"` 26 State LightState `json:"state,omitempty"` 27 SwConfigID string `json:"swconfigid,omitempty"` 28 SwVersion string `json:"swversion,omitempty"` 29 Type string `json:"type,omitempty"` 30 UniqueID string `json:"uniqueid,omitempty"` 31 } 32 33 // String returns a new string form of the light. 34 func (l Light) String() string { 35 return fmt.Sprintf("%d %s", l.ID, l.Name) 36 } 37 38 // LightConfig holds light config options. 39 type LightConfig struct { 40 Archetype string `json:"archetype,omitempty"` 41 Function string `json:"function,omitempty"` 42 Direction string `json:"direction,omitempty"` 43 } 44 45 // LightCapabilities holds light capabilities. 46 type LightCapabilities struct { 47 Certified bool `json:"certified,omitempty"` 48 Control LightCapabilitiesControl `json:"control,omitempty"` 49 Streaming LightCapabilitiesStreaming `json:"streaming,omitempty"` 50 } 51 52 // LightCapabilitiesControl holds light capabilities for control. 53 type LightCapabilitiesControl struct { 54 MinDimLevel int `json:"mindimlevel,omitempty"` 55 MaxLumen int `json:"maxlumen,omitempty"` 56 ColorGamutType string `json:"colorgamuttype,omitempty"` 57 ColorGamut [][]float64 `json:"colorgamut,omitempty"` 58 ColorTemperature MinMaxInt `json:"ct,omitempty"` 59 } 60 61 // MinMaxInt represents a minimum and a maximum integer. 62 type MinMaxInt struct { 63 Min int `json:"min,omitempty"` 64 Max int `json:"max,omitempty"` 65 } 66 67 // LightCapabilitiesStreaming holds the light streaming capabilities. 68 type LightCapabilitiesStreaming struct { 69 Renderer bool `json:"renderer,omitempty"` 70 Proxy bool `json:"proxy,omitempty"` 71 } 72 73 // LightState defines the attributes and properties of a light 74 type LightState struct { 75 Alert string `json:"alert,omitempty"` 76 Bri uint8 `json:"bri,omitempty"` 77 BriInc int `json:"bri_inc,omitempty"` 78 ColorMode string `json:"colormode,omitempty"` 79 Ct uint16 `json:"ct,omitempty"` 80 CtInc int `json:"ct_inc,omitempty"` 81 Effect string `json:"effect,omitempty"` 82 Hue uint16 `json:"hue,omitempty"` 83 HueInc int `json:"hue_inc,omitempty"` 84 On bool `json:"on"` 85 Reachable bool `json:"reachable,omitempty"` 86 Sat uint8 `json:"sat,omitempty"` 87 SatInc int `json:"sat_inc,omitempty"` 88 Scene string `json:"scene,omitempty"` 89 TransitionTime uint16 `json:"transitiontime,omitempty"` 90 Xy []float32 `json:"xy,omitempty"` 91 XyInc int `json:"xy_inc,omitempty"` 92 } 93 94 // Lights defines a list of lights discovered the last time the bridge performed a light discovery. 95 // Also stores the timestamp the last time a discovery was performed. 96 type Lights struct { 97 Lights []string 98 LastScan string `json:"lastscan"` 99 } 100 101 // SetState sets the state of the light to s. 102 func (l *Light) SetState(ctx context.Context, s LightState) error { 103 _, err := l.bridge.SetLightState(ctx, l.ID, s) 104 if err != nil { 105 return err 106 } 107 l.State = s 108 return nil 109 } 110 111 // Off sets the On state of one light to false, turning it off 112 func (l *Light) Off(ctx context.Context) error { 113 state := LightState{} 114 _, err := l.bridge.SetLightState(ctx, l.ID, state) 115 if err != nil { 116 return err 117 } 118 l.State.On = false 119 return nil 120 } 121 122 // On sets the On state of one light to true, turning it on 123 func (l *Light) On(ctx context.Context) error { 124 state := LightState{On: true} 125 _, err := l.bridge.SetLightState(ctx, l.ID, state) 126 if err != nil { 127 return err 128 } 129 l.State.On = true 130 return nil 131 } 132 133 // IsOn returns true if light state On property is true 134 func (l *Light) IsOn() bool { 135 return l.State.On 136 } 137 138 // Rename sets the name property of the light 139 func (l *Light) Rename(ctx context.Context, new string) error { 140 update := Light{Name: new} 141 _, err := l.bridge.UpdateLight(ctx, l.ID, update) 142 if err != nil { 143 return err 144 } 145 l.Name = new 146 return nil 147 } 148 149 // Brightness sets the light brightness state property 150 func (l *Light) Brightness(ctx context.Context, new uint8) error { 151 update := LightState{On: true, Bri: new} 152 _, err := l.bridge.SetLightState(ctx, l.ID, update) 153 if err != nil { 154 return err 155 } 156 l.State.Bri = new 157 l.State.On = true 158 return nil 159 } 160 161 // Hue sets the light hue state property (0-65535). 162 // 163 // Use the color helpers to create a more user-friendly input. 164 func (l *Light) Hue(ctx context.Context, new uint16) error { 165 update := LightState{On: true, Hue: new} 166 _, err := l.bridge.SetLightState(ctx, l.ID, update) 167 if err != nil { 168 return err 169 } 170 l.State.Hue = new 171 l.State.On = true 172 return nil 173 } 174 175 // Saturation sets the light saturation state property (0-254) 176 func (l *Light) Saturation(ctx context.Context, new uint8) error { 177 update := LightState{On: true, Sat: new} 178 _, err := l.bridge.SetLightState(ctx, l.ID, update) 179 if err != nil { 180 return err 181 } 182 l.State.Sat = new 183 l.State.On = true 184 return nil 185 } 186 187 // Xy sets the x and y coordinates of a color in CIE color space. (0-1 per value) 188 func (l *Light) Xy(ctx context.Context, new []float32) error { 189 update := LightState{On: true, Xy: new} 190 _, err := l.bridge.SetLightState(ctx, l.ID, update) 191 if err != nil { 192 return err 193 } 194 l.State.Xy = new 195 l.State.On = true 196 return nil 197 } 198 199 // ColorTemperature sets the light color temperature state property 200 func (l *Light) ColorTemperature(ctx context.Context, new uint16) error { 201 update := LightState{On: true, Ct: new} 202 _, err := l.bridge.SetLightState(ctx, l.ID, update) 203 if err != nil { 204 return err 205 } 206 l.State.Ct = new 207 l.State.On = true 208 return nil 209 } 210 211 // Color sets the light color as RGB (will be converted to xy) 212 func (l *Light) Color(ctx context.Context, new Color) error { 213 xy := new.XY(GetGamutForModelID(l.ModelID)) 214 update := LightState{On: true, Xy: xy, Bri: l.State.Bri} 215 _, err := l.bridge.SetLightState(ctx, l.ID, update) 216 if err != nil { 217 return err 218 } 219 l.State.Xy = xy 220 l.State.On = true 221 return nil 222 } 223 224 // TransitionTime sets the duration of the transition from the light’s current state to the new state 225 func (l *Light) TransitionTime(ctx context.Context, new uint16) error { 226 update := LightState{On: l.State.On, TransitionTime: new} 227 _, err := l.bridge.SetLightState(ctx, l.ID, update) 228 if err != nil { 229 return err 230 } 231 l.State.TransitionTime = new 232 return nil 233 } 234 235 // Effect the dynamic effect of the light, currently “none” and “colorloop” are supported 236 func (l *Light) Effect(ctx context.Context, new string) error { 237 update := LightState{On: true, Effect: new} 238 _, err := l.bridge.SetLightState(ctx, l.ID, update) 239 if err != nil { 240 return err 241 } 242 l.State.Effect = new 243 l.State.On = true 244 return nil 245 } 246 247 // Alert makes the light blink in its current color. Supported values are: 248 // “none” – The light is not performing an alert effect. 249 // “select” – The light is performing one breathe cycle. 250 // “lselect” – The light is performing breathe cycles for 15 seconds or until alert is set to "none". 251 func (l *Light) Alert(ctx context.Context, new string) error { 252 update := LightState{On: true, Alert: new} 253 _, err := l.bridge.SetLightState(ctx, l.ID, update) 254 if err != nil { 255 return err 256 } 257 l.State.Effect = new 258 l.State.On = true 259 return nil 260 }