Hi After a fun couple of days I thought I would share my Lua code for accessing Fronius Solar Inverters through the API and Tech Sterowniki (underfloor heating controllers. Both use request http command and return a json file which then can be queried and read the relevant values. I have included both API manuals as I have used only the data I need in the examples. Sonos - I converted the code from the other forum which used Wiser 2. First one below is for Fronius. Code: -- importing HTTP and json packages local http = require'ssl.https' local json = require('json') local ltn12 = require("ltn12") -- Create table, request json file and store (sink) local data = {} local r, c , h, s = http.request { url = 'http://<your local IP>/solar_api/v1/GetInverterRealtimeData.cgi?Scope=Device&DataCollection=CommonInverterData&DeviceId=1', method = 'GET', headers = { ["Content-Type"] = "application/json" }, sink = ltn12.sink.table(data) } --combine table and decode json data. local response = table.concat(data) local data2 = json.decode(response) --Select data totalenergy = data2.Body.Data.TOTAL_ENERGY.Value yearenergy = data2.Body.Data.YEAR_ENERGY.Value dayenergy = data2.Body.Data.DAY_ENERGY.Value --Write to user parameter SetUserParam(0, 20, totalenergy) SetUserParam(0, 21, yearenergy) SetUserParam(0, 22, dayenergy) The second is for Tech Sterowniki. This is done through quering the emodul.pl API interface. Please note obvious for secuity reasons <userID>, <module no> and <authorisation code> have been removed. These can be generated by using postman application and following the API guide attached... Code: -- importing HTTP and json packages local http = require'ssl.https' local json = require('json') local ltn12 = require("ltn12") -- Create table, request http, authorisation code in header and sink into table. local data = {} local r, c , h, s = http.request { url = 'https://emodul.eu/api/v1/users/<userID>/modules/<module no>', method = 'GET', headers = { ["Authorization"] = "Bearer <Authorisation code>", ["Content-Type"] = "application/json" }, sink = ltn12.sink.table(data) } --combine table and decode json data. local response = table.concat(data) local data3 = json.decode(response) --Transfer data to Cbus User parameter - Salon[1}, Kuchnia[2], Wiatrołap[3], Pokój Dół[4], Korytarz Dół[5], Toleta[6], Pomp. Gosp[7], Garaż[8] --Create decimal by divide by ten as number comes without it. salontemp = data3.zones.elements[1].zone.currentTemperature / 10 kuchniatemp = data3.zones.elements[2].zone.currentTemperature /10 wiatrolaptemp = data3.zones.elements[3].zone.currentTemperature /10 pokojdoltemp = data3.zones.elements[4].zone.currentTemperature /10 korytarztemp = data3.zones.elements[5].zone.currentTemperature /10 toletatemp = data3.zones.elements[6].zone.currentTemperature /10 pompgosptemp = data3.zones.elements[7].zone.currentTemperature /10 garaztemp = data3.zones.elements[8].zone.currentTemperature /10 --Transfer data to Cbus User parameter - Sypalnia[9], Łazienka Z&G[10], Pokój Gier[11], Spare[12], Korytarz Gora[13], Łazienka[14], Pokój Oskar[15], Pokój Daniel [16] sypalniatemp = data3.zones.elements[9].zone.currentTemperature /10 lazienkazgtemp = data3.zones.elements[10].zone.currentTemperature /10 pokojgiertemp = data3.zones.elements[11].zone.currentTemperature /10 --Sparetemp = data3.zones.elements[12].zone.currentTemperature /10 korytarzgoratemp = data3.zones.elements[13].zone.currentTemperature /10 lazienkatemp = data3.zones.elements[14].zone.currentTemperature /10 pokojoskartemp = data3.zones.elements[15].zone.currentTemperature /10 pokojdanieltemp = data3.zones.elements[16].zone.currentTemperature /10 -- send to userparameter SetUserParam(0, 4, salontemp) SetUserParam(0, 5, kuchniatemp) SetUserParam(0, 6, wiatrolaptemp) SetUserParam(0, 7, pokojdoltemp) SetUserParam(0, 8, korytarztemp) SetUserParam(0, 9, toletatemp) SetUserParam(0, 10, pompgosptemp) SetUserParam(0, 11, garaztemp) SetUserParam(0, 19, sypalniatemp) SetUserParam(0, 12, lazienkazgtemp) SetUserParam(0, 13, pokojgiertemp) SetUserParam(0, 14, Sparetemp) SetUserParam(0, 15, korytarzgoratemp) SetUserParam(0, 16, lazienkatemp) SetUserParam(0, 17, pokojoskartemp) SetUserParam(0, 18, pokojdanieltemp) An finally SONOS. Once again I used node js on windows setup and run the following code to give me the API. https://github.com/jishi/node-sonos-http-api Then on the SHAC side I have the following code examples. I use an EDLT to trigger the code. Play/Pause Code: playpause = event.getvalue() if (playpause == 255) then http = require'socket.http' body = http.request("http://<Windows PC IP>:5005/Bedroom/play") else http = require'socket.http' body = http.request("http://<Windows PC IP>:5005/Bedroom/pause") end -- Read state of amp, extract volume level, convert to number and send to cbus state http = require'socket.http' body = http.request("http://<Windows PC IP>:5005/Bedroom/state") volumestring = string.match(body,'volume":(%d+)') volumenumber = tonumber(volumestring) volumelevel = CBusPctToLevel(volumenumber) SetCBusLevel(0, 56, 134, volumelevel,0) Volume Control Code: --send volume level sendvolumenum = event.getvalue() sendvolumep = CBusLevelToPct(sendvolumenum) sendvolumestring = tostring(sendvolumep) http = require'socket.http' body = http.request("http://<Windows PC IP>:5005/Bedroom/volume/"..sendvolumestring) log(body) Start radio, update volume state and play if stopped. Code: --change to magic http = require'socket.http' body = http.request("http://<Windows PC IP>:5005/ Bedroom/Favourite/Magic") -- Read state of amp, extract volume elevel, convert to number and send to cbus state http = require'socket.http' body = http.request("http://<Windows PC IP>:5005/Bedroom/state") volumestring = string.match(body,'volume":(%d+)') volumenumber = tonumber(volumestring) volumelevel = CBusPctToLevel(volumenumber) SetCBusLevel(0, 56, 134, volumelevel,0) -- Read state of amp, extract play state and set to correct state playstate = string.match(body,'playbackState":"(%u%u%u%u%u%u%u)') if ('STOPPED' == playstate) then SetCBusState(0, 56, 133, false) elseif ('PLAYING' == playstate) then SetCBusState(0, 56, 133, true) end Hoping this will help someone. Happy Lua coding.
Updated my Sonos scipt to run as resident scipt which can extract with ease the status Json file which sonos requires and info can be sent to EDLT's Code: -- importing HTTP and json packages local http = require'ssl.https' local json = require('json') local ltn12 = require("ltn12") -- ************************************************************************** -- ************************KITCHEN SONOS DATA EXTRACT************************ -- ************************************************************************** -- Create table, request json file and store (sink) local data = {} local r, c , h, s = http.request { url = 'http://YOUR IP:5005/kitchen/state', method = 'GET', headers = { ["Content-Type"] = "application/json" }, sink = ltn12.sink.table(data) } --combine table and decode json data. local response = table.concat(data) local data2 = json.decode(response) --Select data kitchenvolume = data2.volume kitchenmute = data2.mute kitchenplayback = data2.playbackState kitchenartist = data2.currentTrack.artist kitchentitle = data2.currentTrack.title kitchentimelapse = data2.elapsedTimeFormatted --Send playing information (max 14 charactors on EDLT) if kitchenartist == nil or kitchenartist == "" then SetCBusUnicodeLabel(0, 56, 135, 'English', 'Variant1', "") else if kitchenartist ~= changeartist then kitchenartist2 = string.sub(kitchenartist, 1, 14) SetCBusUnicodeLabel(0, 56, 135, 'English', 'Variant1', kitchenartist2) changeartist = kitchenartist end end --Update volume on EDLT cbuskitchenlevel = GetCBusLevel(0, 56, 138) kitchenlevel = CBusPctToLevel(kitchenvolume) if kitchenlevel ~= cbuskitchenlevel then SetCBusLevel(0, 56, 138, kitchenlevel,0) end --Update play state group cbuskitchenplay = GetCBusLevel(0, 56, 137) if kitchenplayback == "PLAYING" and cbuskitchenplay == 0 then SetCBusLevel(0, 56, 137, 255, 0) elseif kitchenplayback == "STOPPED" and cbuskitchenplay == 255 then SetCBusLevel(0, 56, 137, 0, 0) elseif kitchenplayback == "PAUSED_PLAYBACK" and cbuskitchenplay == 255 then SetCBusLevel(0, 56, 137, 0, 0) end --Write to user parameter for SHAC SetUserParam(0, 63, kitchenartist) SetUserParam(0, 64, kitchentitle) SetUserParam(0, 65, kitchentimelapse)
For Sonos, Why do you not use the Multiroom Audio Application in place of Lighting, Then in eDLT you can use the Audio Functions for Volume and Commands, and if you have multiple Sonos Zones you can use the Zone Numbering in C-Bus to easily separate, You could make a very adaptable re-usable bit of code if you chose this path over Lighting Applications, Effectively just assigning each sonos unit to a MRA Zone
Colin Thanks for your input. Hadn't thought about that route. Wrote it off because it didn't give me all the functionality that I required through the eDLT. However after you comment and some time over Xmas to have a play came up with this solution: 1. Dynamic 1 shows song title and button allows pause/play 2. Dynamic 2 shows artist and button allows to skip to next track. 3. Volume acts as it states. 4. Source button allows to scroll through radio stations. ( 7 in total - 0-6 as field is limted to this) Additional Bass and Treble controls can be added to EDLT through the MRA zonecontrol but I don't show in screen shot however code is in the scripts for them. Objects were created in application 205: 205/0/0 - Volume 205/0/2 - Bass 205/0/3 - Treble 205/0/5 - Source number linked to radio station index in coding. Use this as retentative memory. 205/0/6 - Dynamic 1 - Artist 205/0/7 - Dynamic 2 - Title 205/0/8 - Source descrptor - Radio station desciption 205/0/10 - MRA Command - Use this to control the SONOS details below 205/0/1 - Balance - I did not use this because no functionality in eDLT and SONOS does not send this on the state request json. 205/0/4 - Mute - I did not use this as it is the same as pausing effectively. Pausing gives more functionality as it stops the song. So trying match systems up I used the following commands out of the MRA command list as these are the ones which can be sent from eDLT through application 205. The coding is still being tested and debugged at this stage. It is split into 2 scripts a 1. Resident for updates from the Sonos system to C-Bus 2. Event triggered for the button presses on the eDLT/ SHAC webpage. IP addresses have been deleted for obvious reasons 1. Resident code - I still had to use a group (retentative memory) for play/pause tthis allows SONOS and the MRA logic to sync. Code: -- ************************************************************************** -- ************************LOUNGE SONOS DATA EXTRACT************************ -- ************************************************************************** -- Create table, request json file and store (sink) local data5 = {} local r, c , h, s = http.request { url = 'http://<YOUR IP>:5005/Lounge/state', method = 'GET', headers = { ["Content-Type"] = "application/json" }, sink = ltn12.sink.table(data5) } --combine table and decode json data. local response3 = table.concat(data5) local data6 = json.decode(response3) --Select data from table JSON response. loungevolume = data6.volume loungebass = data6.equalizer.bass loungetreble = data6.equalizer.treble loungenmute = data6.mute loungeplayback = data6.playbackState loungeartist = data6.currentTrack.artist loungetitle = data6.currentTrack.title loungetimelapse = data6.elapsedTimeFormatted --Update play state group cbusloungeplay = GetCBusLevel(0, 56, 128) if loungeplayback == "PLAYING" and cbusloungeplay == 0 then SetCBusLevel(0, 56, 128, 255, 0) elseif loungeplayback == "STOPPED" and cbusloungeplay == 255 then SetCBusLevel(0, 56, 128, 0, 0) elseif loungeplayback == "PAUSED_PLAYBACK" and cbusloungeplay == 255 then SetCBusLevel(0, 56, 128, 0, 0) end -- Send to network loungevolume255 = CBusPctToLevel(loungevolume) CBusMRASetObjectValue(0, 0 , 0, loungevolume255) loungebass255 = CBusPctToLevel(loungebass) CBusMRASetObjectValue(0, 0 , 2, loungebass255) loungetreble255 = CBusPctToLevel(loungetreble) CBusMRASetObjectValue(0, 0 , 3, loungetreble255) CBusMRASetObjectValue(0, 0 , 6, loungeartist) CBusMRASetObjectValue(0, 0 , 7, loungetitle) 2. Event Trigger - looks at group 205/0/0/10 - MRA command and the change in text dictates the action. This is not as good as I hoped but it was working after my first testing. Will condense and improve in due course.Please note your radio stations need to stored in your favourites an dthe decription to match in order for it to work. Code: --Get MRA command MRAcommand = event.getvalue() log(MRAcommand) if MRAcommand == "Status Request" then -- do nothing handshake as command executed elseif MRAcommand == "Dynamic1" then playpause = GetCBusLevel(0, 56, 128) log(playpause) if (playpause == 0) then http = require'socket.http' body = http.request("http://<YOUR IP>:5005/lounge/play") CBusMRASetObjectValue(0, 0 , 10, {value='Status Request'}) else http = require'socket.http' body = http.request("http://<YOUR IP>:5005/lounge/pause") CBusMRASetObjectValue(0, 0 , 10, {value='Status Request'}) end elseif MRAcommand == "Dynamic2" then http = require'socket.http' body = http.request("http://<YOUR IP>:5005/Lounge/next") CBusMRASetObjectValue(0, 0 , 10, {value='Status Request'}) elseif MRAcommand == "Next Feed" then r = CBusMRAGetObjectValue(0, 0, 5) radiostation = r["value"] if radiostation == 6 then radiostation2 = 0 CBusMRASetObjectValue(0, 0 , 5, 0) else radiostation2 = radiostation + 1 end log(radiostation) if radiostation2 == 1 then http = require'socket.http' body = http.request("http://<YOUR IP>:5005/Lounge/Favourite/RMF MAXXX") CBusMRASetObjectValue(0, 0 , 8, {value='RMF MAXX'}) elseif radiostation2 == 2 then http = require'socket.http' body = http.request("http://<YOUR IP>:5005/Lounge/Favourite/Radio Zlote Przeboje") CBusMRASetObjectValue(0, 0 , 8, {value='Zlote Przeboje'}) elseif radiostation2 == 3 then http = require'socket.http' body = http.request("http://<YOUR IP>:5005/Lounge/Favourite/Capital London") CBusMRASetObjectValue(0, 0 , 8, {value='Capital London'}) elseif radiostation2 == 4 then http = require'socket.http' body = http.request("http://<YOUR IP>:5005/Lounge/Favourite/Heart UK") CBusMRASetObjectValue(0, 0 , 8, {value='Heart UK'}) elseif radiostation2 == 5 then http = require'socket.http' body = http.request("http://<YOUR IP>:5005/Lounge/Favourite/Radio Zet Kids") CBusMRASetObjectValue(0, 0 , 8, {value='Radio Zet Kids'}) elseif radiostation2 == 6 then http = require'socket.http' body = http.request("http://<YOUR IP>:5005/Lounge/Favourite/SuperNova") CBusMRASetObjectValue(0, 0 , 8, {value='SuperNova'}) end log (radiostation2) CBusMRASetObjectValue(0, 0 , 5, radiostation2) CBusMRASetObjectValue(0, 0 , 10, {value='Status Request'}) elseif MRAcommand == "Previous Feed" then r = CBusMRAGetObjectValue(0, 0, 5) radiostation = r["value"] if radiostation == 0 then radiostation2 = 6 else radiostation2 = radiostation - 1 end log (radiostation2) if radiostation2 == 1 then http = require'socket.http' body = http.request("http://10.0.0.13:5005/Lounge/Favourite/RMF MAXXX") CBusMRASetObjectValue(0, 0 , 8, {value='RMF MAXX'}) elseif radiostation2 == 2 then http = require'socket.http' body = http.request("http://10.0.0.13:5005/Lounge/Favourite/Radio Zlote Przeboje") CBusMRASetObjectValue(0, 0 , 8, {value='Zlote Przeboje'}) elseif radiostation2 == 3 then http = require'socket.http' body = http.request("http://10.0.0.13:5005/Lounge/Favourite/Capital London") CBusMRASetObjectValue(0, 0 , 8, {value='Capital London'}) elseif radiostation2 == 4 then http = require'socket.http' body = http.request("http://10.0.0.13:5005/Lounge/Favourite/Heart UK") CBusMRASetObjectValue(0, 0 , 8, {value='Heart UK'}) elseif radiostation2 == 5 then http = require'socket.http' body = http.request("http://10.0.0.13:5005/Lounge/Favourite/Radio Zet Kids") CBusMRASetObjectValue(0, 0 , 8, {value='Radio Zet Kids'}) elseif radiostation2 == 6 then http = require'socket.http' body = http.request("http://10.0.0.13:5005/Lounge/Favourite/SuperNova") CBusMRASetObjectValue(0, 0 , 8, {value='SuperNova'}) end log (radiostation2) CBusMRASetObjectValue(0, 0 , 5, radiostation2) CBusMRASetObjectValue(0, 0 , 10, {value='Status Request'}) end For me the advanatages of doing it this way were: 1. Reduced the amount of groups used in lighting. 2. Didn't have to right additional code to stop the resident code from flooding the network every 10 seconds. 3. Easier to set up on the eDLT. Select the zone number and away you go. 4. For radio selection I was using scene functionality to select the radio station on the eDLT. I can now use this for lighting control. 5. Utilise one line on eDLT to do two things - play/pause and show title. 6. Volume control - removes the on/off buttons on the shac http interface. "On" would put it up to 100%. Saying that some disdvantages were 1. Volume control - limited to increments of 7.8% on the volume control where as through the lighting application you can set your nudge value. 2. Shame the MTC objects (application 192) can't be selected on the eDLT as this would make the coding even easier. 3. Run out of commands on eDLT to use - example grouping zones, shuffle, time etc can not be included through this way. This would have to stay on lighting application. 4. Stuggling to find away of allowing the commands to work on the SHAC HTTP interface for the dynamic fields and slecting the radio station. Curently my buttons don't work on selection of the group. for next, play, pause and source select. Work in progress Hope this helps everyone. Regards Gareth
Sorted the last bit select MRA Command then select action in visualisation parameters. Will update code in week or so.
A week or so turned into a month after some testing by my kids and wife. Final code using MRA to control Sonos So the code sits in four scripts. 1 resident and 3 event based. 1. Sonos data Extract (Resident). 2. Volume control. 3. MRA Command. 4. Set radio from MRA source. (this has been split out to allow user to scroll through radio stations before being set - I have allowed 2 seconds which works for me). 1. Sonos data extract (duplicate for additional zones) Code: -- importing HTTP and json packages local http = require'ssl.https' local json = require('json') local ltn12 = require("ltn12") ip = "<your ip>" MRAzonekitchen = 1 -- ************************************************************************** -- ************************KITCHEN SONOS DATA EXTRACT MRA Zone 2 (1)********* -- ************************************************************************** -- Create table, request json file and store (sink) local data1 = {} local r, c , h, s = http.request { url = 'http://'..ip..':5005/kitchen/state', method = 'GET', headers = { ["Content-Type"] = "application/json" }, sink = ltn12.sink.table(data1) } --combine table and decode json data. local response1 = table.concat(data1) local data2 = json.decode(response1) --Select data kitchenvolume = data2.volume kitchenbass = data2.equalizer.bass kitchentreble = data2.equalizer.treble kitchenmute = data2.mute kitchenplayback = data2.playbackState kitchenartist = data2.currentTrack.artist kitchentitle = data2.currentTrack.title kitchentimelapse = data2.elapsedTimeFormatted --Update play state group cbuskitchenplay = GetCBusLevel(0, 56, 137) if kitchenplayback == "PLAYING" and cbuskitchenplay == 0 then SetCBusLevel(0, 56, 137, 255, 0) elseif kitchenplayback == "STOPPED" and cbuskitchenplay == 255 then SetCBusLevel(0, 56, 137, 0, 0) elseif kitchenplayback == "PAUSED_PLAYBACK" and cbuskitchenplay == 255 then SetCBusLevel(0, 56, 137, 0, 0) end -- Send to network if kitchenvolume ~= nil then kitchenvolume255 = CBusPctToLevel(kitchenvolume) CBusMRASetObjectValue(0, MRAzonekitchen, 0, kitchenvolume255) end if kitchenbass ~= nil then kitchenbass255 = CBusPctToLevel(kitchenbass) CBusMRASetObjectValue(0, MRAzonekitchen, 2, kitchenbass255) end if kitchentreble ~= nil then kitchentreble255 = CBusPctToLevel(kitchentreble) CBusMRASetObjectValue(0, MRAzonekitchen, 3, kitchentreble255) end if kitchentitle ~= nil then CBusMRASetObjectValue(0, MRAzonekitchen, 7, kitchentitle) end if kitchenartist ~= nil then CBusMRASetObjectValue(0, MRAzonekitchen, 6, kitchenartist) end 2. Volume Control (sets the volume on button press) triggered from group HOME/MRA/Zone 1/Volume (0/205/1/0) Code: --send volume level ipaddress = "<your IP>" sendvolumenum = event.getvalue() sendvolumep = CBusLevelToPct(sendvolumenum) sendvolumestring = tostring(sendvolumep) http = require'socket.http' body = http.request("http://"..ipaddress..":5005/Kitchen/volume/"..sendvolumestring) 3. MRA command triggered from HOME/MRA/Zone 1/MRA Command (0/205/1/10) Code: --Get MRA command MRAcommand = event.getvalue() -- Set server ip (PC/Rasberry pie running sonos api), zone and pause /play group (pp). -- Radio 1-7 - Set text for eDLT -- Zone must be the same spelling as in sonos app, -- All MRA groups need to be added in SHAC (application 205). -- Play/Pause group needs to be adding to lighting application and added below under pp. -- MRA zone is assigned to a Sonos zone - Don't forget Zone 1 eDLT is Zone 0 in SHAC, zone2 eDLT is Zone 1 SHAC and so on. ip ="<your ip>" zone = "Kitchen" MRAzone = 1 pp = 137 radio1 = "KISS" radio2 = "RMF MAXXX" radio3 = "Zlote Przeboje" radio4 = "Capital London" radio5 = "Heart" radio6 = "Zet Kids" radio7 = "SuperNova" if MRAcommand == "Status Request" then -- do nothing handshake as command executed -- Dynamic1 = Play/Pause Group 137 used to toggle. elseif MRAcommand == "Dynamic1" then playpause = GetCBusLevel(0, 56, pp) if (playpause == 0) then http = require'socket.http' body = http.request("http://"..ip..":5005/"..zone.."/play") SetCBusLevel(0, 56, pp, 255, 0) CBusMRASetObjectValue(0, MRAzone , 10, {value='Status Request'}) else http = require'socket.http' body = http.request("http://"..ip..":5005/"..zone.."/pause") SetCBusLevel(0, 56, pp, 0, 0) CBusMRASetObjectValue(0, MRAzone , 10, {value='Status Request'}) end -- Dynamic 2 = Next Track elseif MRAcommand == "Dynamic2" then http = require'socket.http' body = http.request("http://"..ip..":5005/"..zone.."/next") CBusMRASetObjectValue(0, MRAzone , 10, {value='Status Request'}) -- Next feed = Next/Previous radio station else if MRAcommand == "Next Feed" then r = CBusMRAGetObjectValue(0, MRAzone , 5) radiostation = r["value"] if radiostation == 6 then radiostation2 = 0 CBusMRASetObjectValue(0, MRAzone , 5, 0) else radiostation2 = radiostation + 1 end elseif MRAcommand == "Previous Feed" then r = CBusMRAGetObjectValue(0, MRAzone, 5) radiostation = r["value"] if radiostation == 0 then radiostation2 = 6 else radiostation2 = radiostation - 1 end end CBusMRASetObjectValue(0, MRAzone , 5, radiostation2) -- Triigers radio station HTTP request CBusMRASetObjectValue(0, MRAzone , 10, {value='Status Request'}) -- Set display to show radio station slection. Set here for quick update to screen if radiostation2 == 0 then CBusMRASetObjectValue(0, MRAzone , 8, {value=radio1}) elseif radiostation2 == 1 then CBusMRASetObjectValue(0, MRAzone , 8, {value=radio2}) elseif radiostation2 == 2 then CBusMRASetObjectValue(0, MRAzone , 8, {value=radio3}) elseif radiostation2 == 3 then CBusMRASetObjectValue(0, MRAzone , 8, {value=radio4}) elseif radiostation2 == 4 then CBusMRASetObjectValue(0, MRAzone , 8, {value=radio5}) elseif radiostation2 == 5 then CBusMRASetObjectValue(0, MRAzone , 8, {value=radio6}) elseif radiostation2 == 6 then CBusMRASetObjectValue(0, MRAzone , 8, {value=radio7}) end end 4. Set Radio from MRA source Code: -- set radio station based on MRA Source number value -- radio must be in favourites and spelling must be exact on this script -- change "Favourite" to "Playlist" and you can add a playlist ip ="<your ip>" zone = "Kitchen" MRAzone = 1 radio1 = "KISS" radio2 = "RMF MAXXX" radio3 = "Radio Zlote Przeboje" radio4 = "Capital London" radio5 = "Heart UK" radio6 = "Radio Zet Kids" radio7 = "SuperNova" -- allows time for user to skip to the righ radio station sleep(2) r = CBusMRAGetObjectValue(0, MRAzone, 5) MRAsource = r["value"] if MRAsource == 0 then http = require'socket.http' body = http.request("http://"..ip..":5005/"..zone.."/Favourite/"..radio1) elseif MRAsource == 1 then http = require'socket.http' body = http.request("http://"..ip..":5005/"..zone.."/Favourite/"..radio2) elseif MRAsource == 2 then http = require'socket.http' body = http.request("http://"..ip..":5005/"..zone.."/Favourite/"..radio3) elseif MRAsource == 3 then http = require'socket.http' body = http.request("http://"..ip..":5005/"..zone.."/Favourite/"..radio4) elseif MRAsource == 4 then http = require'socket.http' body = http.request("http://"..ip..":5005/"..zone.."/Favourite/"..radio5) elseif MRAsource == 5 then http = require'socket.http' body = http.request("http://"..ip..":5005/"..zone.."/Favourite/"..radio6) elseif MRAsource == 6 then http = require'socket.http' body = http.request("http://"..ip..":5005/"..zone.."/Favourite/"..radio7) end I have additional lighting groups to group Sonos speakers etc. eDLT has no changes to it from original setup at the top of this thread and same for SHAC page. Good luck everyone. If you find this useful then please like my posts to gain how many users use the code and any issue you may have. Thanks. Gareth
Hi Gareth, How about this for an improvement on your Data Extract routine .. allows you to have just one scheduled event that is configured to get all the updates ... Should be reasonably obvious, add a new ZoneX variable for each zone with name, MRA Zone # and GA. Then ensure the Zones variable has all the ZoneX variables. Code: -- importing HTTP and json packages local http = require'ssl.https' local json = require('json') local ltn12 = require("ltn12") -- IP Address of SONOS API Server ip = "192.168.0.136" local Zone1 = {Name = "Study", MRAZone = 11, GA = 201} local Zone2 = {Name = "White Dining", MRAZone = 12, GA = 202} local Zone3 = {Name = "Master Bedroom", MRAZone = 13, GA = 203} local Zone4 = {Name = "Games Room", MRAZone = 14, GA = 204} local Zones = { Zone1, Zone2, Zone3, Zone4 } for _, Zone in ipairs(Zones) do -- Create table, request json file and store (sink) local data1 = {} local r, c , h, s = http.request { url = 'http://'..ip..':5005/'..Zone.Name..'/state', method = 'GET', headers = { ["Content-Type"] = "application/json" }, sink = ltn12.sink.table(data1) } --combine table and decode json data. local response1 = table.concat(data1) local data2 = json.decode(response1) --Select data zone_volume = data2.volume zone_bass = data2.equalizer.bass zone_treble = data2.equalizer.treble zone_mute = data2.mute zone_playback = data2.playbackState zone_artist = data2.currentTrack.artist zone_title = data2.currentTrack.title zone_timelapse = data2.elapsedTimeFormatted --Update play state group cbuszone_play = FIT_GetCBUSDefZero(0, 56, Zone.GA) if zone_playback == "PLAYING" and cbuszone_play == 0 then SetCBusLevel(0, 56, Zone.GA, 255, 0) elseif zone_playback == "STOPPED" and cbuszone_play == 255 then SetCBusLevel(0, 56, Zone.GA, 0, 0) elseif zone_playback == "PAUSED_PLAYBACK" and cbuszone_play == 255 then SetCBusLevel(0, 56, Zone.GA, 0, 0) end -- Send to network if zone_volume ~= nil then zone_volume255 = CBusPctToLevel(zone_volume) CBusMRASetObjectValue(0, Zone.MRAZone, 0, zone_volume255) end if zone_bass ~= nil then zone_bass255 = CBusPctToLevel(zone_bass) CBusMRASetObjectValue(0, Zone.MRAZone, 2, zone_bass255) end if zone_treble ~= nil then zone_treble255 = CBusPctToLevel(zone_treble) CBusMRASetObjectValue(0, Zone.MRAZone, 3, zone_treble255) end if zone_title ~= nil then CBusMRASetObjectValue(0, Zone.MRAZone, 7, zone_title) end if zone_artist ~= nil then CBusMRASetObjectValue(0, Zone.MRAZone, 6, zone_artist) end end Cheers, Mal.