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  }