github.com/amimof/huego@v1.2.1/group.go (about)

     1  package huego
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"image/color"
     7  )
     8  
     9  // Group represents a bridge group https://developers.meethue.com/documentation/groups-api
    10  type Group struct {
    11  	Name       string               `json:"name,omitempty"`
    12  	Lights     []string             `json:"lights,omitempty"`
    13  	Type       string               `json:"type,omitempty"`
    14  	GroupState *GroupState          `json:"state,omitempty"`
    15  	Recycle    bool                 `json:"recycle,omitempty"`
    16  	Class      string               `json:"class,omitempty"`
    17  	Stream     *Stream              `json:"stream,omitempty"`
    18  	Locations  map[string][]float64 `json:"locations,omitempty"`
    19  	State      *State               `json:"action,omitempty"`
    20  	ID         int                  `json:"-"`
    21  	bridge     *Bridge
    22  }
    23  
    24  // GroupState defines the state on a group.
    25  // Can be used to control the state of all lights in a group rather than controlling them individually
    26  type GroupState struct {
    27  	AllOn bool `json:"all_on,omitempty"`
    28  	AnyOn bool `json:"any_on,omitempty"`
    29  }
    30  
    31  // Stream define the stream status of a group
    32  type Stream struct {
    33  	ProxyMode string  `json:"proxymode,omitempty"`
    34  	ProxyNode string  `json:"proxynode,omitempty"`
    35  	ActiveRaw *bool   `json:"active,omitempty"`
    36  	OwnerRaw  *string `json:"owner,omitempty"`
    37  }
    38  
    39  // Active returns the stream active state, and will return false if ActiveRaw is nil
    40  func (s *Stream) Active() bool {
    41  	if s.ActiveRaw == nil {
    42  		return false
    43  	}
    44  
    45  	return *s.ActiveRaw
    46  }
    47  
    48  // Owner returns the stream Owner, and will return an empty string if OwnerRaw is nil
    49  func (s *Stream) Owner() string {
    50  	if s.OwnerRaw == nil {
    51  		return ""
    52  	}
    53  
    54  	return *s.OwnerRaw
    55  }
    56  
    57  // SetState sets the state of the group to s.
    58  func (g *Group) SetState(s State) error {
    59  	return g.SetStateContext(context.Background(), s)
    60  }
    61  
    62  // SetStateContext sets the state of the group to s.
    63  func (g *Group) SetStateContext(ctx context.Context, s State) error {
    64  	_, err := g.bridge.SetGroupStateContext(ctx, g.ID, s)
    65  	if err != nil {
    66  		return err
    67  	}
    68  	g.State = &s
    69  	return nil
    70  }
    71  
    72  // Rename sets the name property of the group
    73  func (g *Group) Rename(new string) error {
    74  	return g.RenameContext(context.Background(), new)
    75  }
    76  
    77  // RenameContext sets the name property of the group
    78  func (g *Group) RenameContext(ctx context.Context, new string) error {
    79  	update := Group{Name: new}
    80  	_, err := g.bridge.UpdateGroupContext(ctx, g.ID, update)
    81  	if err != nil {
    82  		return err
    83  	}
    84  	g.Name = new
    85  	return nil
    86  }
    87  
    88  // Off sets the On state of one group to false, turning all lights in the group off
    89  func (g *Group) Off() error {
    90  	return g.OffContext(context.Background())
    91  }
    92  
    93  // OffContext sets the On state of one group to false, turning all lights in the group off
    94  func (g *Group) OffContext(ctx context.Context) error {
    95  	state := State{On: false}
    96  	_, err := g.bridge.SetGroupStateContext(ctx, g.ID, state)
    97  	if err != nil {
    98  		return err
    99  	}
   100  	g.State.On = false
   101  	return nil
   102  }
   103  
   104  // On sets the On state of one group to true, turning all lights in the group on
   105  func (g *Group) On() error {
   106  	return g.OnContext(context.Background())
   107  }
   108  
   109  // OnContext sets the On state of one group to true, turning all lights in the group on
   110  func (g *Group) OnContext(ctx context.Context) error {
   111  	state := State{On: true}
   112  	_, err := g.bridge.SetGroupStateContext(ctx, g.ID, state)
   113  	if err != nil {
   114  		return err
   115  	}
   116  	g.State.On = true
   117  	return nil
   118  }
   119  
   120  // IsOn returns true if light state On property is true
   121  func (g *Group) IsOn() bool {
   122  	return g.State.On
   123  }
   124  
   125  // Bri sets the light brightness state property
   126  func (g *Group) Bri(new uint8) error {
   127  	return g.BriContext(context.Background(), new)
   128  }
   129  
   130  // BriContext sets the light brightness state property
   131  func (g *Group) BriContext(ctx context.Context, new uint8) error {
   132  	update := State{On: true, Bri: new}
   133  	_, err := g.bridge.SetGroupStateContext(ctx, g.ID, update)
   134  	if err != nil {
   135  		return err
   136  	}
   137  	g.State.Bri = new
   138  	g.State.On = true
   139  	return nil
   140  }
   141  
   142  // Hue sets the light hue state property (0-65535)
   143  func (g *Group) Hue(new uint16) error {
   144  	return g.HueContext(context.Background(), new)
   145  }
   146  
   147  // HueContext sets the light hue state property (0-65535)
   148  func (g *Group) HueContext(ctx context.Context, new uint16) error {
   149  	update := State{On: true, Hue: new}
   150  	_, err := g.bridge.SetGroupStateContext(ctx, g.ID, update)
   151  	if err != nil {
   152  		return err
   153  	}
   154  	g.State.Hue = new
   155  	g.State.On = true
   156  	return nil
   157  }
   158  
   159  // Sat sets the light saturation state property (0-254)
   160  func (g *Group) Sat(new uint8) error {
   161  	return g.SatContext(context.Background(), new)
   162  }
   163  
   164  // SatContext sets the light saturation state property (0-254)
   165  func (g *Group) SatContext(ctx context.Context, new uint8) error {
   166  	update := State{On: true, Sat: new}
   167  	_, err := g.bridge.SetGroupStateContext(ctx, g.ID, update)
   168  	if err != nil {
   169  		return err
   170  	}
   171  	g.State.Sat = new
   172  	g.State.On = true
   173  	return nil
   174  }
   175  
   176  // Xy sets the x and y coordinates of a color in CIE color space. (0-1 per value)
   177  func (g *Group) Xy(new []float32) error {
   178  	return g.XyContext(context.Background(), new)
   179  }
   180  
   181  // XyContext sets the x and y coordinates of a color in CIE color space. (0-1 per value)
   182  func (g *Group) XyContext(ctx context.Context, new []float32) error {
   183  	update := State{On: true, Xy: new}
   184  	_, err := g.bridge.SetGroupStateContext(ctx, g.ID, update)
   185  	if err != nil {
   186  		return err
   187  	}
   188  	g.State.Xy = new
   189  	g.State.On = true
   190  	return nil
   191  }
   192  
   193  // Ct sets the light color temperature state property
   194  func (g *Group) Ct(new uint16) error {
   195  	return g.CtContext(context.Background(), new)
   196  }
   197  
   198  // CtContext sets the light color temperature state property
   199  func (g *Group) CtContext(ctx context.Context, new uint16) error {
   200  	update := State{On: true, Ct: new}
   201  	_, err := g.bridge.SetGroupStateContext(ctx, g.ID, update)
   202  	if err != nil {
   203  		return err
   204  	}
   205  	g.State.Ct = new
   206  	g.State.On = true
   207  	return nil
   208  }
   209  
   210  // Col sets the light color as RGB (will be converted to xy)
   211  func (g *Group) Col(new color.Color) error {
   212  	return g.ColContext(context.Background(), new)
   213  }
   214  
   215  // ColContext sets the light color as RGB (will be converted to xy)
   216  func (g *Group) ColContext(ctx context.Context, new color.Color) error {
   217  	xy, bri := ConvertRGBToXy(new)
   218  
   219  	update := State{On: true, Xy: xy, Bri: bri}
   220  	_, err := g.bridge.SetGroupStateContext(ctx, g.ID, update)
   221  	if err != nil {
   222  		return err
   223  	}
   224  	g.State.Xy = xy
   225  	g.State.Bri = bri
   226  	g.State.On = true
   227  	return nil
   228  }
   229  
   230  // Scene sets the scene by it's identifier of the scene you wish to recall
   231  func (g *Group) Scene(scene string) error {
   232  	return g.SceneContext(context.Background(), scene)
   233  }
   234  
   235  // SceneContext sets the scene by it's identifier of the scene you wish to recall
   236  func (g *Group) SceneContext(ctx context.Context, scene string) error {
   237  	update := State{On: true, Scene: scene}
   238  	_, err := g.bridge.SetGroupStateContext(ctx, g.ID, update)
   239  	if err != nil {
   240  		return err
   241  	}
   242  	g.State.Scene = scene
   243  	g.State.On = true
   244  	return nil
   245  }
   246  
   247  // TransitionTime sets the duration of the transition from the light’s current state to the new state
   248  func (g *Group) TransitionTime(new uint16) error {
   249  	return g.TransitionTimeContext(context.Background(), new)
   250  }
   251  
   252  // TransitionTimeContext sets the duration of the transition from the light’s current state to the new state
   253  func (g *Group) TransitionTimeContext(ctx context.Context, new uint16) error {
   254  	update := State{On: g.State.On, TransitionTime: new}
   255  	_, err := g.bridge.SetGroupStateContext(ctx, g.ID, update)
   256  	if err != nil {
   257  		return err
   258  	}
   259  	g.State.TransitionTime = new
   260  	return nil
   261  }
   262  
   263  // Effect the dynamic effect of the lights in the group, currently “none” and “colorloop” are supported
   264  func (g *Group) Effect(new string) error {
   265  	return g.EffectContext(context.Background(), new)
   266  }
   267  
   268  // EffectContext the dynamic effect of the lights in the group, currently “none” and “colorloop” are supported
   269  func (g *Group) EffectContext(ctx context.Context, new string) error {
   270  	update := State{On: true, Effect: new}
   271  	_, err := g.bridge.SetGroupStateContext(ctx, g.ID, update)
   272  	if err != nil {
   273  		return err
   274  	}
   275  	g.State.Effect = new
   276  	g.State.On = true
   277  	return nil
   278  }
   279  
   280  // Alert makes the lights in the group blink in its current color. Supported values are:
   281  // “none” – The light is not performing an alert effect.
   282  // “select” – The light is performing one breathe cycle.
   283  // “lselect” – The light is performing breathe cycles for 15 seconds or until alert is set to "none".
   284  func (g *Group) Alert(new string) error {
   285  	return g.AlertContext(context.Background(), new)
   286  }
   287  
   288  // AlertContext makes the lights in the group blink in its current color. Supported values are:
   289  // “none” – The light is not performing an alert effect.
   290  // “select” – The light is performing one breathe cycle.
   291  // “lselect” – The light is performing breathe cycles for 15 seconds or until alert is set to "none".
   292  func (g *Group) AlertContext(ctx context.Context, new string) error {
   293  	update := State{On: true, Alert: new}
   294  	_, err := g.bridge.SetGroupStateContext(ctx, g.ID, update)
   295  	if err != nil {
   296  		return err
   297  	}
   298  	g.State.Effect = new
   299  	g.State.On = true
   300  	return nil
   301  }
   302  
   303  // EnableStreaming enables streaming for the group by setting the Stream Active property to true
   304  func (g *Group) EnableStreaming() error {
   305  	return g.EnableStreamingContext(context.Background())
   306  }
   307  
   308  // EnableStreamingContext enables streaming for the group by setting the Stream Active property to true
   309  func (g *Group) EnableStreamingContext(ctx context.Context) error {
   310  	if g.Type != "Entertainment" {
   311  		return errors.New("must be an entertainment group to enable streaming")
   312  	}
   313  
   314  	active := true
   315  	update := Group{
   316  		Stream: &Stream{
   317  			ActiveRaw: &active,
   318  		},
   319  	}
   320  	_, err := g.bridge.UpdateGroupContext(ctx, g.ID, update)
   321  	if err != nil {
   322  		return err
   323  	}
   324  
   325  	g.Stream.ActiveRaw = &active
   326  	g.Stream.OwnerRaw = &g.bridge.User
   327  
   328  	return nil
   329  }
   330  
   331  // DisableStreaming disabled streaming for the group by setting the Stream Active property to false
   332  func (g *Group) DisableStreaming() error {
   333  	return g.DisableStreamingContext(context.Background())
   334  }
   335  
   336  // DisableStreamingContext disabled streaming for the group by setting the Stream Active property to false
   337  func (g *Group) DisableStreamingContext(ctx context.Context) error {
   338  	if g.Type != "Entertainment" {
   339  		return errors.New("must be an entertainment group to disable streaming")
   340  	}
   341  
   342  	active := false
   343  	update := Group{
   344  		Stream: &Stream{
   345  			ActiveRaw: &active,
   346  		},
   347  	}
   348  	_, err := g.bridge.UpdateGroupContext(ctx, g.ID, update)
   349  	if err != nil {
   350  		return err
   351  	}
   352  
   353  	g.Stream.ActiveRaw = &active
   354  	g.Stream.OwnerRaw = nil
   355  
   356  	return nil
   357  }