[SOLVED] Making this rule generic

I can do that with TimeofDay, but what about armed? Because I have 8 proxies for the cameras, one for each camera. Im not sure how I’d check if the triggeringItem is also armed. Does that make sense?


/* Motion Sensor Item for Blue Iris Cameras */

Switch NorthWestDriveMotion                    "[MAP(motion.map):%s] North West Drive Camera" (gMotionSensors)
Switch PatioMotion                             "[MAP(motion.map):%s] Patio Camera"            (gMotionSensors)
Switch PatioBBQMotion                          "[MAP(motion.map):%s] Patio BBQ Camera"        (gMotionSensors)
Switch EntranceWestMotion                      "[MAP(motion.map):%s] Entrance West Camera"    (gMotionSensors)
Switch LibraryMotion                           "[MAP(motion.map):%s] Library Camera"          (gMotionSensors)
Switch Bedroom1Motion                          "[MAP(motion.map):%s] Bedroom 1 Camera"        (gMotionSensors)
Switch DrivewayNorthMotion                     "[MAP(motion.map):%s] Driveway North Camera"   (gMotionSensors)
Switch EastMotion                              "[MAP(motion.map):%s] East Camera"             (gMotionSensors)

/* Enables/Disables Cameras as Motion Sensors */

Switch NorthWestDriveMotion_Armed                   "[MAP(motion.map):%s] North West Drive Camera" (gMotionSensors)
Switch PatioMotion_Armed                            "[MAP(motion.map):%s] Patio Camera"            (gMotionSensors)
Switch PatioBBQMotion_Armed                         "[MAP(motion.map):%s] Patio BBQ Camera"        (gMotionSensors)
Switch EntranceWestMotion_Armed                     "[MAP(motion.map):%s] Entrance West Camera"    (gMotionSensors)
Switch LibraryMotion_Armed                          "[MAP(motion.map):%s] Library Camera"          (gMotionSensors)
Switch Bedroom1Motion_Armed                         "[MAP(motion.map):%s] Bedroom 1 Camera"        (gMotionSensors)
Switch DrivewayNorthMotion_Armed                    "[MAP(motion.map):%s] Driveway North Camera"   (gMotionSensors)
Switch EastMotion_Armed                             "[MAP(motion.map):%s] East Camera"             (gMotionSensors)



Group:Switch:OR(ON, OFF)    gMotionSensors            "All Motion Sensors"

/*Group Definitions for Lights*/
Group:Switch:SUM gAllLights          "All Lights"

/*ZWave Switch Node 2 Bedroom Lights*/
Switch BedRoom1_Sw1  "Bedroom West Exterior"                                      (gLights_Random,gAllLights,gInsideLights)          { channel="zwave:device:ce741a7c:node2:switch_binary1" }
Switch BedRoom1_Sw2  "Bedroom East Exterior"                                      (gLights_Random,gAllLights,gInsideLights)          { channel="zwave:device:ce741a7c:node2:switch_binary2" }

/*ZWave Switch Node 3 Laundry Lights*/
Switch Laundry_Sw1  "Laundry Entrance Exterior"                                   (gLights_Random,gAllLights,gInsideLights)          { channel="zwave:device:ce741a7c:node3:switch_binary1" }
Switch Laundry_Sw2  "Laundry Driveway Exterior"                                   (gLights_Random,gAllLights,gInsideLights)          { channel="zwave:device:ce741a7c:node3:switch_binary2" }

/*ZWave Switch Node 4 Hall Lights*/
Switch Hall_Sw1  "Front Door"                                                     (gLights_Random,gAllLights,gInsideLights)          { channel="zwave:device:ce741a7c:node4:switch_binary1" }
Switch Hall_Sw2  "West Garden"                                                    (gLights_Random,gAllLights,gInsideLights)          { channel="zwave:device:ce741a7c:node4:switch_binary2" }

/*ZWave Switch Node 5 Library West Lights*/
Switch Library_Sw1  "Library West Exit"                                           (gLights_Random,gAllLights,gInsideLights)          { channel="zwave:device:ce741a7c:node5:switch_binary" }

/*ZWave Switch Node 6 Wall Pendant Lights*/
Switch Kitchen_Sw1   "Wall Pendant"                                               (gLights_Random,gAllLights,gInsideLights)          { channel="zwave:device:ce741a7c:node6:switch_binary" }

