Simple state rule for a simple man

I am having trouble working our how to detect and store state for a switch. Heres the scenario:

I have a rule that fires on XBMC player.state. I check this for play, pause or stop. If it’s play, I turn off light switch, if it pause or stop, I turn on light swith.

All works.

However if the switch is already off before the play state, I dont want it to come when it detect pause or stop, only if th light switch was already on.

I undertand I can check the state of the switch, but not sure when to do this as it cant be done on the change of player.state as this will always be off after the state of play.

It seems simple but I cant find any simple examples on how to do this most of the examples all seem a bit uber and way more than I need.

Define a variable at the top of your rules file to remember whether you switched the light off, e.g. var boolean lightWasOnWhenPlaybackStarted = false. Then, when stopping or pausing playback, switch on the light only if it was switched off when playback started.

Rather than using a separate variable as suggested above, you can use persistence extensions to check the state of the light. This assumes of course that you have persistence configured :smile:

The advantage of using persistence is that it will work even if you restart OH, or when the rules get reloaded, where a local variable in a rule won’t.

So, something like <item>.historicState(now) should give you the currently persisted state of an item, and you can use this to decide what to do in your rule.

Sorry, I still dont get it - when do I check the persistance as wont that be what it is at (now), so if it was told to turn off, it will be off, but also if it was off, it will be off?

I have persistance set up but nbot sure how to use it.

This is my script - any chance you could modify it into a working example?

ule “Lights off when Play Starts”

when

Item xbmc_state_1 changed

then

var String state = xbmc_state_1.state.toString()

if (state.lowerCase == "play") {
sendCommand(Lounge_Dimmer, OFF)
}	
if (state.lowerCase == "pause") {
sendCommand(Lounge_Dimmer,ON)
}
if (state.lowerCase == "stop") {
sendCommand(Lounge_Dimmer,ON)
}

end

To be honest, I’ve not checked the order of when things get called (ie if the persistence is updated before or after calling the rule). You might be right, but in this case, can’t you just use

<item>.previousState(AbstractInstant) - Retrieves the previous state of the item.

to get the previous state?

I set to OFF at the start of the movie when state.lowerCase == “play”, then when checked after the movie finishes state.lowerCase == “stop”, wont the .previousState(AbstractInstant) be OFF? and always OFF even if it was ON before the movie started?

If you used a variable to store the state before movie starts, it would look something like this:


var String state_before_play = ""

rule "Lights off when Play Starts"
when
    Item xbmc_state_1 changed
then


    if (state.lowerCase == "play") {
        // store the state when play was pressed
        state_before_play = Lounge_Dimmer.state.toString()
        sendCommand(Lounge_Dimmer, OFF)
    }	
    // combining these states for simpler code
    if (state.lowerCase == "pause"
        || state.lowerCase == "stop") {

        // this if could be combined with the outer if. Keeping separate for clarity. 
        // If combined, it would be in the form: if(("pause" || "stop") && state_before_play)
        if(state_before_play == "ON") {
            sendCommand(Lounge_Dimmer,ON)
        }
    }
end

Alternatively, if you wanted to use historic state it would look similar with just a few tweaks


var AbstractInstant time_play_started

rule "Lights off when Play Starts"
when
    Item xbmc_state_1 changed
then


    if (state.lowerCase == "play") {
        // store the state when play was pressed
        time_play_started = now
        sendCommand(Lounge_Dimmer, OFF)
    }	
    // combining these states for simpler code
    if (state.lowerCase == "pause"
        || state.lowerCase == "stop") {

        // this if could be combined with the outer if. Keeping separate for clarity. 
        // If combined, it would be in the form: if(("pause" || "stop") && historic_state)
        if(Lounge_Dimmer.historic_state(time_play_started) == "ON") {
            sendCommand(Lounge_Dimmer,ON)
        }
    }
end

I don’t think either of these would survive an openHAB restart as the variable defined above the rule would be cleared.

To use the extensions as Chris was suggesting, you could use this extension:

.lastUpdate - Query for the last update timestamp of a given item.

So the embedded if in the pause/stop portion of the rule would look something like this:

        var play_time = xbmc_state_1.lastUpdate
        if(Lounge_Dimmer.historic_state(play_time) == "ON") {
            sendCommand(Lounge_Dimmer,ON)
        }

And if Lounge_Dimmer.historic_state(play_time) for some reason gives Lounge_Dimmer’s state AFTER the switch was changed and lights were turned off, you could get the state a second or two before. Something like this:

if(Lounge_Dimmer.historic_state(play_time.minusSeconds(1)) == “ON”) {

I haven’t tested any of the code in this post, but hopefully if anything it would just need syntax tweaks.

Hope this helps!

hi Jonnydev13 - this is brilliant - so clear - thankyou for showing me a full example using my code - that helped solidify my understanding so much!

I will put this in place. the only scenario I can think where I might need to tweak this is if there was ever a pause event, then a stop event, or if there was a stop event and then a play event, the light would stay off or on but I think I could do something like xbmc_state_1.historic_state(play_time) and check for play, pause or stop and condition it accordingly

Thanks so much!

Glad it’s helpful!

I think it would probably work as-is for the scenarios you talk about. The key things are that it will store the state only when you push play, so that wouldn’t get overwritten if you pause then stop. Basically for the stop command you would be setting it to the same value as you did for pause so you wouldn’t see a change. Similarly, for stop and play, it would be moved back to the state you wanted (which you stored during the play event) when you hit stop, and when you hit play it would store the current state again, essentially starting all over with a new stored state. You may find situations where this doesn’t work, but I think this simple rule covers most possibilites!

Hi simple man here again - I seem to get no output from play_time = xbmc_state_1.lastUpdate
does this mean I dont have persistance working?

OK I have finally sorted it out - here is the final script - it stores the time when the video is playing and then when the pause or stop state is triggered, it checks the persistance back when the video started and sets the dimmer to the same value.

import org.openhab.core.library.types.DecimalType
import org.openhab.core.library.types.*
import org.openhab.model.script.actions.*
import java.lang.Math
import org.joda.time.*
import org.openhab.core.persistence.*

var DateTime time_play_started 

//logInfo("FILE", "kodi " + Kodistate)

rule "Lights off when Play Starts"
when
Item xbmc_state_1 changed
then
var String Kodistate = xbmc_state_1.state.toString()
if (Kodistate == "Play") {
	// store the state when play was pressed
	time_play_started = now
	sendCommand(Lounge_Dimmer, OFF)
}

if (Kodistate == "Pause" || Kodistate == "Stop") {
   var Number Lounge_DimmerState = Lounge_Dimmer.historicState(time_play_started).state
if(Lounge_DimmerState > 0) {
sendCommand(Lounge_Dimmer,Lounge_DimmerState)
}
} end
1 Like

Great! Good job sticking with it and figuring out something that works!