diff --git a/pkg/clients/denonavr/denonavrclient.go b/pkg/clients/denonavr/denonavrclient.go index c8cad4a..318c656 100644 --- a/pkg/clients/denonavr/denonavrclient.go +++ b/pkg/clients/denonavr/denonavrclient.go @@ -58,7 +58,7 @@ func NewDenonAVRClient(i *integration.Integration) *DenonAVRClient { } metadata := integration.DriverMetadata{ - DriverId: "denonavr-dev", + DriverId: "denonavr", Developer: integration.Developer{ Name: "Sebastian Plattner", }, diff --git a/pkg/denonavr/attributes.go b/pkg/denonavr/attributes.go index 212c03c..62b5a9e 100644 --- a/pkg/denonavr/attributes.go +++ b/pkg/denonavr/attributes.go @@ -1,10 +1,16 @@ package denonavr -import "reflect" +import ( + "fmt" + "reflect" +) // Set an attribute and call entity Change function if changed func (d *DenonAVR) SetAttribute(name string, value interface{}) { + d.attributeMutex.Lock() + defer d.attributeMutex.Unlock() + changed := d.attributes[name] == nil || !reflect.DeepEqual(d.attributes[name], value) d.attributes[name] = value @@ -14,3 +20,16 @@ func (d *DenonAVR) SetAttribute(name string, value interface{}) { } } + +func (d *DenonAVR) GetAttribute(name string) (interface{}, error) { + + d.attributeMutex.Lock() + defer d.attributeMutex.Unlock() + + if d.attributes[name] == nil { + return nil, fmt.Errorf("Attribute not Found") + } + + return d.attributes[name], nil + +} diff --git a/pkg/denonavr/commands.go b/pkg/denonavr/commands.go index 2354ed8..016668e 100644 --- a/pkg/denonavr/commands.go +++ b/pkg/denonavr/commands.go @@ -16,6 +16,8 @@ func (d *DenonAVR) sendCommandToDevice(cmd DenonCommand, payload string) (int, e if err != nil { return 404, err } + + return 200, nil } return d.sendHTTPCommand(cmd, payload) diff --git a/pkg/denonavr/denonavr.go b/pkg/denonavr/denonavr.go index 223e347..09a020b 100644 --- a/pkg/denonavr/denonavr.go +++ b/pkg/denonavr/denonavr.go @@ -88,7 +88,9 @@ type DenonAVR struct { zoneStatus map[DenonZone]DenonZoneStatus netAudioStatus DenonNetAudioStatus - attributes map[string]interface{} + // Attributes + attributes map[string]interface{} + attributeMutex sync.Mutex updateTrigger chan string @@ -157,8 +159,6 @@ func (d *DenonAVR) getMainZoneDataFromDevice() { func (d *DenonAVR) StartListenLoop() { log.Info("Start Denon Listen Loop") - //@TOOD: replace "example.net:5555" with address you want to connect to. - //telnet.DialToAndCall(d.Host+":23", d) updateInterval := 5 * time.Second ticker := time.NewTicker(updateInterval) @@ -169,7 +169,12 @@ func (d *DenonAVR) StartListenLoop() { // Start listening to telnet if d.telnetEnabled { - go d.listenTelnet() + go func() { + // just try to reconnect if connection lost + for { + d.listenTelnet() + } + }() } // do an intial update to make sure we have up to date values diff --git a/pkg/denonavr/power.go b/pkg/denonavr/power.go index ae3c7e8..d621b3f 100644 --- a/pkg/denonavr/power.go +++ b/pkg/denonavr/power.go @@ -1,5 +1,9 @@ package denonavr +import ( + log "github.com/sirupsen/logrus" +) + func (d *DenonAVR) TurnOn() error { if _, err := d.sendCommandToDevice(DenonCommandPower, "ON"); err != nil { return err @@ -30,7 +34,13 @@ func (d *DenonAVR) TogglePower() error { func (d *DenonAVR) IsOn() bool { - switch d.mainZoneData.ZonePower { + mainzonepower, err := d.GetAttribute("MainZonePower") + if err != nil { + log.WithError(err).Error("MainZonePower attribute not found") + return false + } + + switch mainzonepower.(string) { case "ON": return true default: diff --git a/pkg/denonavr/telnet.go b/pkg/denonavr/telnet.go index 36b3557..f72801c 100644 --- a/pkg/denonavr/telnet.go +++ b/pkg/denonavr/telnet.go @@ -20,54 +20,60 @@ type TelnetEvent struct { func (d *DenonAVR) handleTelnetEvents() { for { - select { - case event := <-d.telnetEvents: - log.WithFields(log.Fields{ - "cmd": event.Command, - "payload": event.Payload, - }).Debug("received telnet event") - - parsedCommand := strings.Split(event.Command, "") - command := parsedCommand[0] + parsedCommand[1] - param := strings.Join(parsedCommand[2:], "") - - log.WithFields(log.Fields{ - "command": DenonCommand(command), - "param": param, - }).Debug("parsed telnet event") - - switch DenonCommand(command) { - case DenonCommandMainZoneVolume: - if param != "MAX" { - log.Debug("Main Zone Volume from telnet") - volume, err := strconv.ParseFloat(param, 32) - log.WithField("volume", volume).Debug("Got volume") - if err != nil { - log.WithError(err).Error("failed to parse volume") - } - - if len(param) == 3 { - volume = volume / 10 - log.WithField("volume", volume).Debug("Got volume after conversion") - } - - log.WithField("volume", fmt.Sprintf("%0.1f", volume-80)).Debug("Got volume") - - d.SetAttribute("MainZoneVolume", fmt.Sprintf("%0.1f", volume-80)) + event := <-d.telnetEvents + parsedCommand := strings.Split(event.Command, "") + command := parsedCommand[0] + parsedCommand[1] + param := strings.Join(parsedCommand[2:], "") + + if event.Command == "OPSTS" { + // ignore this + continue + } + + log.WithFields(log.Fields{ + "cmd": event.Command, + "payload": event.Payload, + "command": DenonCommand(command), + "param": param, + }).Debug("Telnet Event received") + + switch DenonCommand(command) { + case DenonCommandPower: + d.SetAttribute("POWER", param) + case DennonCommandZoneMain: + d.SetAttribute("MainZonePower", param) + case DenonCommandMainZoneVolume: + if param != "MAX" { + + volume, err := strconv.ParseFloat(param, 32) + if err != nil { + log.WithError(err).Error("failed to parse volume") } - case DenonCommandMainZoneMute: - log.Debug("Main Zone Mute from telnet") - d.SetAttribute("MainZoneMute", strings.ToLower(param)) + // The Volume command need the following + // 10.5 -> MV105 + // 11 -> MV11 + if len(param) == 3 { + volume = volume / 10 + log.WithField("volume", volume).Debug("Got volume after conversion") + } + d.SetAttribute("MainZoneVolume", fmt.Sprintf("%0.1f", volume-80)) } + case DenonCommandMainZoneMute: + d.SetAttribute("MainZoneMute", strings.ToLower(param)) } } } func (d *DenonAVR) listenTelnet() { + defer func() { + log.Debug("Closing Telnet connection") + d.telnet.Close() + }() + go d.handleTelnetEvents() var err error @@ -87,7 +93,7 @@ func (d *DenonAVR) listenTelnet() { log.WithError(err).Error("failed to set tcp keep alive period") } - log.Debug("telnet connected") + log.WithField("host", d.Host+":23").Debug("Telnet connected") for { data, err := d.telnet.ReadString('\r') @@ -105,6 +111,7 @@ func (d *DenonAVR) listenTelnet() { event.Payload = parsedData[1] } + // Fire Event for handling d.telnetEvents <- &event } } @@ -113,13 +120,12 @@ func (d *DenonAVR) listenTelnet() { func (d *DenonAVR) sendTelnetCommand(cmd DenonCommand, payload string) error { d.telnetMutex.Lock() - defer d.telnetMutex.Unlock() log.WithFields(log.Fields{ "cmd": string(cmd), "payload": payload, - }).Debug("send telnet command") + }).Debug("Send Telnet command") _, err := d.telnet.Write([]byte(string(cmd) + payload + "\r")) diff --git a/pkg/denonavr/volume.go b/pkg/denonavr/volume.go index 0a12096..9f744ad 100644 --- a/pkg/denonavr/volume.go +++ b/pkg/denonavr/volume.go @@ -4,6 +4,8 @@ import ( "fmt" "math" "strings" + + log "github.com/sirupsen/logrus" ) func (d *DenonAVR) SetVolume(volume float64) error { @@ -48,7 +50,13 @@ func (d *DenonAVR) MainZoneMuteToggle() error { func (d *DenonAVR) MainZoneMuted() bool { - switch d.zoneStatus[MainZone].Mute { + mainZoneMute, err := d.GetAttribute("MainZoneMute") + if err != nil { + log.WithError(err).Debug("MainZoneMute attribute not found") + return false + } + + switch mainZoneMute.(string) { case "on": return true default: