func (d *Device) SetStateLabel(pkt *packet.Packet) error { l := stateLabel{} if err := pkt.DecodePayload(&l); err != nil { return err } common.Log.Debugf("Got label (%v): %+v\n", d.id, l.Label) newLabel := stripNull(string(l.Label[:])) if newLabel != d.label { d.label = newLabel if err := d.publish(common.EventUpdateLabel{Label: d.label}); err != nil { return err } } return nil }
func (d *Device) SetStateHostFirmware(pkt *packet.Packet) error { f := stateHostFirmware{} if err := pkt.DecodePayload(&f); err != nil { return err } common.Log.Debugf("Got firmware version (%d): %d", d.id, f.Version) d.RLock() version := d.firmwareVersion d.RUnlock() if f.Version != version { d.Lock() d.firmwareVersion = f.Version d.firmwareVersionString = f.String() d.Unlock() } return nil }
func (d *Device) SetStateLabel(pkt *packet.Packet) error { l := stateLabel{} if err := pkt.DecodePayload(&l); err != nil { return err } common.Log.Debugf("Got label (%d): %v", d.id, string(l.Label[:])) newLabel := stripNull(string(l.Label[:])) if newLabel != d.CachedLabel() { d.Lock() d.label = newLabel d.Unlock() if err := d.publish(common.EventUpdateLabel{Label: newLabel}); err != nil { return err } } return nil }
func New(addr *net.UDPAddr, requestSocket *net.UDPConn, timeout *time.Duration, retryInterval *time.Duration, reliable bool, pkt *packet.Packet) (*Device, error) { d := new(Device) d.init(addr, requestSocket, timeout, retryInterval, reliable) if pkt != nil { d.id = pkt.Target service := new(stateService) if err := pkt.DecodePayload(service); err != nil { return nil, err } d.address.Port = int(service.Port) } go d.handler() return d, nil }
func (d *Device) SetStatePower(pkt *packet.Packet) error { p := statePower{} if err := pkt.DecodePayload(&p); err != nil { return err } common.Log.Debugf("Got power (%v): %+v\n", d.id, d.power) if d.power != p.Level { d.Lock() d.power = p.Level d.Unlock() if err := d.publish(common.EventUpdatePower{Power: d.power > 0}); err != nil { return err } } return nil }
func (d *Device) SetStatePower(pkt *packet.Packet) error { p := statePower{} if err := pkt.DecodePayload(&p); err != nil { return err } common.Log.Debugf("Got power (%d): %d", d.id, d.power) state := p.Level > 0 if d.CachedPower() != state { d.Lock() d.power = p.Level d.Unlock() if err := d.publish(common.EventUpdatePower{Power: state}); err != nil { return err } } return nil }
func (g *Group) Parse(pkt *packet.Packet) error { var shouldUpdate, labelUpdate bool s := stateGroup{} if err := pkt.DecodePayload(&s); err != nil { return err } g.RLock() if s.UpdatedAt > g.updatedAt { shouldUpdate = true } g.RUnlock() if shouldUpdate { g.Lock() g.id = s.ID g.idEncoded = strings.Replace( base64.URLEncoding.EncodeToString(s.ID[:]), `=`, ``, -1, ) g.updatedAt = s.UpdatedAt if g.label != s.Label { g.label = s.Label labelUpdate = true } g.Unlock() if labelUpdate { if err := g.publish(common.EventUpdateLabel{Label: g.GetLabel()}); err != nil { return err } } } return nil }
func (l *Light) SetState(pkt *packet.Packet) error { s := &state{} if err := pkt.DecodePayload(s); err != nil { return err } common.Log.Debugf("Got light state (%v): %+v\n", l.id, s) if l.color != s.Color { l.Lock() l.color = s.Color l.Unlock() if err := l.publish(common.EventUpdateColor{Color: l.color}); err != nil { return err } } if l.power != s.Power { l.Lock() l.power = s.Power l.Unlock() if err := l.publish(common.EventUpdatePower{Power: l.power > 0}); err != nil { return err } } newLabel := stripNull(string(s.Label[:])) if newLabel != l.label { l.Lock() l.label = newLabel l.Unlock() if err := l.publish(common.EventUpdateLabel{Label: l.label}); err != nil { return err } } return nil }
func (p *V2) process(pkt *packet.Packet, addr *net.UDPAddr) { common.Log.Debugf("Processing packet from %v: source %v, type %v, sequence %v, target %v, tagged %v, resRequired %v, ackRequired %v: %+v\n", addr.IP, pkt.GetSource(), pkt.GetType(), pkt.GetSequence(), pkt.GetTarget(), pkt.GetTagged(), pkt.GetResRequired(), pkt.GetAckRequired(), *pkt) // Update device seen time for any targeted packets if pkt.Target != 0 { dev, err := p.getDevice(pkt.Target) if err == nil { dev.SetSeen(time.Now()) } } // Broadcast packets, or packets generated by other clients if pkt.GetSource() != packet.ClientID { switch pkt.GetType() { case device.StatePower: dev, err := p.getDevice(pkt.GetTarget()) if err != nil { common.Log.Debugf("Skipping StatePower packet for unknown device: source %v, type %v, sequence %v, target %v, tagged %v, resRequired %v, ackRequired %v: %+v\n", pkt.GetSource(), pkt.GetType(), pkt.GetSequence(), pkt.GetTarget(), pkt.GetTagged(), pkt.GetResRequired(), pkt.GetAckRequired(), *pkt) return } err = dev.SetStatePower(pkt) if err != nil { common.Log.Debugf("Failed setting StatePower on device: source %v, type %v, sequence %v, target %v, tagged %v, resRequired %v, ackRequired %v: %+v\n", pkt.GetSource(), pkt.GetType(), pkt.GetSequence(), pkt.GetTarget(), pkt.GetTagged(), pkt.GetResRequired(), pkt.GetAckRequired(), *pkt) return } case device.StateLabel: dev, err := p.getDevice(pkt.GetTarget()) if err != nil { common.Log.Debugf("Skipping StateLabel packet for unknown device: source %v, type %v, sequence %v, target %v, tagged %v, resRequired %v, ackRequired %v: %+v\n", pkt.GetSource(), pkt.GetType(), pkt.GetSequence(), pkt.GetTarget(), pkt.GetTagged(), pkt.GetResRequired(), pkt.GetAckRequired(), *pkt) return } err = dev.SetStateLabel(pkt) if err != nil { common.Log.Debugf("Failed setting StatePower on device: source %v, type %v, sequence %v, target %v, tagged %v, resRequired %v, ackRequired %v: %+v\n", pkt.GetSource(), pkt.GetType(), pkt.GetSequence(), pkt.GetTarget(), pkt.GetTagged(), pkt.GetResRequired(), pkt.GetAckRequired(), *pkt) return } case device.State: dev, err := p.getDevice(pkt.GetTarget()) if err != nil { common.Log.Debugf("Skipping State packet for unknown device: source %v, type %v, sequence %v, target %v, tagged %v, resRequired %v, ackRequired %v: %+v\n", pkt.GetSource(), pkt.GetType(), pkt.GetSequence(), pkt.GetTarget(), pkt.GetTagged(), pkt.GetResRequired(), pkt.GetAckRequired(), *pkt) return } light, ok := dev.(*device.Light) if !ok { common.Log.Debugf("Skipping State packet for non-light device: source %v, type %v, sequence %v, target %v, tagged %v, resRequired %v, ackRequired %v: %+v\n", pkt.GetSource(), pkt.GetType(), pkt.GetSequence(), pkt.GetTarget(), pkt.GetTagged(), pkt.GetResRequired(), pkt.GetAckRequired(), *pkt) return } err = light.SetState(pkt) if err != nil { common.Log.Debugf("Error setting State on device: source %v, type %v, sequence %v, target %v, tagged %v, resRequired %v, ackRequired %v: %+v\n", pkt.GetSource(), pkt.GetType(), pkt.GetSequence(), pkt.GetTarget(), pkt.GetTagged(), pkt.GetResRequired(), pkt.GetAckRequired(), *pkt) return } default: common.Log.Debugf("Skipping packet with non-local source: source %v, type %v, sequence %v, target %v, tagged %v, resRequired %v, ackRequired %v: %+v\n", pkt.GetSource(), pkt.GetType(), pkt.GetSequence(), pkt.GetTarget(), pkt.GetTagged(), pkt.GetResRequired(), pkt.GetAckRequired(), *pkt) } return } // Packets processed at the protocol level regardless of target switch pkt.GetType() { case device.StateLocation: p.addLocation(pkt) case device.StateGroup: p.addGroup(pkt) } // Packets processed at the protocol level or returned to target switch pkt.GetType() { case device.StateService: dev, err := p.getDevice(pkt.Target) if err != nil { dev, err := device.New(addr, p.socket, p.timeout, p.retryInterval, p.Reliable, pkt) if err != nil { common.Log.Errorf("Failed creating device: %v\n", err) return } p.addDevice(dev) return } // Perform state discovery on lights if l, ok := dev.(*device.Light); ok { if err := l.Get(); err != nil { common.Log.Debugf("Failed getting light state: %v\n", err) } } default: if pkt.GetTarget() == 0 { common.Log.Debugf("Skipping packet without target: %+v\n", *pkt) return } dev, err := p.getDevice(pkt.GetTarget()) if err != nil { common.Log.Errorf("No known device with ID %v\n", pkt.GetTarget()) return } common.Log.Debugf("Returning packet to device %v: %+v\n", dev.ID(), *pkt) dev.Handle(pkt) } }
func (d *Device) Send(pkt *packet.Packet, ackRequired, responseRequired bool) (packet.Chan, error) { proxyChan := make(packet.Chan) // Rate limiter <-d.limiter.C // Broadcast vs direct broadcast := d.id == 0 if broadcast { // Broadcast can't be reliable ackRequired = false pkt.SetTagged(true) } else { pkt.SetTarget(d.id) if ackRequired { pkt.SetAckRequired(true) } if responseRequired { pkt.SetResRequired(true) } if ackRequired || responseRequired { seq, res := d.addSeq() pkt.SetSequence(seq) go func() { defer func() { close(res.done) close(proxyChan) }() var ( timeout <-chan time.Time ticker = time.NewTicker(*d.retryInterval) ) if d.timeout == nil || *d.timeout == 0 { timeout = make(<-chan time.Time) } else { timeout = time.After(*d.timeout) } for { select { case pktResponse, ok := <-res.ch: if !ok { return } if pktResponse.Result.GetType() == Acknowledgement { common.Log.Debugf("Got ACK for seq %d on device %d, cancelling retries", seq, d.ID()) ticker.Stop() // Ack does not resolve outstanding request, // continue waiting for response if responseRequired { continue } } proxyChan <- pktResponse return case <-ticker.C: common.Log.Debugf("Retrying send for seq %d on device %d after %d milliseconds", seq, d.ID(), *d.retryInterval/time.Millisecond) if err := pkt.Write(); err != nil { proxyChan <- &packet.Response{ Error: err, } return } case <-timeout: proxyChan <- &packet.Response{ Error: common.ErrTimeout, } return } } }() } } err := pkt.Write() d.resetLimiter(broadcast) return proxyChan, err }
func (d *Device) Send(pkt *packet.Packet, ackRequired, responseRequired bool) (packet.Chan, error) { proxyChan := make(packet.Chan) // Rate limiter <-d.limiter.C // Broadcast vs direct broadcast := d.id == 0 if broadcast { // Broadcast can't be reliable ackRequired = false pkt.SetTagged(true) } else { pkt.SetTarget(d.id) if ackRequired { pkt.SetAckRequired(true) } if responseRequired { pkt.SetResRequired(true) } if ackRequired || responseRequired { inputChan := make(packet.Chan) doneChan := make(chan struct{}) d.Lock() d.sequence++ if d.sequence == 0 { d.sequence++ } seq := d.sequence d.responseMap[seq] = inputChan d.doneMap[seq] = doneChan pkt.SetSequence(seq) d.Unlock() go func() { defer func() { close(doneChan) }() var ( ok bool timeout <-chan time.Time pktResponse = packet.Response{} ticker = time.NewTicker(*d.retryInterval) ) if d.timeout == nil || *d.timeout == 0 { timeout = make(<-chan time.Time) } else { timeout = time.After(*d.timeout) } for { select { case pktResponse, ok = <-inputChan: if !ok { close(proxyChan) return } if pktResponse.Result.GetType() == Acknowledgement { common.Log.Debugf("Got ACK for seq %d on device %d, cancelling retries\n", seq, d.ID()) ticker.Stop() if responseRequired { continue } } proxyChan <- pktResponse return case <-ticker.C: common.Log.Debugf("Retrying send after %d milliseconds: %+v\n", *d.retryInterval/time.Millisecond, *pkt) if err := pkt.Write(); err != nil { pktResponse.Error = err proxyChan <- pktResponse return } case <-timeout: pktResponse.Error = common.ErrTimeout proxyChan <- pktResponse return } } }() } } err := pkt.Write() d.resetLimiter(broadcast) return proxyChan, err }