/*ZWave Switch Node 8 Bird Lights*/
Switch Bird_Sw1  "Bird Light"                                                     (gLights_Random,gAllLights,gInsideLights)          { channel="zwave:device:ce741a7c:node8:switch_binary" }

/*ZWave Switch Node 10 Patio/Eastern Exterior Lights*/
Switch Patio_Sw1             "North Patio Lights"                                 (gLights_Random,gAllLights,gOutsideLights)         { channel="zwave:device:ce741a7c:node10:switch_binary1" }
Switch EasternExteriorSw2   "Eastern Exterior Light"                             (gLights_Random,gAllLights,gOutsideLights)         { channel="zwave:device:ce741a7c:node10:switch_binary2" }

/*ZWave Switch Node 14 Western Exterior Light*/
Switch Node14_Sw1   "West Exterior Light"                                         (gLights_Random,gAllLights,gOutsideLights)         { channel="zwave:device:ce741a7c:node14:switch_binary" }


rule "Motion activated Lights using CCTV Cameras"
when
	Member of gMotionSensors received command ON
then
	logInfo("Motion.rules", triggeringItem.name + " detected motion.")
     if (vTimeOfDay.state == "EVENING" || vTimeOfDay.state == "NIGHT") {
      val source = triggeringItem.name.split("_").get(0)
      val _Cam = gMotionSensors.members.findFirst[ cam | cam.name == source"_Cam" ]
      val _Light = gAllLights.members.findFirst[ light | light.name == source"_Sw" ]
	sendCommand(_Light,ON)
	createTimer(now.plusSeconds(60)) [ | {sendCommand(_Light,OFF)}]
     }
end


I don’t really understand. Getting name Patio_armed from name Patio is pretty straightforward and exampled in Paul’s rule. (Albeit it needs source + “_extra” syntax fixing)

Sure, but is it possible using an if statement to check if the triggeringItem (which was a Motion sensor) has its corrosponding ‘Armed’ item as ON?

Does that make sense?

If Camera tripped motion, and its corresponding Armed Sensor is ON, then turn on light Blah.

Yes of course. Have you tried? Maybe do it in steps, all the parts are already shown in this thread. Trigger a rule. Get the triggering Item name. Use that to build the armed item name. Use that to fetch the Item from a group. Now you can construct an if() evaluation of that Item’s state. Then you can turn the light on (or not).

I can’t try because I dont have access to the system as yet. OK, so I can construct the Armed item from the triggeringItem as the names are the same, the Armed just has _Armed prepended to the end.

rule "Motion activated Lights using CCTV Cameras"
when
	Member of gMotionSensors received command ON
