Updating an Item from a variable

Like most I have a number of Motion, Door & Window sensors. As I started out I created rules to cover each device or group of devices. Now that I’ve expanded my list of sensors around the house I’ve begun to work on improving my rules. The first of them is below.

Rather than creating loads of rules that are essentially the same I decided to standardise where I could. So all of my Item are now in the form of LOCATION _ PRODUCT TYPE _ FUNCTION. An example being: Landing_SP3102_Motion. The rule below works great and give me the results I was looking for. What I’d like to now add is a counter for each device, as per my commented lines in the rule below. What I need help with is how do I do this dynamically, similar to how I update the Last Activation item but in reverse?

Also I’d like to read your comments on where I could improve this rule or whether this is useful.

val String filename = "Sensors.rules"
var myTimer = null
val int vTimeout = 10

rule "Which Sensor?"
when
    Member of gSensors changed
then
val vLocation = triggeringItem.name.split("_").get(0)
val vDevice = triggeringItem.name.split("_").get(1)
val vType = triggeringItem.name.split("_").get(2)
val vStatus = triggeringItem.state
var vItem = vLocation + "_" + vDevice + "_v" + vType
var vActivation = vLocation + "_" + vType + "_Last_Activation"
var vDate = new DateTimeType
if(vStatus == OFF && vType == "Motion") {
    myTimer = createTimer(now.plusSeconds(vTimeout)) [|
        if(myTimer !== null) {
            if(vStatus == ON && vType == "Motion") return;
        }
        myTimer = null
    ]
}
sendCommand(vItem, vStatus.toString)
sendCommand(vActivation, vDate.toString)
logInfo(filename, "Sensor Status: {} {} Sensor has changed to {}",vLocation ,vType ,vStatus.toString)
//    val counter = (Cloakroom_Door_Counter.state as Number) + 1
//    Cloakroom_Door_Counter.sendCommand(counter)
end

Thanks,

Garry

Hi @Maximo,

I’m not the best at just looking at rules and figuring things out, but I believe…

  1. val counter = (Cloakroom_Door_Counter.state as Number) + 1 should be var counter, as values aren’t supposed to change, while variables can.

  2. Cloakroom_Door_Counter.sendCommand(counter) should look more like Cloakroom_Door_Counter.postUpdate(counter)

  3. Unless you are using persistence, your counters will only be good until the next reboot. You may want to look into persistence if this is a problem.

Regards,
Burzin

1 Like

Thanks for your reply @Burzin_Sumariwalla, I think you’ve misunderstood what I was asking. I’m looking to create Cloakroom_Door_Counter dynamically from the item that my rule is processing at the time.

You mean, access an Item when you have a string for it’s name?
postUpdate(string,string) Action will actually allow this

What I want to do in the opposite, I want to obtain the current state of an item but creating the item dynamically.

So if for example my rule above is triggered by the Kitchen motion sensor I then want to retrieve the counter status from the item Kitchen_Motion_Counter.

1 Like

Thanks @5iver this is what I was looking for.

1 Like

Just for completeness here’s my updated rule. Again, I’m happy for anyone to comment and advice on ways to improve this or an alternative approach.

import org.eclipse.smarthome.model.script.ScriptServiceUtil

val String filename = "Sensors.rules"
var myTimer = null
val int vTimeout = 10

rule "Which Sensor?"
when
    Member of gSensors changed
then
val vLocation = triggeringItem.name.split("_").get(0)
val vDevice = triggeringItem.name.split("_").get(1)
val vType = triggeringItem.name.split("_").get(2)
val vStatus = triggeringItem.state
var vItem = vLocation + "_" + vDevice + "_v" + vType
var vActivation = vLocation + "_" + vType + "_Last_Activation"
var vDate = new DateTimeType
if(vStatus == OFF && vType == "Motion") {
    myTimer = createTimer(now.plusSeconds(vTimeout)) [|
        if(myTimer !== null) {
            if(vStatus == ON && vType == "Motion") return;
        }
        myTimer = null
    ]
}
sendCommand(vItem, vStatus.toString)
sendCommand(vActivation, vDate.toString)
logInfo(filename, "Status Changed: {} {} Sensor has changed to {}",vLocation ,vType ,vStatus.toString)
if(vStatus == ON ) {
    var vCounterItem = vLocation + "_" + vType + "_Counter"
    val vCounter = ScriptServiceUtil.getItemRegistry.getItem(vCounterItem)
    val vCounterValue = (vCounter.state as Number) + 1
    sendCommand(vCounterItem, vCounterValue)
}
end

Why do you need a timer that doesn’t do anything?

This is much more straightforward using Jython and the helper libraries rather that the DSL. Here is an alternative…