Sonos - Play/Pause + feedback

Hi,

I’m trying to configure a KNX switch to control my Sonos.

This is my KNX item:

Switch KNX_GV_Keuken_Sonos_10_1_0								"Sonos Aan/Uit"							<soundvolume>			(gGV_Keuken, gSonos) 		{ knx="10/1/0" }

When this switch is “on”, Sonos should start playing. When the switch is “off”, Sonos should pause.

This is my Sonos item:

Player Sonos_GV_Keuken					"Radio keuken"						<soundvolume>		(gGV_Keuken, gSonos) 		{channel="sonos:PLAY5:RINCON_000E58834E6A01400:control"}

I have connected these items using the following rules:

rule "Play/Pause Sonos Keuken"

when
    Item KNX_GV_Keuken_Sonos_10_1_0 received update
then

    if (KNX_GV_Keuken_Sonos_10_1_0.state==ON) {
        sendCommand(Sonos_GV_Keuken, PLAY)
    } else {
        sendCommand(Sonos_GV_Keuken, PAUSE)
    }
end

This rule is working fine. Using my switch I can now play/pause my Sonos. However, it is only working fine when I would control my Sonos using only this switch (e.g. not via the Sonos app). When the KNX-switch is “off” and I start my Sonos using the Sonos-app, the KNX-switch remains off.

I would like to have a feedback from Sonos to update the switch-status.

I tried adding this rule:

rule "Play/Pause Sonos Keuken - reverse"

when
    Item Sonos_GV_Keuken received update
then

    if (Sonos_GV_Keuken.state==PLAY) {
        sendCommand(KNX_GV_Keuken_Sonos_10_1_0, ON)
    } else {
        sendCommand(KNX_GV_Keuken_Sonos_10_1_0, OFF)
    }
end

But together with the first rule, it creates obviously an infinite loop.

Does anyone have a better idea?

I think if you replace:
sendCommand
with:
sendUpdate
in your second rule, it would do just that: update the items status,but don’t trigger any command.

Is sendUpdate available? Didn’t try this…but I’m using this in my rule:

rule "Status Kitchen"
	when
    	Item Sonos_Kitchen_State changed
	then	
		if(Sonos_Kitchen_State.state == "PLAYING") {
			postUpdate(Sonos_Kitchen_Play, ON)
		} else {
			postUpdate(Sonos_Kitchen_Play, OFF)
		}				
	end

“Sonos_Kitchen_Play” would be your switch and to get the feedback I’m using this channel here:

Hi,

Thank you both for helping.

@Oli: If I use “sendUpdate” I see errors in my log (2017-04-01 11:13:44.864 [ERROR] [.script.engine.ScriptExecutionThread] - Rule ‘Play/Pause Sonos Keuken - reverse’: An error occured during the script execution: The name ‘sendUpdate(,)’ cannot be resolved to an item or type.)

Also “postupdate” is not an option. I really want the new value to be transmitted to the KNX bus, so I think I have to use the sendcommand. Otherwise nothing is send over the KNX binding. Correct?

I tried adding an additional check in my rule.
In fact, if both variables (KNX and Sonos) are having the same state (“ON”, “PLAYING”), nothing should happen. This could avoid the loop.

But since this is my first rule in OpenHAB, I don’t succeed in getting there. I’m not sure I’m doing this in an elegant way:

// Play or pause Sonos Keuken

rule "Play/Pause Sonos Keuken - part 1"

when   
    Item  KNX_GV_Keuken_Sonos_10_1_0 changed from OFF to ON
then
    if (Sonos_GV_Keuken_State.state != "PLAYING") {
        sendCommand(Sonos_GV_Keuken, PLAY)
    } else {
        /* Do Nothing */
    }
end

rule "Play/Pause Sonos Keuken - part 2"

when   
    Item  KNX_GV_Keuken_Sonos_10_1_0 changed from ON to OFF
then
    if (Sonos_GV_Keuken_State.state == "PLAYING") {
        sendCommand(Sonos_GV_Keuken, PAUSE)
    } else {
        /* Do Nothing */
    }
end

rule "Play/Pause Sonos Keuken - part 3"

when   
    Item  Sonos_GV_Keuken changed to PLAYING
then
    if (KNX_GV_Keuken_Sonos_10_1_0 == OFF) {
        sendCommand(KNX_GV_Keuken_Sonos_10_1_0, ON)
    } else {
        /* Do Nothing */
    }
end

rule "Play/Pause Sonos Keuken - part 4"

when   
    Item  Sonos_GV_Keuken changed to SOMETHINGELSETHANPLAYING (PAUSED_PLAYBACK / STOPPED / ...)
