plugin.Name = "AnthemController"; plugin.OnChangeRequest = onChangeRequest; plugin.OnConnect = onConnect; plugin.OnDisconnect = onDisconnect; plugin.OnPoll = onPoll; plugin.OnSynchronizeDevices = onSynchronizeDevices; plugin.PollingInterval = 0; plugin.DefaultSettings = { "Host": "192.168.20.112", "Port": "14999" }; var socket = new TCPClient(); var zoneCount = 1; //set to two if you're using both zones; setting to 1 reduces the amount of polling required var unprocessedData = ""; var rawVolume; var data = null; var options = { timeout: 2000 }; var _readBuffer = ""; var _eol = ";"; var AIN= ""; var AIR = ""; var VIR = ""; var AIC = ""; function readMessage() { while (true) { var eolIndex = _readBuffer.indexOf(_eol); if (eolIndex != -1) { var message = _readBuffer.substring(0, eolIndex + 1); _readBuffer = _readBuffer.substring(eolIndex + 1); return message; } else { var data = socket.receive(); if (!data) { throw "End of the stream"; } _readBuffer = _readBuffer + data; } } } function onChangeRequest(device, attribute, value) { console.log("AVM onChangeRequest-" + attribute + ":" + value); var cmd = null; switch (attribute) { case "SeatingPosition": if (value == "Front") { cmd = "IS6SP0;IS7SP0"; break; } else if (value == "Back") { cmd = "IS6SP1;IS7SP1"; break; } case "MediaCommand": if (value == "VolumeUp") { cmd = "Z" + device.Id + "VUP01" } else if (value == "VolumeDown") { cmd = "Z" + device.Id + "VDN01" } else if (value == "MuteToggle") { cmd = "Z" + device.Id + "SIM0027" } else if (value == "Setup") { cmd = "Z" + device.Id + "SIM0012" } else if (value == "Info") { cmd = "Z" + device.Id + "SIM0017" } else if (value == "DirectionUp") { cmd = "Z" + device.Id + "SIM0018" } else if (value == "DirectionDown") { cmd = "Z" + device.Id + "SIM0019" } else if (value == "DirectionLeft") { cmd = "Z" + device.Id + "SIM0020" } else if (value == "DirectionRight") { cmd = "Z" + device.Id + "SIM0021" } else if (value == "Select") { cmd = "Z" + device.Id + "SIM0022" } else { throw "not implemented"; } break; case "InputSource": cmd = "Z" + device.Id + "INP" + parseInt(value).toString().padStart(2, '0'); break; case "Mute": cmd = "Z" + device.Id + "MUT" + ((value == "Muted") ? "1" : "0"); break; case "Switch": cmd = "Z" + device.Id + "POW" + ((value == "On") ? "1" : "0"); break; case "VolumeDecibel": cmd = "Z" + device.Id + "VOL" + value.toString(); break; default: throw "Not implemented!"; } console.log("command: " + cmd); cmd = cmd + ";"; socket.send(cmd); } function onConnect() { console.log("Anthem onConnect"); socket.connect(plugin.Settings["Host"], parseInt(plugin.Settings["Port"])); for (var i = 1; i <= zoneCount; i++) { var id = i.toString(); socket.send("Z" + id + "POW?;"); socket.send("Z" + id + "MUT?;"); socket.send("Z" + id + "VOL?;"); socket.send("Z" + id + "AIR?;"); socket.send("Z" + id + "AIN?;"); socket.send("Z" + id + "AIC?;"); socket.send("Z" + id + "VIR?;"); socket.send("Z" + id + "INP?;"); socket.send("IS6SP?;"); } } function onDisconnect() { console.log("Anthem onDisconnect"); socket.close(); } function onPoll() { var dirtystatus = 0; var message = readMessage(); console.log("Msg: " + message); if (message.substring(3,6) == 'SP0' ) { var deviceId = 1; var device = plugin.Devices[deviceId]; console.log ("Front"); device.SeatingPosition = "Front"; } if (message.substring(3,6) == 'SP1' ) { var deviceId = 1; var device = plugin.Devices[deviceId]; console.log ("Back"); device.SeatingPosition = "Back"; } if (message.length > 5 && message.charAt(0) == 'Z' ) { var deviceId = message.substring(1,2).toString(); var messageId = message.substring(2, 5); var val1 = message.substring(5,6); var val2 = message.substring(5,7); var val3 = message.substring(5,8); var valfull = message.substring(5,message.length-1) var device = plugin.Devices[deviceId]; switch (messageId) { case "VOL": var vol = parseInt(val3); device.VolumeDecibel = vol; console.log("Volume: " + device.Volume); break; case "AIR": AIR = valfull; console.log ("AIR: " + AIR); dirtystatus=1; break; case "AIN": AIN = valfull; console.log ("AIN: " + AIN); dirtystatus=1; break; case "AIC": switch (val1) { case "1": AIC = "Other"; break; case "2": AIC = "1.0"; break; case "3": AIC = "2.0"; break; case "4": AIC = "5.1"; break; case "5": AIC = "6.1"; break; case "6": AIC = "7.1"; break; default: AIC=""; break } console.log ("AIC: " + AIC); dirtystatus=1; break; case "VIR": switch (val1) { case "2": VIR = "1080p60"; break; case "3": VIR = "1080p50"; break; case "4": VIR = "1080p24"; break; case "5": VIR = "1080i60"; break; case "6": VIR = "1080i50"; break; case "7": VIR = "720p60"; break; case "8": VIR = "720p50"; break; case "9": VIR = "576p50"; break; case "10": VIR = "576i50"; break; case "11": VIR = "480p60"; break; case "12": VIR = "480i60"; break; case "13": VIR = "3D"; break; case "14": VIR = "4K"; break; default: VIR="Unknown"; break } console.log ("VIR: " + VIR); dirtystatus=1; break; case "POW": device.Switch = (val1 == "1" ? "On" : "Off"); break; case "MUT": device.Mute = (val1 == "1" ? "Muted" : "Unmuted"); break; case "INP": device.InputSource = parseInt(val2); break; default: console.log("unknown data read: " + message); break; } } if (dirtystatus == 1) { if (VIR == "Unknown") { device.SoundMode = AIN + " " + AIR + " " + AIC + " (No Video)" } else { device.SoundMode = AIN + " " + AIR + " " + AIC + " (" + VIR + ")" } } } function onSynchronizeDevices() { console.log("Anthem onSynchronizeDevices"); //Generate zones 1 and 2 //First digit in Id is the zone number. for (var i = 1; i <= zoneCount; i++) { var device = new Device(); device.Id = i.toString(); device.DisplayName = "Anthem Zone " + i.toString(); device.Icon = "Receiver"; device.Capabilities = ["AudioMute", "AudioSoundMode", "AudioVolumeDecibel", "MediaControl", "MediaInputSource", "Switch"]; device.Attributes = ["SeatingPosition"]; device.DeviceType = "AudioZone"; device.TileTemplate = "AudioZoneTile_hw.xaml"; device.DetailsTemplate = "AudioZoneDetails_hw.xaml"; plugin.Devices[device.Id] = device; } }