then
	logInfo("Motion.rules", triggeringItem.name + " detected motion.")
     if (vTimeOfDay.state == "EVENING" || vTimeOfDay.state == "NIGHT") {
      val source = triggeringItem.name
      val armed = triggeringItem.name+"_Armed" as SwitchItem
      }
     if (armed.state == ON){

Does that look ok? I will need to change the Light names to match the triggeringItem to some degree I would guess. I don’t really understand the logic in Paul’s example with respect to:

 val _Cam = gMotionSensors.members.findFirst[ cam | cam.name == source"_Cam" ]
      val _Light = gAllLights.members.findFirst[ light | light.name == source"_Sw" ]

Nope. armed in your rule is just a string, the name of the Item you want. It doesn’t have a .state, it’s just a string not an Item.

There are at least two ways to get hold of the actual Item with that name (so that you can in turn get hold of its state),
You can select it from a group of which it is a member, as already shown in in this thread, or you can use a registry action.

Learning a language is incredibly difficult for someone without programming background so apologies for what may seem extremely trivial to you.

import org.eclipse.smarthome.model.script.ScriptServiceUtil
val _Armed = ScriptServiceUtil.getItemRegistry.getItem(triggeringItem.name+"_Armed") as SwitchItem

To end up with:

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

rule "Motion activated Lights using CCTV Cameras"
when
	Member of gMotionSensors received command ON
then
	logInfo("Motion.rules", triggeringItem.name + " detected motion.")
     if (vTimeOfDay.state == "EVENING" || vTimeOfDay.state == "NIGHT") {
      val source = triggeringItem.name
      val _Armed = ScriptServiceUtil.getItemRegistry.getItem(triggeringItem.name+"_Armed") as SwitchItem
      }
     if (_Armed.state == ON){

I can only speak from my own experience and I use the name to make things easy, have two lights one called _Sw1 and one called _Sw2 does not really help when trying to make things generic.

I am sure some genius around here can assist but its beyond my abilities, whereas the way I described is how I do all of my generic rules pretty much.

Take the easy way or continue down the harder road.

I am sorry I could not help

Thanks

Paul

1 Like

You’re helping Paul. Don’t be sorry. Yes I think I’ll have to rename my lights to match my motion sensors and camera names with underscores to allow the user of triggeritem.name

I’m trying to understand what your syntax means :slight_smile:

The general syntax I use is

  1. the delimiter is an underscore, this is useful and supper easy to locate when breaking the name into different parts inside rules.
  2. The first part is an abbreviation for the location, e.g LR - Livingrroom, BR1 equals Bedroom 1 and KT equals Kitchen.
  3. The second part equals the device type.
    4.The final part is the specific cahannel so if its simply the device on /off you could use ‘Switch’ or for such a default actual just omit it. I went with omitting it but if I started again I would give using ‘Switch’ a go. other obvious actions are Online, LastSeen and Brightness.

putting that all together ends with names like this

KT_PIR_Detect
so Kitchen PIR sensor Detect

Or BR1_Fan_Switch
Bedroom 1 fan switch
Hope the naming syntax makes sense.

now to grab a part of a triggering name item which is part of a group you simply do this

val location = triggeringItem.name.split("").get(0)
val device= triggeringItem.name.split("
").get(1)
val action= triggeringItem.name.split("_").get(3)

The three values now contain the individual parts for the triggered item.
These parts can be used to make up other item names so say you have a motion detector trigger in the Library and you want the library light to come on.

if (__Cam==ON) {
     sendConnand(_Light,ON)
}

This assumes that you have made _Cam match the Motion Detector of the triggering Camera, and the _Light is trhe deterrent light you want turned on in this event.

I really think you need to start slowly and get access to a system before you try such an advanced topic, with a little playing you will figure it out.

Regards

Paul

1 Like

Thanks Paul, what is the significance of the .get(0) to get(3)?

its returning the part based on the Underscore delimiter of the item name.

Call me stupid but that makes no sense

If your triggeringItem name is: KT_PIR_Detect

val location = triggeringItem.name.split("").get(0) (So, this returns KT?)
val device= triggeringItem.name.split(" “).get(1) (So, this returns PIR?)
val action= triggeringItem.name.split(”_").get(3) (So, this returns Detect?)

Why have the underscore the the last one but not the first ones. I don’t see any consistency.

I think that’s just what the forum has done to underscores outside of code fences.
Like the way it will hide <angles> if you don’t fence them.
The third part should be get(2) as well.

But you’ve grasped the idea of the split / get tools, it’s just string manipulation.

haha im not so sure I’ve grasped it at all :slight_smile:

the split command splits up a string into chunks. The item in the parenthesis is the delimiter. It is a string, enclosed in double quotations. In other words, the character in the delimiter string is where we want the string to be split up at. The command returns a array of strings which are the resulting chunks of the string. Each member of the array is one chunk of the string. The dot get and a number enclosed in parenthesis is which member of the array we want. The array is zero based so if we wanted to get the first chunk we would say .get (0) If we want the second chunk, we say .get(1) and so on

I think the correct syntax is:

val location = triggeringItem.name.split("_").get(0)
val device= triggeringItem.name.split("_").get(1)
val action= triggeringItem.name.split("_").get(2)
1 Like

Now, that makes perfect sense! Thanks gents!

It is difficult, but, the cool thing is once you grasp programming logic, they all work the same just different syntax for different languages. So… it is a skill you can use for the rest of your life
to me is fun

Absolutely Andrew!

So I’ve spent a fair bit of time changing the names to allow the underscore delimiter for stripping

I still don’t understand these lines:


    val _Sensor = gMotionSensors.members.findFirst[ cam | cam.name == Source"_Camera" ]
    val _Light = gAllLights.members.findFirst[ light | light.name == Source"_Light" ]

Specifically the section in square brackets, cam | cam.name == etc etc

Same with light | light.name

Can anyone explain? Config so far below:


/*Group Definitions for Lights*/
Group:Switch:SUM gAllLights          "All Lights"


/*Lights*/

Switch NorthWestDrive_Light  "North West Exterior"                                         (gLights_Random,gAllLights,gInsideLights)          { channel="zwave:device:ce741a7c:node2:switch_binary1" }
Switch NorthEastDrive_Light  "North East Exterior"                                         (gLights_Random,gAllLights,gInsideLights)          { channel="zwave:device:ce741a7c:node2:switch_binary2" }
Switch FrontDoor_Light   "Front Door"                                                      (gLights_Random,gAllLights,gInsideLights)          { channel="zwave:device:ce741a7c:node4:switch_binary1" }
Switch WestGarden_Light  "West Garden"                                                     (gLights_Random,gAllLights,gInsideLights)          { channel="zwave:device:ce741a7c:node4:switch_binary2" }
Switch Library_Light         "Library West Exit"                                           (gLights_Random,gAllLights,gInsideLights)          { channel="zwave:device:ce741a7c:node5:switch_binary" }
Switch Bird_Light            "Bird Light"                                                  (gLights_Random,gAllLights,gInsideLights)          { channel="zwave:device:ce741a7c:node8:switch_binary" }
Switch Patio_Light     "Patio Lights"                                                      (gLights_Random,gAllLights,gOutsideLights)         { channel="zwave:device:ce741a7c:node10:switch_binary1" }
Switch PatioBBQ_Light  "Patio BBQ Lights"                                                  (gLights_Random,gAllLights,gOutsideLights)         { channel="zwave:device:ce741a7c:node10:switch_binary2" }
Switch Library_Light         "West Exterior Light"                                         (gLights_Random,gAllLights,gOutsideLights)         { channel="zwave:device:ce741a7c:node14:switch_binary" }
Switch WallPendant_Light         "Wall Pendant"                                            (gLights_Random,gAllLights,gInsideLights)          { channel="zwave:device:ce741a7c:node6:switch_binary" }


/* Sensors */

Switch NorthWestDriveMotion_Armed               "[MAP(motion.map):%s] North West Drive Camera" (gMotionSensors)
Switch NorthEastDriveMotion_Armed               "[MAP(motion.map):%s] Driveway North Camera"   (gMotionSensors)
Switch PatioMotion_Armed                        "[MAP(motion.map):%s] Patio Camera"            (gMotionSensors)
Switch PatioBBQMotion_Armed                     "[MAP(motion.map):%s] Patio BBQ Camera"        (gMotionSensors)
Switch NorthCarParkMotion_Armed                 "[MAP(motion.map):%s] Entrance West Camera"    (gMotionSensors)
Switch LibraryMotion_Armed                      "[MAP(motion.map):%s] Library Camera"          (gMotionSensors)
Switch EastMotion_Armed                         "[MAP(motion.map):%s] East Camera"             (gMotionSensors)
Switch EntranceWestMotion_Armed                 "[MAP(motion.map):%s] Entrance West Camera"    (gMotionSensors)


rule "Motion activated Lights using CCTV Cameras"
when
	Member of gMotionSensors received command ON
then
	logInfo("Motion.rules", triggeringItem.name + " detected motion.")
   if (vTimeOfDay.state == "EVENING" || vTimeOfDay.state == "NIGHT") {
    val Source = triggeringItem.name.split("_").get(0)
    val _Sensor = gMotionSensors.members.findFirst[ cam | cam.name == Source"_Camera" ]
    val _Light = gAllLights.members.findFirst[ light | light.name == Source"_Light" ]
    }
   if (_Sensor.state == ON){
     sendCommand(_Light,ON)
	createTimer(now.plusSeconds(60)) [ | {sendCommand(_Light,OFF)}]
   }
end

Yes I have access now, but I dont have a rule I can implement, I’m still confused


rule "Motion activated Lights using CCTV Cameras"
when
        Member of gMotionSensors received command ON
then
        logInfo("Motion.rules", triggeringItem.name + " detected motion.")
   if (vTimeOfDay.state == "EVENING" || vTimeOfDay.state == "NIGHT") {
    val source = triggeringItem.name.split("_").get(0)
    val _Armed = gMotionSensors.members.findFirst[ arm | armed.name == source"_Armed" ]
    logInfo("Motion.rules", _armed.name + " Sensor")
     }
end

I would imagine, that when a group member receives command ON, that in the final log, I should see the name of the Armed item that corrosponds to the triggeringItem, but I see nothing