then
    if (KNX_GV_Keuken_Sonos_10_1_0 == ON) {
        sendCommand(KNX_GV_Keuken_Sonos_10_1_0, OFF)
    } else {
        /* Do Nothing */
    }
end

I just don’t know how to changed this line into something that acctually works:

    Item  Sonos_GV_Keuken changed to SOMETHINGELSETHANPLAYING (PAUSED_PLAYBACK / STOPPED / ...)

Is there a “not equal” statement that you can use in this when-statement? How? I couldn’t find anything.

Thanks!

Not that I’m aware of.You could do an or and include all you’re interested in:
Item Sonos_GV_Keuken changed to PAUSED or
Item Sonos_GV_Keuken changed to STOPPED or
Item Sonos_GV_Keuken changed to OFF or

Hi,
Thanks again Oli. I was hoping a “not” was available, because your approach assumes I know all states. I think they are limited to PLAYING, PAUSED_PLAYBACK and STOPPED.

Below my final rule. It is working well. I’m not sure it is the most elegant way to go. This is my first Openhab rule, so any suggestions to improve/optimize are welcome. :slight_smile:

// Play or pause Sonos Keuken

rule "Play/Pause Sonos Keuken - part 1"

when   
    Item  KNX_GV_Keuken_Sonos_10_1_0 changed from OFF to ON
then
    if (Sonos_GV_Keuken_State.state != "PLAYING") {
        sendCommand(Sonos_GV_Keuken, PLAY)
		logInfo("Debug","Sonos Debug1")
    } else {
	    /* Do Nothing */
		logInfo("Debug","Sonos Debug2")
    }
end

rule "Play/Pause Sonos Keuken - part 2"

when   
    Item  KNX_GV_Keuken_Sonos_10_1_0 changed from ON to OFF
then
    if (Sonos_GV_Keuken_State.state == "PLAYING") {
        sendCommand(Sonos_GV_Keuken, PAUSE)
		logInfo("Debug","Sonos Debug3")
    } else {
	    /* Do Nothing */
        logInfo("Debug","Sonos Debug4")
    }
end

rule "Play/Pause Sonos Keuken - part 3"

when
    Item  Sonos_GV_Keuken_State changed to PLAYING
then
    if (KNX_GV_Keuken_Sonos_10_1_0.state == OFF) {
        sendCommand(KNX_GV_Keuken_Sonos_10_1_0, ON)
		logInfo("Debug","Sonos Debug5")
    } else {
        /* Do Nothing */
		logInfo("Debug","Sonos Debug6")
    }
end

rule "Play/Pause Sonos Keuken - part 4"

when   
	Item Sonos_GV_Keuken_State changed to PAUSED_PLAYBACK or
	Item Sonos_GV_Keuken_State changed to STOPPED
then
    if (KNX_GV_Keuken_Sonos_10_1_0.state == ON) {
        sendCommand(KNX_GV_Keuken_Sonos_10_1_0, OFF)
		logInfo("Debug","Sonos Debug7")
    } else {
        /* Do Nothing */
		logInfo("Debug","Sonos Debug8")
    }
end

Elegance is overrated :wink: as long as it works.
But you could reduce that to just two rules. In your part 2 rules you basically do stuff you could put in the else-part of rules part 1:

rule "Play/Pause Sonos Keuken - part 1"

when   
    Item  KNX_GV_Keuken_Sonos_10_1_0 changed 
then
    if (Sonos_GV_Keuken_State.state != "PLAYING") {
        sendCommand(Sonos_GV_Keuken, PLAY)
		logInfo("Debug","Sonos Debug1")
    } else {
	    sendCommand(Sonos_GV_Keuken, PAUSE)
		logInfo("Debug","Sonos Debug3")
    }
end

rule "Play/Pause Sonos Keuken - part 3"

when
    Item  Sonos_GV_Keuken_State changed 
then
    //
    if (KNX_GV_Keuken_Sonos_10_1_0.state == OFF) {
        sendCommand(KNX_GV_Keuken_Sonos_10_1_0, ON)
		logInfo("Debug","Sonos Debug5")
    } else {
       sendCommand(KNX_GV_Keuken_Sonos_10_1_0, OFF)
		logInfo("Debug","Sonos Debug7")
    }
end

I think that will work the same. But make a backup of your current 4 rules just to be save :wink:

Hi Oli,

Thanks.
I’m afraid using this approach, I will create an infinite loop again.

The first rule says "When “KNX_GV_Keuken_Sonos_10_1_0” changes, change “Sonos_GV_Keuken_State”. The second rule says exactly the opposite. I’m afraid these rules will keep each other busy for quite a while.

But like you say, elegance is overrated. :wink: