I've mentioned this in several other issues, but maybe it deserves an issue on its own: the way the deCONZ REST API plugin triggers rules differs significantly from the way the Hue bridge triggers rules. On the Hue bridge, rules are triggered when the last condition _becomes_ true, on deCONZ while all conditions _are_ true.
This causes many issues using rules created for the Hue bridge in deCONZ. While not unsolvable, re-writing the rules for deCONZ almost triples their footprint (as in number of rules and conditions needed to achieve the same logic).
As an example, on the Hue bridge I use a series of rules to control the lights in a room, based on:
/sensors/220;/sensors/222;/sensors/2.On the Hue bridge, I would use the following conditions, in a rule that recalls the daytime scene for the room (I actually use /sensors/222/state/dark in the second condition, but that's another story):
"conditions": [
{
"address": "/sensors/220/state/flag",
"operator": "eq",
"value": true
},
{
"address": "/sensors/222/state/lightlevel",
"operator": "lt",
"value": 12000
},
{
"address": "/sensors/102/state/flag",
"operator": "eq",
"value": false
}
]
On the Hue bridge this rule fires when:
On the deCONZ this rule fires continuously while all three conditions hold, _causing a scene recall every second_. With a couple of rooms setup like this, the ZigBee network is swamped. To remedy this, I'd need three rules, each with an added dx condition. So instead of one rule with three conditions, I need three rules with a total of twelve conditions.
On the Hue bridge, rules are triggered when the last condition becomes true, on deCONZ while all conditions are true.
I agree and suggest to adapt the behaviour of the fire then last condition becomes true. The sooner the better to not cause side effects when implementing it too late.
Thanks for the hint :)
So if I understand correctly the rule should fire only again if any of the conditions has refreshed since the rule triggered the last time?
By refreshed I mean not only changed but also same value with new timestamp like same button pressed again.
This is tricky, the Hue API doesn't distinguish between triggers and conditions, unlike e.g. HomeKit. When a condition _changes_ value, it might be a trigger (when the other conditions hold). When it doesn't change value, it's just a condition (regardless whether it's refreshed).
Best give some examples.
On the Hue bridge a rule with
"conditions": [
{
"address": "/sensors/2/state/flag",
"operator": "eq",
"value": "true"
}
]
fires only when state.flag _changes_ to true, i.e. when PUTting {"flag": true} while state.flag is false. It does _not_ fire when when PUTting {"flag": true} while state.flag was already true. For that, you'd use:
"conditions": [
{
"address": "/sensors/2/state/flag",
"operator": "eq",
"value": "true"
},
{
"address": "/sensors/2/state/lastupdated",
"operator": "dx"
}
]
which fires when state.lastupdated changes while state.flag is true. state.flag is updated before state.lastupdated, so this rules fires whenever PUTting {"flag": true}, regardless of the (previous) value of state.flag. Same for ddx variants.
In other words: including a condition for state.lastupdated forces any update ("refresh") of the state to be (considered as) a trigger.
As rule with
"conditions": [
{
"address": "/sensors/1/state/daylight",
"operator": "eq",
"value": "false"
},
{
"address": "/sensors/2/state/flag",
"operator": "eq",
"value": "true"
}
]
fires:
state.daylight _changes_ to false) while state.flag is true; orstate.flag _changes_ to true while state.daylight is false, i.e. when PUTting {"flag": true} while state.flag is false and state.daylight is false.A rule with
"conditions": [
{
"address": "/sensors/1/state/daylight",
"operator": "eq",
"value": "false"
},
{
"address": "/sensors/2/state/flag",
"operator": "eq",
"value": "true"
},
{
"address": "/sensors/2/state/lastupdated",
"operator": "dx"
}
]
fires when PUTting {"flag": true} while state.daylight is false, irrespective of the (previous) value of state.flag, but _not_ on sunset.
A rule with
"conditions": [
{
"address": "/config/localtime",
"operator": "in",
"value": "T07:00:00/T23:00:00"
},
{
"address": "/sensors/2/state/flag",
"operator": "eq",
"value": "true"
}
]
Fires:
state.flag is true; orstate.flag _becomes_ true between 7:00 and 23:00, i.e. when PUTting {"flag": true} while state.flag is false and config.localtime is between T07:00:00 and T23:00:00.In other words: only the first time in a range is (considered as) a trigger.
A rule with
"conditions": [
{
"address": "/sensors/3/state/lightlevel",
"operator": "lt",
"value": "12000"
}
]
fires when state.lightlevel changes from 13000 to 11000, but also when it changes from 11000 to 10000. A rule with
"conditions": [
{
"address": "/sensors/3/state/dark",
"operator": "eq",
"value": "true"
}
]
fires only when state.lightlevel drops below 12000 (assuming that's the value of config.tholddark).
Thanks for the detailed examples this helps a lot. For all rules which don't contain time related conditions my current understanding according the examples is:
Trigger if
1) all conditions met
2) anything changed, where anything also includes lastupdated via operator dx
Since each resource item has two time stamps for last set and last changed, this will be easy to implement.
For the time related conditions I need to think a bit more ..
I think one of the recent changes introduced a bug. An action got fired while not all conditions are true.
My rule:
{
"actions": [
{
"address": "/groups/3/scenes/5/recall",
"body": {},
"method": "PUT"
}
],
"conditions": [
{
"address": "/sensors/1/state/buttonevent",
"operator": "eq",
"value": "2002"
},
{
"address": "/sensors/1/state/lastupdated",
"operator": "dx"
},
{
"address": "/config/localtime",
"operator": "in",
"value": "T07:00:00/T22:00:00"
}
],
"created": "2017-08-30T21:13:46",
"lasttriggered": "2017-09-01T07:00:00",
"name": "Rule 1",
...
"periodic": 0,
"status": "enabled",
"timestriggered": 1
}
]
/sensors/1:
{
"config": {
"battery": 100,
"group": "5681",
"on": true,
"reachable": true
},
"ep": 1,
"manufacturername": "Philips",
"mode": 1,
"modelid": "RWL021",
"name": "Dimmer",
"state": {
"buttonevent": 2002,
"lastupdated": "2017-08-31T22:09:18"
},
"swversion": "5.45.1.16265",
"type": "ZHASwitch",
"uniqueid": "00:17:88:01:10:39:XX:XX-XX-fc00"
}
Desired rule: when pressing de DimUp button on the dimmer switch between 7:00 and 22:00, recall a specific scene.
However the rule did fire on 7:00 today, without pressing the button.
As you can see "lasttriggered": "2017-09-01T07:00:00" while the condition
{"address": "/sensors/1/state/lastupdated","operator": "dx"} should evaluate to false, because the last time I pressed the button was on: "lastupdated": "2017-08-31T22:09:18" (sensors/1/state)
I think one of the recent changes introduced a bug.
Rule triggering logic was changed in 2.04.70. I'm seeing some unexpected rule triggering as well, but haven't yet done extensive testing.
Desired rule: when pressing de DimUp button on the dimmer switch between 7:00 and 22:00, recall a specific scene.
Indeed, that's what the rule should do.
However the rule did fire on 7:00 today, without pressing the button.
That is a bug, indeed.
As a workaround, you could create a CLIPGenericFlag sensor Night. Create a set of rules to set this flag at 22:00 and clear it at 7:00 (or use a set of schedules for this). Then change the last condition in your rule to check this flag instead of /config/localtime. This has the added advantage that you can manually override the behaviour (e.g. when having a pyjama party, you would clear the flag, so you could still use the dimmer after 22:00). Of course, I expose these kind of flags to HomeKit, so the override is as easy as telling Siri to set Night off.
so you could still use the dimmer after 22:00
I also have a rule for "T22:00:00/T07:00:00", just with a different scene (warm color, less bright).
As a workaround, you could create a CLIPGenericFlag sensor
Thanks for this suggestion.
I like the idea of using CLIPGenericFlag (or even CLIPGenericStatus) to be able to override/affect the behaviour of sensors. It will also make changing the time range easier, because it is in one place.
I read that you also use this technique to override motion sensors behaviour in rooms (master switch) and track leaving rooms. Do you have an example of a "leaving room" rule?
Time for some serious rule triggering tests!
Setup my test Raspberry Pi, with just one Tr氓dfri light, one group and two scenes: 1 to set ct to 454, 2 to set ct to 250. Made sure the attribute reporting for colour temperature was setup.
Based on my ph.sh script, I created the following test script: test.sh.zip. Basically it creates a CLIPGenericFlag sensor and two rules: 1 to recall scene 1 when the flag is true, one to recall scene 2 when the flag is false. Tested both rules with dx on lastupdated and without.
The good news: the basics seem ok:
dx condition on state.lastupdated fire when state.flag is set (regardless whether it's to a different or to the same value);dx condition fire when state.flag is changed (i.e. set to a different value).The bad news:
state.flag is set to the same value, _even though state.lastupdated has been changed_!state.lastupdated upon creation. I think it should be initialised to "none" (cf. the rule's lasttriggered).dx rule when restoring the sensor's state.flag value from the database, even though state.lastupdated isn't changed. I suppose, state.lastupdated is initialised as empty upon creation of the resource and then restored from the database.dx rule only when the sensor's state.flag was true. I suppose, state.flag is initialised to false and then restored from the database.If memory serves, the Hue bridge doesn't restore values for CLIP sensors on startup, so after restarting the bridge, state.flag would be false and state.lastupdated would be "none" (numeric attributes, like state.status would be 0). It doesn't fire any rule on startup. In fact, I used the initial setting of the Daylight sensor as condition for startup rules, in combination with a CLIPGenericFlag _Boot Time_ that recorded the boot time in it's state.lastupdated. I think the Hue bridge also resets timestriggered to 0 on reboot.
For reference, here's the test transcript:
Fri Sep 1 13:12:52 CEST 2017: Testing v2.04.71
Fri Sep 1 13:12:52 CEST 2017: /sensors/2: {
"config": {
"on": true,
"reachable": true
},
"etag": "853815e4d97e28cb227d4d90982d6654",
"manufacturername": "homebridge-hue",
"modelid": "CLIPGenericFlag",
"name": "Test",
"state": {
"flag": false
},
"swversion": "1",
"type": "CLIPGenericFlag",
"uniqueid": "/sensors/1"
}
Fri Sep 1 13:12:52 CEST 2017: /rules/3: {
"actions": [
{
"address": "/groups/1/scenes/1/recall",
"body": {},
"method": "PUT"
}
],
"conditions": [
{
"address": "/sensors/2/state/flag",
"operator": "eq",
"value": true
},
{
"address": "/sensors/2/state/lastupdated",
"operator": "dx"
}
],
"created": "2017-09-01T11:12:52",
"etag": "853815e4d97e28cb227d4d90982d6654",
"lasttriggered": "none",
"name": "Test On, dx",
"owner": "philipshue",
"periodic": 0,
"status": "enabled",
"timestriggered": 0
}
Fri Sep 1 13:12:52 CEST 2017: /rules/4: {
"actions": [
{
"address": "/groups/1/scenes/2/recall",
"body": {},
"method": "PUT"
}
],
"conditions": [
{
"address": "/sensors/2/state/flag",
"operator": "eq",
"value": false
},
{
"address": "/sensors/2/state/lastupdated",
"operator": "dx"
}
],
"created": "2017-09-01T11:12:52",
"etag": "853815e4d97e28cb227d4d90982d6654",
"lasttriggered": "none",
"name": "Test Off, dx",
"owner": "philipshue",
"periodic": 0,
"status": "enabled",
"timestriggered": 0
}
Fri Sep 1 13:12:52 CEST 2017: /sensors/2/state: {"lastupdated": , "flag": false}
Fri Sep 1 13:12:53 CEST 2017: /rules/3: {"lasttriggered": "none", "timestriggered": 0}
Fri Sep 1 13:12:53 CEST 2017: /rules/4: {"lasttriggered": "none", "timestriggered": 0}
Fri Sep 1 13:12:57 CEST 2017: /sensors/2/state: set flag to false...
Fri Sep 1 13:12:58 CEST 2017: /sensors/2/state: {"lastupdated": "2017-09-01T11:12:57", "flag": false}
Fri Sep 1 13:12:58 CEST 2017: /rules/3: {"lasttriggered": "none", "timestriggered": 0}
Fri Sep 1 13:12:58 CEST 2017: /rules/4: {"lasttriggered": "2017-09-01T13:12:57", "timestriggered": 1}
Fri Sep 1 13:13:02 CEST 2017: /sensors/2/state: set flag to false...
Fri Sep 1 13:13:03 CEST 2017: /sensors/2/state: {"lastupdated": "2017-09-01T11:13:02", "flag": false}
Fri Sep 1 13:13:03 CEST 2017: /rules/3: {"lasttriggered": "none", "timestriggered": 0}
Fri Sep 1 13:13:04 CEST 2017: /rules/4: {"lasttriggered": "2017-09-01T13:13:02", "timestriggered": 2}
Fri Sep 1 13:13:08 CEST 2017: /sensors/2/state: set flag to true...
Fri Sep 1 13:13:09 CEST 2017: /sensors/2/state: {"lastupdated": "2017-09-01T11:13:08", "flag": true}
Fri Sep 1 13:13:09 CEST 2017: /rules/3: {"lasttriggered": "2017-09-01T13:13:08", "timestriggered": 1}
Fri Sep 1 13:13:09 CEST 2017: /rules/4: {"lasttriggered": "2017-09-01T13:13:02", "timestriggered": 2}
Fri Sep 1 13:13:13 CEST 2017: /sensors/2/state: set flag to true...
Fri Sep 1 13:13:14 CEST 2017: /sensors/2/state: {"lastupdated": "2017-09-01T11:13:13", "flag": true}
Fri Sep 1 13:13:14 CEST 2017: /rules/3: {"lasttriggered": "2017-09-01T13:13:13", "timestriggered": 2}
Fri Sep 1 13:13:15 CEST 2017: /rules/4: {"lasttriggered": "2017-09-01T13:13:02", "timestriggered": 2}
Fri Sep 1 13:13:19 CEST 2017: /sensors/2/state: set flag to false...
Fri Sep 1 13:13:20 CEST 2017: /sensors/2/state: {"lastupdated": "2017-09-01T11:13:19", "flag": false}
Fri Sep 1 13:13:20 CEST 2017: /rules/3: {"lasttriggered": "2017-09-01T13:13:13", "timestriggered": 2}
Fri Sep 1 13:13:20 CEST 2017: /rules/4: {"lasttriggered": "2017-09-01T13:13:19", "timestriggered": 3}
Fri Sep 1 13:13:24 CEST 2017: /sensors/2/state: set flag to false...
Fri Sep 1 13:13:25 CEST 2017: /sensors/2/state: {"lastupdated": "2017-09-01T11:13:24", "flag": false}
Fri Sep 1 13:13:25 CEST 2017: /rules/3: {"lasttriggered": "2017-09-01T13:13:13", "timestriggered": 2}
Fri Sep 1 13:13:26 CEST 2017: /rules/4: {"lasttriggered": "2017-09-01T13:13:24", "timestriggered": 4}
Fri Sep 1 13:13:30 CEST 2017: /sensors/2/state: set flag to true...
Fri Sep 1 13:13:31 CEST 2017: /sensors/2/state: {"lastupdated": "2017-09-01T11:13:30", "flag": true}
Fri Sep 1 13:13:31 CEST 2017: /rules/3: {"lasttriggered": "2017-09-01T13:13:30", "timestriggered": 3}
Fri Sep 1 13:13:31 CEST 2017: /rules/4: {"lasttriggered": "2017-09-01T13:13:24", "timestriggered": 4}
Fri Sep 1 13:13:35 CEST 2017: /sensors/2/state: set flag to true...
Fri Sep 1 13:13:36 CEST 2017: /sensors/2/state: {"lastupdated": "2017-09-01T11:13:35", "flag": true}
Fri Sep 1 13:13:36 CEST 2017: /rules/3: {"lasttriggered": "2017-09-01T13:13:35", "timestriggered": 4}
Fri Sep 1 13:13:36 CEST 2017: /rules/4: {"lasttriggered": "2017-09-01T13:13:24", "timestriggered": 4}
Fri Sep 1 13:13:40 CEST 2017: /groups/1/action: set on to false...
Fri Sep 1 13:13:42 CEST 2017: /sensors/2/state: {"lastupdated": "2017-09-01T11:13:35", "flag": true}
Fri Sep 1 13:13:42 CEST 2017: /rules/3: {"lasttriggered": "2017-09-01T13:13:35", "timestriggered": 4}
Fri Sep 1 13:13:42 CEST 2017: /rules/4: {"lasttriggered": "2017-09-01T13:13:24", "timestriggered": 4}
Fri Sep 1 13:13:42 CEST 2017: restart deCONZ...
Fri Sep 1 13:14:12 CEST 2017: /sensors/2/state: {"lastupdated": "2017-09-01T09:13:35", "flag": true}
Fri Sep 1 13:14:12 CEST 2017: /rules/3: {"lasttriggered": "2017-09-01T13:13:47", "timestriggered": 5}
Fri Sep 1 13:14:12 CEST 2017: /rules/4: {"lasttriggered": "none", "timestriggered": 4}
Fri Sep 1 13:14:16 CEST 2017: /sensors/2/state: set flag to false...
Fri Sep 1 13:14:18 CEST 2017: /sensors/2/state: {"lastupdated": "2017-09-01T11:14:17", "flag": false}
Fri Sep 1 13:14:18 CEST 2017: /rules/3: {"lasttriggered": "2017-09-01T13:13:47", "timestriggered": 5}
Fri Sep 1 13:14:18 CEST 2017: /rules/4: {"lasttriggered": "2017-09-01T13:14:17", "timestriggered": 5}
Fri Sep 1 13:14:22 CEST 2017: /groups/1/action: set on to false...
Fri Sep 1 13:14:23 CEST 2017: /sensors/2/state: {"lastupdated": "2017-09-01T11:14:17", "flag": false}
Fri Sep 1 13:14:23 CEST 2017: /rules/3: {"lasttriggered": "2017-09-01T13:13:47", "timestriggered": 5}
Fri Sep 1 13:14:24 CEST 2017: /rules/4: {"lasttriggered": "2017-09-01T13:14:17", "timestriggered": 5}
Fri Sep 1 13:14:24 CEST 2017: restart deCONZ...
Fri Sep 1 13:14:54 CEST 2017: /sensors/2/state: {"lastupdated": "2017-09-01T09:14:17", "flag": false}
Fri Sep 1 13:14:54 CEST 2017: /rules/3: {"lasttriggered": "none", "timestriggered": 5}
Fri Sep 1 13:14:54 CEST 2017: /rules/4: {"lasttriggered": "2017-09-01T13:14:29", "timestriggered": 6}
Fri Sep 1 13:14:54 CEST 2017: /rules/3: {
"actions": [
{
"address": "/groups/1/scenes/1/recall",
"body": {},
"method": "PUT"
}
],
"conditions": [
{
"address": "/sensors/2/state/flag",
"operator": "eq",
"value": true
}
],
"created": "2017-09-01T11:12:52",
"etag": "fe13890a25f88e6c9f170350bff9c7d9",
"lasttriggered": "none",
"name": "Test On, dx",
"owner": "philipshue",
"periodic": 0,
"status": "enabled",
"timestriggered": 5
}
Fri Sep 1 13:14:54 CEST 2017: /rules/3: {
"actions": [
{
"address": "/groups/1/scenes/2/recall",
"body": {},
"method": "PUT"
}
],
"conditions": [
{
"address": "/sensors/2/state/flag",
"operator": "eq",
"value": false
}
],
"created": "2017-09-01T11:12:52",
"etag": "fe13890a25f88e6c9f170350bff9c7d9",
"lasttriggered": "2017-09-01T13:14:29",
"name": "Test Off, dx",
"owner": "philipshue",
"periodic": 0,
"status": "enabled",
"timestriggered": 6
}
Fri Sep 1 13:14:58 CEST 2017: /sensors/2/state: set flag to false...
Fri Sep 1 13:15:00 CEST 2017: /sensors/2/state: {"lastupdated": "2017-09-01T11:14:59", "flag": false}
Fri Sep 1 13:15:00 CEST 2017: /rules/3: {"lasttriggered": "none", "timestriggered": 5}
Fri Sep 1 13:15:00 CEST 2017: /rules/4: {"lasttriggered": "2017-09-01T13:14:29", "timestriggered": 6}
Fri Sep 1 13:15:04 CEST 2017: /sensors/2/state: set flag to false...
Fri Sep 1 13:15:05 CEST 2017: /sensors/2/state: {"lastupdated": "2017-09-01T11:15:04", "flag": false}
Fri Sep 1 13:15:05 CEST 2017: /rules/3: {"lasttriggered": "none", "timestriggered": 5}
Fri Sep 1 13:15:05 CEST 2017: /rules/4: {"lasttriggered": "2017-09-01T13:14:29", "timestriggered": 6}
Fri Sep 1 13:15:09 CEST 2017: /sensors/2/state: set flag to true...
Fri Sep 1 13:15:11 CEST 2017: /sensors/2/state: {"lastupdated": "2017-09-01T11:15:09", "flag": true}
Fri Sep 1 13:15:11 CEST 2017: /rules/3: {"lasttriggered": "2017-09-01T13:15:09", "timestriggered": 6}
Fri Sep 1 13:15:12 CEST 2017: /rules/4: {"lasttriggered": "2017-09-01T13:14:29", "timestriggered": 6}
Fri Sep 1 13:15:16 CEST 2017: /sensors/2/state: set flag to true...
Fri Sep 1 13:15:18 CEST 2017: /sensors/2/state: {"lastupdated": "2017-09-01T11:15:16", "flag": true}
Fri Sep 1 13:15:18 CEST 2017: /rules/3: {"lasttriggered": "2017-09-01T13:15:09", "timestriggered": 6}
Fri Sep 1 13:15:18 CEST 2017: /rules/4: {"lasttriggered": "2017-09-01T13:14:29", "timestriggered": 6}
Fri Sep 1 13:15:22 CEST 2017: /sensors/2/state: set flag to false...
Fri Sep 1 13:15:23 CEST 2017: /sensors/2/state: {"lastupdated": "2017-09-01T11:15:22", "flag": false}
Fri Sep 1 13:15:23 CEST 2017: /rules/3: {"lasttriggered": "2017-09-01T13:15:09", "timestriggered": 6}
Fri Sep 1 13:15:24 CEST 2017: /rules/4: {"lasttriggered": "2017-09-01T13:15:22", "timestriggered": 7}
Fri Sep 1 13:15:28 CEST 2017: /sensors/2/state: set flag to false...
Fri Sep 1 13:15:29 CEST 2017: /sensors/2/state: {"lastupdated": "2017-09-01T11:15:28", "flag": false}
Fri Sep 1 13:15:29 CEST 2017: /rules/3: {"lasttriggered": "2017-09-01T13:15:09", "timestriggered": 6}
Fri Sep 1 13:15:29 CEST 2017: /rules/4: {"lasttriggered": "2017-09-01T13:15:22", "timestriggered": 7}
Fri Sep 1 13:15:33 CEST 2017: /sensors/2/state: set flag to true...
Fri Sep 1 13:15:34 CEST 2017: /sensors/2/state: {"lastupdated": "2017-09-01T11:15:33", "flag": true}
Fri Sep 1 13:15:34 CEST 2017: /rules/3: {"lasttriggered": "2017-09-01T13:15:33", "timestriggered": 7}
Fri Sep 1 13:15:34 CEST 2017: /rules/4: {"lasttriggered": "2017-09-01T13:15:22", "timestriggered": 7}
Fri Sep 1 13:15:38 CEST 2017: /sensors/2/state: set flag to true...
Fri Sep 1 13:15:40 CEST 2017: /sensors/2/state: {"lastupdated": "2017-09-01T11:15:38", "flag": true}
Fri Sep 1 13:15:40 CEST 2017: /rules/3: {"lasttriggered": "2017-09-01T13:15:33", "timestriggered": 7}
Fri Sep 1 13:15:40 CEST 2017: /rules/4: {"lasttriggered": "2017-09-01T13:15:22", "timestriggered": 7}
Fri Sep 1 13:15:44 CEST 2017: /groups/1/action: set on to false...
Fri Sep 1 13:15:45 CEST 2017: /sensors/2/state: {"lastupdated": "2017-09-01T11:15:38", "flag": true}
Fri Sep 1 13:15:45 CEST 2017: /rules/3: {"lasttriggered": "2017-09-01T13:15:33", "timestriggered": 7}
Fri Sep 1 13:15:45 CEST 2017: /rules/4: {"lasttriggered": "2017-09-01T13:15:22", "timestriggered": 7}
Fri Sep 1 13:15:45 CEST 2017: restart deCONZ...
Fri Sep 1 13:16:15 CEST 2017: /sensors/2/state: {"lastupdated": "2017-09-01T09:15:38", "flag": true}
Fri Sep 1 13:16:16 CEST 2017: /rules/3: {"lasttriggered": "2017-09-01T13:15:50", "timestriggered": 8}
Fri Sep 1 13:16:16 CEST 2017: /rules/4: {"lasttriggered": "none", "timestriggered": 7}
Fri Sep 1 13:16:20 CEST 2017: /sensors/2/state: set flag to false...
Fri Sep 1 13:16:21 CEST 2017: /sensors/2/state: {"lastupdated": "2017-09-01T11:16:20", "flag": false}
Fri Sep 1 13:16:21 CEST 2017: /rules/3: {"lasttriggered": "2017-09-01T13:15:50", "timestriggered": 8}
Fri Sep 1 13:16:21 CEST 2017: /rules/4: {"lasttriggered": "2017-09-01T13:16:20", "timestriggered": 8}
Fri Sep 1 13:16:25 CEST 2017: /groups/1/action: set on to false...
Fri Sep 1 13:16:26 CEST 2017: /sensors/2/state: {"lastupdated": "2017-09-01T11:16:20", "flag": false}
Fri Sep 1 13:16:26 CEST 2017: /rules/3: {"lasttriggered": "2017-09-01T13:15:50", "timestriggered": 8}
Fri Sep 1 13:16:27 CEST 2017: /rules/4: {"lasttriggered": "2017-09-01T13:16:20", "timestriggered": 8}
Fri Sep 1 13:16:27 CEST 2017: restart deCONZ...
Fri Sep 1 13:16:57 CEST 2017: /sensors/2/state: {"lastupdated": "2017-09-01T09:16:20", "flag": false}
Fri Sep 1 13:16:57 CEST 2017: /rules/3: {"lasttriggered": "none", "timestriggered": 8}
Fri Sep 1 13:16:57 CEST 2017: /rules/4: {"lasttriggered": "none", "timestriggered": 8}
And here's the event log (using dc_eventlog):
Fri Sep 01 2017 13:12:40: start
Fri Sep 01 2017 13:12:40: listening on localhost:443
Fri Sep 01 2017 13:12:57: /lights/1/state: {"colormode":"ct"}
Fri Sep 01 2017 13:12:57: /groups/1/state: {"any_on":true}
Fri Sep 01 2017 13:12:57: /groups/1/scenes/2
Fri Sep 01 2017 13:13:02: /groups/1/scenes/2
Fri Sep 01 2017 13:13:08: /sensors/2/state: {"flag":true,"lastupdated":"2017-09-01T11:13:08"}
Fri Sep 01 2017 13:13:08: /lights/1/state: {"ct":454}
Fri Sep 01 2017 13:13:08: /groups/1/scenes/1
Fri Sep 01 2017 13:13:14: /groups/1/scenes/1
Fri Sep 01 2017 13:13:19: /sensors/2/state: {"flag":false,"lastupdated":"2017-09-01T11:13:19"}
Fri Sep 01 2017 13:13:19: /lights/1/state: {"ct":250}
Fri Sep 01 2017 13:13:19: /groups/1/scenes/2
Fri Sep 01 2017 13:13:25: /groups/1/scenes/2
Fri Sep 01 2017 13:13:30: /sensors/2/state: {"flag":true,"lastupdated":"2017-09-01T11:13:30"}
Fri Sep 01 2017 13:13:30: /lights/1/state: {"ct":454}
Fri Sep 01 2017 13:13:30: /groups/1/scenes/1
Fri Sep 01 2017 13:13:35: /groups/1/scenes/1
Fri Sep 01 2017 13:13:41: /lights/1/state: {"on":false}
Fri Sep 01 2017 13:13:41: /groups/1/state: {"any_on":false}
Fri Sep 01 2017 13:13:43: connection closed - retry in 10 seconds
Fri Sep 01 2017 13:13:53: listening on localhost:443
Fri Sep 01 2017 13:14:10: /lights/1/state: {"on":true}
Fri Sep 01 2017 13:14:10: /groups/1/state: {"any_on":true}
Fri Sep 01 2017 13:14:11: /lights/1/state: {"bri":254}
Fri Sep 01 2017 13:14:11: /lights/1/state: {"ct":454}
Fri Sep 01 2017 13:14:11: /lights/1/state: {"colormode":"xy"}
Fri Sep 01 2017 13:14:17: /sensors/2/state: {"flag":false,"lastupdated":"2017-09-01T11:14:17"}
Fri Sep 01 2017 13:14:17: /lights/1/state: {"colormode":"ct"}
Fri Sep 01 2017 13:14:17: /lights/1/state: {"ct":250}
Fri Sep 01 2017 13:14:17: /groups/1/scenes/2
Fri Sep 01 2017 13:14:22: /lights/1/state: {"on":false}
Fri Sep 01 2017 13:14:22: /groups/1/state: {"any_on":false}
Fri Sep 01 2017 13:14:24: connection closed - retry in 10 seconds
Fri Sep 01 2017 13:14:34: listening on localhost:443
Fri Sep 01 2017 13:14:51: /lights/1/state: {"on":true}
Fri Sep 01 2017 13:14:51: /groups/1/state: {"any_on":true}
Fri Sep 01 2017 13:14:52: /lights/1/state: {"bri":254}
Fri Sep 01 2017 13:14:53: /lights/1/state: {"ct":250}
Fri Sep 01 2017 13:14:53: /lights/1/state: {"colormode":"xy"}
Fri Sep 01 2017 13:15:09: /sensors/2/state: {"flag":true,"lastupdated":"2017-09-01T11:15:09"}
Fri Sep 01 2017 13:15:09: /lights/1/state: {"colormode":"ct"}
Fri Sep 01 2017 13:15:09: /lights/1/state: {"ct":454}
Fri Sep 01 2017 13:15:10: /groups/1/scenes/1
Fri Sep 01 2017 13:15:22: /sensors/2/state: {"flag":false,"lastupdated":"2017-09-01T11:15:22"}
Fri Sep 01 2017 13:15:22: /lights/1/state: {"ct":250}
Fri Sep 01 2017 13:15:22: /groups/1/scenes/2
Fri Sep 01 2017 13:15:33: /sensors/2/state: {"flag":true,"lastupdated":"2017-09-01T11:15:33"}
Fri Sep 01 2017 13:15:33: /lights/1/state: {"ct":454}
Fri Sep 01 2017 13:15:33: /groups/1/scenes/1
Fri Sep 01 2017 13:15:44: /lights/1/state: {"on":false}
Fri Sep 01 2017 13:15:44: /groups/1/state: {"any_on":false}
Fri Sep 01 2017 13:15:46: connection closed - retry in 10 seconds
Fri Sep 01 2017 13:15:56: listening on localhost:443
Fri Sep 01 2017 13:16:13: /lights/1/state: {"on":true}
Fri Sep 01 2017 13:16:13: /groups/1/state: {"any_on":true}
Fri Sep 01 2017 13:16:14: /lights/1/state: {"bri":254}
Fri Sep 01 2017 13:16:15: /lights/1/state: {"ct":454}
Fri Sep 01 2017 13:16:15: /lights/1/state: {"colormode":"xy"}
Fri Sep 01 2017 13:16:20: /sensors/2/state: {"flag":false,"lastupdated":"2017-09-01T11:16:20"}
Fri Sep 01 2017 13:16:20: /lights/1/state: {"colormode":"ct"}
Fri Sep 01 2017 13:16:20: /lights/1/state: {"ct":250}
Fri Sep 01 2017 13:16:20: /groups/1/scenes/2
Fri Sep 01 2017 13:16:25: /lights/1/state: {"on":false}
Fri Sep 01 2017 13:16:25: /groups/1/state: {"any_on":false}
Fri Sep 01 2017 13:16:27: connection closed - retry in 10 seconds
Fri Sep 01 2017 13:16:37: listening on localhost:443
Fri Sep 01 2017 13:16:55: /lights/1/state: {"bri":254}
Fri Sep 01 2017 13:16:56: /lights/1/state: {"ct":250}
Fri Sep 01 2017 13:16:56: /lights/1/state: {"colormode":"xy"}
Fri Sep 01 2017 13:16:57: {"e":"deleted","r":"sensors","sensor":{"id":"2"},"t":"event"}
I also have a rule for "T22:00:00/T07:00:00", just with a different scene (warm color, less bright).
Did that one trigger at 22:00?
Do you have an example of a "leaving room" rule?
It's a whole set of rules, based around a CLIPGenericStatus sensor, which keeps the state of the room:
And a CLIPGenericFlag as the room's master switch, using the following logic:
I use a second set of rules to control the lights based on the master switch, the lightlevel sensor, and the Night flag, so the lights turn on during an eclipse (haven't been able to test that, but it works during a thunderstorm), or turn off when I open tye curtains. I expose the master swicth to HomeKit and use HomeKit rules to control my Sonos speakers and fan (connected to an Eve Energy plug), in combination with the temperature sensor.
I had this running perfectly on the Hue bridge, but needed to workaround the old, faulty rule triggering logic of deCONZ. Now I need to clean that up. I also want to do some more optimisations so I'd need fewer conditions and/or rules. I plan to post the scripts maintaining these rules on GitHub once I'm done with that.
As you have noticed there are problems that conditions and CLIP sensors go fancy after startup due database restored values. This drives me crazy at night, because everytime I recompile and start deCONZ I'm sitting in the dark, because the turn the lights off due no motion rules are triggering :)
I'll check that later on. Should it work if rules are only triggered, when sensor values have a newer time stamp than deCONZ start time?
Should it work if rules are only triggered, when sensor values have a newer time stamp than deCONZ start time?
That sounds right.
I'm not sure to the best approach regarding restoring the CLIP sensor values in the first place. After a simple restart during development and test, you'd like the sensor values to be restored. After a power outage you'd like them to be initialised to 0 / false.
This drives me crazy at night, because everytime I recompile and start deCONZ I'm sitting in the dark
Same here. I can work by the light of my screen, but I hate it when my music stops...
because the turn the lights off due no motion rules are triggering
Turning lights off on no motion makes sense for a hallway, where you pass through, but it doesn't make sense for a room, where you sit still. That's why I started the rules on presence in an adjacent room, to turn the lights off on _leaving_ the room instead.
Some more testing. It would seem that once deCONZ finds a first potential trigger, it doesn't check the remaining conditions for triggers, but only for conditions. So a set of (value1 eq true, value2 eq true, value2 dx) triggers when value1 becomes true while value2 is already true, ignoring the dx on value2. This is probably the same issue as @snozzlebert logged.
The following rules should never trigger, since I cannot set two flags at the same time. Yet they do.
Fri Sep 1 14:56:29 CEST 2017: Testing v2.04.73
Fri Sep 1 14:56:29 CEST 2017: /sensors/9: {
"config": {
"on": true,
"reachable": true
},
"etag": "cc63b12e652a95cc451a9b1fce3c6b9e",
"manufacturername": "homebridge-hue",
"modelid": "CLIPGenericFlag",
"name": "Test 1",
"state": {
"flag": false
},
"swversion": "1",
"type": "CLIPGenericFlag",
"uniqueid": "/sensors/1"
}
Fri Sep 1 14:56:29 CEST 2017: /sensors/10: {
"config": {
"on": true,
"reachable": true
},
"etag": "cc63b12e652a95cc451a9b1fce3c6b9e",
"manufacturername": "homebridge-hue",
"modelid": "CLIPGenericFlag",
"name": "Test 2",
"state": {
"flag": false
},
"swversion": "1",
"type": "CLIPGenericFlag",
"uniqueid": "/sensors/2"
}
Fri Sep 1 14:56:29 CEST 2017: /rules/8: {
"actions": [
{
"address": "/groups/1/scenes/1/recall",
"body": {},
"method": "PUT"
}
],
"conditions": [
{
"address": "/sensors/9/state/flag",
"operator": "eq",
"value": true
},
{
"address": "/sensors/9/state/lastupdated",
"operator": "dx"
},
{
"address": "/sensors/10/state/flag",
"operator": "eq",
"value": true
},
{
"address": "/sensors/10/state/lastupdated",
"operator": "dx"
}
],
"created": "2017-09-01T12:56:29",
"etag": "cc63b12e652a95cc451a9b1fce3c6b9e",
"lasttriggered": "none",
"name": "Test On",
"owner": "philipshue",
"periodic": 0,
"status": "enabled",
"timestriggered": 0
}
Fri Sep 1 14:56:30 CEST 2017: /rules/9: {
"actions": [
{
"address": "/groups/1/scenes/2/recall",
"body": {},
"method": "PUT"
}
],
"conditions": [
{
"address": "/sensors/9/state/flag",
"operator": "eq",
"value": false
},
{
"address": "/sensors/9/state/lastupdated",
"operator": "dx"
},
{
"address": "/sensors/10/state/flag",
"operator": "eq",
"value": true
},
{
"address": "/sensors/10/state/lastupdated",
"operator": "dx"
}
],
"created": "2017-09-01T12:56:30",
"etag": "4bf1013832570b9e0e07d60aa88c7935",
"lasttriggered": "none",
"name": "Test Off",
"owner": "philipshue",
"periodic": 0,
"status": "enabled",
"timestriggered": 0
}
Fri Sep 1 14:56:30 CEST 2017: /sensors/9/state: {"lastupdated": , "flag": false}
Fri Sep 1 14:56:30 CEST 2017: /sensors/10/state: {"lastupdated": , "flag": false}
Fri Sep 1 14:56:30 CEST 2017: /rules/8: {"lasttriggered": "none", "timestriggered": 0}
Fri Sep 1 14:56:30 CEST 2017: /rules/9: {"lasttriggered": "none", "timestriggered": 0}
Fri Sep 1 14:56:34 CEST 2017: /sensors/9/state: set flag to false...
Fri Sep 1 14:56:35 CEST 2017: /sensors/9/state: {"lastupdated": "2017-09-01T12:56:34", "flag": false}
Fri Sep 1 14:56:35 CEST 2017: /sensors/10/state: {"lastupdated": , "flag": false}
Fri Sep 1 14:56:35 CEST 2017: /rules/8: {"lasttriggered": "none", "timestriggered": 0}
Fri Sep 1 14:56:35 CEST 2017: /rules/9: {"lasttriggered": "none", "timestriggered": 0}
Fri Sep 1 14:56:39 CEST 2017: /sensors/10/state: set flag to false...
Fri Sep 1 14:56:41 CEST 2017: /sensors/9/state: {"lastupdated": "2017-09-01T12:56:34", "flag": false}
Fri Sep 1 14:56:41 CEST 2017: /sensors/10/state: {"lastupdated": "2017-09-01T12:56:39", "flag": false}
Fri Sep 1 14:56:41 CEST 2017: /rules/8: {"lasttriggered": "none", "timestriggered": 0}
Fri Sep 1 14:56:41 CEST 2017: /rules/9: {"lasttriggered": "none", "timestriggered": 0}
Fri Sep 1 14:56:45 CEST 2017: /sensors/9/state: set flag to true...
Fri Sep 1 14:56:46 CEST 2017: /sensors/9/state: {"lastupdated": "2017-09-01T12:56:45", "flag": true}
Fri Sep 1 14:56:46 CEST 2017: /sensors/10/state: {"lastupdated": "2017-09-01T12:56:39", "flag": false}
Fri Sep 1 14:56:46 CEST 2017: /rules/8: {"lasttriggered": "none", "timestriggered": 0}
Fri Sep 1 14:56:46 CEST 2017: /rules/9: {"lasttriggered": "none", "timestriggered": 0}
Fri Sep 1 14:56:50 CEST 2017: /sensors/10/state: set flag to true...
Fri Sep 1 14:56:51 CEST 2017: /sensors/9/state: {"lastupdated": "2017-09-01T12:56:45", "flag": true}
Fri Sep 1 14:56:52 CEST 2017: /sensors/10/state: {"lastupdated": "2017-09-01T12:56:50", "flag": true}
Fri Sep 1 14:56:52 CEST 2017: /rules/8: {"lasttriggered": "2017-09-01T14:56:50", "timestriggered": 1}
Fri Sep 1 14:56:52 CEST 2017: /rules/9: {"lasttriggered": "none", "timestriggered": 0}
Fri Sep 1 14:56:56 CEST 2017: /sensors/10/state: set flag to false...
Fri Sep 1 14:56:57 CEST 2017: /sensors/9/state: {"lastupdated": "2017-09-01T12:56:45", "flag": true}
Fri Sep 1 14:56:57 CEST 2017: /sensors/10/state: {"lastupdated": "2017-09-01T12:56:56", "flag": false}
Fri Sep 1 14:56:57 CEST 2017: /rules/8: {"lasttriggered": "2017-09-01T14:56:50", "timestriggered": 1}
Fri Sep 1 14:56:57 CEST 2017: /rules/9: {"lasttriggered": "none", "timestriggered": 0}
Fri Sep 1 14:57:01 CEST 2017: /sensors/9/state: set flag to false...
Fri Sep 1 14:57:02 CEST 2017: /sensors/9/state: {"lastupdated": "2017-09-01T12:57:01", "flag": false}
Fri Sep 1 14:57:03 CEST 2017: /sensors/10/state: {"lastupdated": "2017-09-01T12:56:56", "flag": false}
Fri Sep 1 14:57:03 CEST 2017: /rules/8: {"lasttriggered": "2017-09-01T14:56:50", "timestriggered": 1}
Fri Sep 1 14:57:03 CEST 2017: /rules/9: {"lasttriggered": "none", "timestriggered": 0}
Fri Sep 1 14:57:07 CEST 2017: /sensors/10/state: set flag to true...
Fri Sep 1 14:57:08 CEST 2017: /sensors/9/state: {"lastupdated": "2017-09-01T12:57:01", "flag": false}
Fri Sep 1 14:57:08 CEST 2017: /sensors/10/state: {"lastupdated": "2017-09-01T12:57:07", "flag": true}
Fri Sep 1 14:57:08 CEST 2017: /rules/8: {"lasttriggered": "2017-09-01T14:56:50", "timestriggered": 1}
Fri Sep 1 14:57:08 CEST 2017: /rules/9: {"lasttriggered": "2017-09-01T14:57:07", "timestriggered": 1}
Fri Sep 1 14:57:12 CEST 2017: /sensors/9/state: set flag to true...
Fri Sep 1 14:57:13 CEST 2017: /sensors/9/state: {"lastupdated": "2017-09-01T12:57:12", "flag": true}
Fri Sep 1 14:57:13 CEST 2017: /sensors/10/state: {"lastupdated": "2017-09-01T12:57:07", "flag": true}
Fri Sep 1 14:57:14 CEST 2017: /rules/8: {"lasttriggered": "2017-09-01T14:57:12", "timestriggered": 2}
Fri Sep 1 14:57:14 CEST 2017: /rules/9: {"lasttriggered": "2017-09-01T14:57:07", "timestriggered": 1}
The following rules also fail on the last test:
Fri Sep 1 15:04:54 CEST 2017: Testing v2.04.73
Fri Sep 1 15:04:54 CEST 2017: /sensors/11: {
"config": {
"on": true,
"reachable": true
},
"etag": "d33a8b708fa612254eea6624b944caf9",
"manufacturername": "homebridge-hue",
"modelid": "CLIPGenericFlag",
"name": "Test 1",
"state": {
"flag": false
},
"swversion": "1",
"type": "CLIPGenericFlag",
"uniqueid": "/sensors/1"
}
Fri Sep 1 15:04:54 CEST 2017: /sensors/12: {
"config": {
"on": true,
"reachable": true
},
"etag": "d33a8b708fa612254eea6624b944caf9",
"manufacturername": "homebridge-hue",
"modelid": "CLIPGenericFlag",
"name": "Test 2",
"state": {
"flag": false
},
"swversion": "1",
"type": "CLIPGenericFlag",
"uniqueid": "/sensors/2"
}
Fri Sep 1 15:04:54 CEST 2017: /rules/10: {
"actions": [
{
"address": "/groups/1/scenes/1/recall",
"body": {},
"method": "PUT"
}
],
"conditions": [
{
"address": "/sensors/11/state/flag",
"operator": "eq",
"value": true
},
{
"address": "/sensors/12/state/flag",
"operator": "eq",
"value": true
},
{
"address": "/sensors/12/state/lastupdated",
"operator": "dx"
}
],
"created": "2017-09-01T13:04:54",
"etag": "d33a8b708fa612254eea6624b944caf9",
"lasttriggered": "none",
"name": "Test On",
"owner": "philipshue",
"periodic": 0,
"status": "enabled",
"timestriggered": 0
}
Fri Sep 1 15:04:55 CEST 2017: /rules/11: {
"actions": [
{
"address": "/groups/1/scenes/2/recall",
"body": {},
"method": "PUT"
}
],
"conditions": [
{
"address": "/sensors/11/state/flag",
"operator": "eq",
"value": false
},
{
"address": "/sensors/12/state/flag",
"operator": "eq",
"value": true
},
{
"address": "/sensors/12/state/lastupdated",
"operator": "dx"
}
],
"created": "2017-09-01T13:04:55",
"etag": "be900d6b9a1da6c88081b18fa13b13c9",
"lasttriggered": "none",
"name": "Test Off",
"owner": "philipshue",
"periodic": 0,
"status": "enabled",
"timestriggered": 0
}
Fri Sep 1 15:04:55 CEST 2017: /sensors/11/state: {"lastupdated": , "flag": false}
Fri Sep 1 15:04:55 CEST 2017: /sensors/12/state: {"lastupdated": , "flag": false}
Fri Sep 1 15:04:55 CEST 2017: /rules/10: {"lasttriggered": "none", "timestriggered": 0}
Fri Sep 1 15:04:55 CEST 2017: /rules/11: {"lasttriggered": "none", "timestriggered": 0}
Fri Sep 1 15:04:59 CEST 2017: /sensors/11/state: set flag to false...
Fri Sep 1 15:05:00 CEST 2017: /sensors/11/state: {"lastupdated": "2017-09-01T13:04:59", "flag": false}
Fri Sep 1 15:05:00 CEST 2017: /sensors/12/state: {"lastupdated": , "flag": false}
Fri Sep 1 15:05:00 CEST 2017: /rules/10: {"lasttriggered": "none", "timestriggered": 0}
Fri Sep 1 15:05:00 CEST 2017: /rules/11: {"lasttriggered": "none", "timestriggered": 0}
Fri Sep 1 15:05:04 CEST 2017: /sensors/12/state: set flag to false...
Fri Sep 1 15:05:06 CEST 2017: /sensors/11/state: {"lastupdated": "2017-09-01T13:04:59", "flag": false}
Fri Sep 1 15:05:06 CEST 2017: /sensors/12/state: {"lastupdated": "2017-09-01T13:05:05", "flag": false}
Fri Sep 1 15:05:06 CEST 2017: /rules/10: {"lasttriggered": "none", "timestriggered": 0}
Fri Sep 1 15:05:06 CEST 2017: /rules/11: {"lasttriggered": "none", "timestriggered": 0}
Fri Sep 1 15:05:10 CEST 2017: /sensors/11/state: set flag to true...
Fri Sep 1 15:05:11 CEST 2017: /sensors/11/state: {"lastupdated": "2017-09-01T13:05:10", "flag": true}
Fri Sep 1 15:05:11 CEST 2017: /sensors/12/state: {"lastupdated": "2017-09-01T13:05:05", "flag": false}
Fri Sep 1 15:05:11 CEST 2017: /rules/10: {"lasttriggered": "none", "timestriggered": 0}
Fri Sep 1 15:05:11 CEST 2017: /rules/11: {"lasttriggered": "none", "timestriggered": 0}
Fri Sep 1 15:05:15 CEST 2017: /sensors/12/state: set flag to true...
Fri Sep 1 15:05:17 CEST 2017: /sensors/11/state: {"lastupdated": "2017-09-01T13:05:10", "flag": true}
Fri Sep 1 15:05:17 CEST 2017: /sensors/12/state: {"lastupdated": "2017-09-01T13:05:15", "flag": true}
Fri Sep 1 15:05:17 CEST 2017: /rules/10: {"lasttriggered": "2017-09-01T15:05:15", "timestriggered": 1}
Fri Sep 1 15:05:17 CEST 2017: /rules/11: {"lasttriggered": "none", "timestriggered": 0}
Fri Sep 1 15:05:21 CEST 2017: /sensors/12/state: set flag to false...
Fri Sep 1 15:05:22 CEST 2017: /sensors/11/state: {"lastupdated": "2017-09-01T13:05:10", "flag": true}
Fri Sep 1 15:05:22 CEST 2017: /sensors/12/state: {"lastupdated": "2017-09-01T13:05:21", "flag": false}
Fri Sep 1 15:05:22 CEST 2017: /rules/10: {"lasttriggered": "2017-09-01T15:05:15", "timestriggered": 1}
Fri Sep 1 15:05:22 CEST 2017: /rules/11: {"lasttriggered": "none", "timestriggered": 0}
Fri Sep 1 15:05:26 CEST 2017: /sensors/11/state: set flag to false...
Fri Sep 1 15:05:27 CEST 2017: /sensors/11/state: {"lastupdated": "2017-09-01T13:05:26", "flag": false}
Fri Sep 1 15:05:28 CEST 2017: /sensors/12/state: {"lastupdated": "2017-09-01T13:05:21", "flag": false}
Fri Sep 1 15:05:28 CEST 2017: /rules/10: {"lasttriggered": "2017-09-01T15:05:15", "timestriggered": 1}
Fri Sep 1 15:05:28 CEST 2017: /rules/11: {"lasttriggered": "none", "timestriggered": 0}
Fri Sep 1 15:05:32 CEST 2017: /sensors/12/state: set flag to true...
Fri Sep 1 15:05:33 CEST 2017: /sensors/11/state: {"lastupdated": "2017-09-01T13:05:26", "flag": false}
Fri Sep 1 15:05:33 CEST 2017: /sensors/12/state: {"lastupdated": "2017-09-01T13:05:32", "flag": true}
Fri Sep 1 15:05:33 CEST 2017: /rules/10: {"lasttriggered": "2017-09-01T15:05:15", "timestriggered": 1}
Fri Sep 1 15:05:33 CEST 2017: /rules/11: {"lasttriggered": "2017-09-01T15:05:32", "timestriggered": 1}
Fri Sep 1 15:05:37 CEST 2017: /sensors/11/state: set flag to true...
Fri Sep 1 15:05:38 CEST 2017: /sensors/11/state: {"lastupdated": "2017-09-01T13:05:37", "flag": true}
Fri Sep 1 15:05:38 CEST 2017: /sensors/12/state: {"lastupdated": "2017-09-01T13:05:32", "flag": true}
Fri Sep 1 15:05:39 CEST 2017: /rules/10: {"lasttriggered": "2017-09-01T15:05:37", "timestriggered": 2}
Fri Sep 1 15:05:39 CEST 2017: /rules/11: {"lasttriggered": "2017-09-01T15:05:32", "timestriggered": 1}
Trigger if
- all conditions met
- anything changed, where anything also includes lastupdated via operator dx
I think it should be: Trigger if:
The dx check on lastupdated should really be is this is the last change to any of the conditions. deCONZ fails the classic Toggle Hue tap button test (don't feel bad - this is also a bug in HomeKit). The second rule shouldn't fire, as the lastupdated dx for 19 shouldn't be true anymore, since the last change was setting the 20 flag from the first rule:
Fri Sep 1 15:34:57 CEST 2017: Testing v2.04.73
Fri Sep 1 15:34:57 CEST 2017: /sensors/19: {
"config": {
"on": true,
"reachable": true
},
"etag": "4776b1d355065c6589d2fef90b901100",
"manufacturername": "homebridge-hue",
"modelid": "CLIPGenericFlag",
"name": "Test 1",
"state": {
"flag": false
},
"swversion": "1",
"type": "CLIPGenericFlag",
"uniqueid": "/sensors/1"
}
Fri Sep 1 15:34:57 CEST 2017: /sensors/20: {
"config": {
"on": true,
"reachable": true
},
"etag": "4776b1d355065c6589d2fef90b901100",
"manufacturername": "homebridge-hue",
"modelid": "CLIPGenericFlag",
"name": "Test 2",
"state": {
"flag": false
},
"swversion": "1",
"type": "CLIPGenericFlag",
"uniqueid": "/sensors/2"
}
Fri Sep 1 15:34:57 CEST 2017: /rules/18: {
"actions": [
{
"address": "/sensors/20/state",
"body": {
"flag": true
},
"method": "PUT"
},
{
"address": "/groups/1/scenes/1/recall",
"body": {},
"method": "PUT"
}
],
"conditions": [
{
"address": "/sensors/19/state/flag",
"operator": "eq",
"value": true
},
{
"address": "/sensors/19/state/lastupdated",
"operator": "dx"
},
{
"address": "/sensors/20/state/flag",
"operator": "eq",
"value": false
}
],
"created": "2017-09-01T13:34:57",
"etag": "4776b1d355065c6589d2fef90b901100",
"lasttriggered": "none",
"name": "Test Toggle On",
"owner": "philipshue",
"periodic": 0,
"status": "enabled",
"timestriggered": 0
}
Fri Sep 1 15:34:58 CEST 2017: /rules/19: {
"actions": [
{
"address": "/sensors/20/state",
"body": {
"flag": false
},
"method": "PUT"
},
{
"address": "/groups/1/scenes/2/recall",
"body": {},
"method": "PUT"
}
],
"conditions": [
{
"address": "/sensors/19/state/flag",
"operator": "eq",
"value": true
},
{
"address": "/sensors/19/state/lastupdated",
"operator": "dx"
},
{
"address": "/sensors/20/state/flag",
"operator": "eq",
"value": true
}
],
"created": "2017-09-01T13:34:57",
"etag": "4776b1d355065c6589d2fef90b901100",
"lasttriggered": "none",
"name": "Test Toggle Off",
"owner": "philipshue",
"periodic": 0,
"status": "enabled",
"timestriggered": 0
}
Fri Sep 1 15:34:58 CEST 2017: /sensors/19/state: {"lastupdated": , "flag": false}
Fri Sep 1 15:34:58 CEST 2017: /sensors/20/state: {"lastupdated": , "flag": false}
Fri Sep 1 15:34:58 CEST 2017: /rules/18: {"lasttriggered": "none", "timestriggered": 0}
Fri Sep 1 15:34:58 CEST 2017: /rules/19: {"lasttriggered": "none", "timestriggered": 0}
Fri Sep 1 15:35:02 CEST 2017: /sensors/19/state: set flag to false...
Fri Sep 1 15:35:03 CEST 2017: /sensors/19/state: {"lastupdated": "2017-09-01T13:35:02", "flag": false}
Fri Sep 1 15:35:03 CEST 2017: /sensors/20/state: {"lastupdated": , "flag": false}
Fri Sep 1 15:35:03 CEST 2017: /rules/18: {"lasttriggered": "none", "timestriggered": 0}
Fri Sep 1 15:35:03 CEST 2017: /rules/19: {"lasttriggered": "none", "timestriggered": 0}
Fri Sep 1 15:35:07 CEST 2017: /sensors/19/state: set flag to false...
Fri Sep 1 15:35:09 CEST 2017: /sensors/19/state: {"lastupdated": "2017-09-01T13:35:07", "flag": false}
Fri Sep 1 15:35:09 CEST 2017: /sensors/20/state: {"lastupdated": , "flag": false}
Fri Sep 1 15:35:09 CEST 2017: /rules/18: {"lasttriggered": "none", "timestriggered": 0}
Fri Sep 1 15:35:09 CEST 2017: /rules/19: {"lasttriggered": "none", "timestriggered": 0}
Fri Sep 1 15:35:13 CEST 2017: /sensors/19/state: set flag to true...
Fri Sep 1 15:35:14 CEST 2017: /sensors/19/state: {"lastupdated": "2017-09-01T13:35:13", "flag": true}
Fri Sep 1 15:35:14 CEST 2017: /sensors/20/state: {"lastupdated": "2017-09-01T13:35:13", "flag": false}
Fri Sep 1 15:35:14 CEST 2017: /rules/18: {"lasttriggered": "2017-09-01T15:35:13", "timestriggered": 1}
Fri Sep 1 15:35:14 CEST 2017: /rules/19: {"lasttriggered": "2017-09-01T15:35:13", "timestriggered": 1}
Fri Sep 1 15:35:18 CEST 2017: /sensors/19/state: set flag to true...
Fri Sep 1 15:35:20 CEST 2017: /sensors/19/state: {"lastupdated": "2017-09-01T13:35:18", "flag": true}
Fri Sep 1 15:35:20 CEST 2017: /sensors/20/state: {"lastupdated": "2017-09-01T13:35:13", "flag": false}
Fri Sep 1 15:35:20 CEST 2017: /rules/18: {"lasttriggered": "2017-09-01T15:35:13", "timestriggered": 1}
Fri Sep 1 15:35:20 CEST 2017: /rules/19: {"lasttriggered": "2017-09-01T15:35:13", "timestriggered": 1}
Fri Sep 1 15:35:24 CEST 2017: /sensors/19/state: set flag to false...
Fri Sep 1 15:35:25 CEST 2017: /sensors/19/state: {"lastupdated": "2017-09-01T13:35:24", "flag": false}
Fri Sep 1 15:35:25 CEST 2017: /sensors/20/state: {"lastupdated": "2017-09-01T13:35:20", "flag": false}
Fri Sep 1 15:35:25 CEST 2017: /rules/18: {"lasttriggered": "2017-09-01T15:35:20", "timestriggered": 2}
Fri Sep 1 15:35:25 CEST 2017: /rules/19: {"lasttriggered": "2017-09-01T15:35:20", "timestriggered": 2}
Fri Sep 1 15:35:29 CEST 2017: /sensors/19/state: set flag to false...
Fri Sep 1 15:35:30 CEST 2017: /sensors/19/state: {"lastupdated": "2017-09-01T13:35:29", "flag": false}
Fri Sep 1 15:35:31 CEST 2017: /sensors/20/state: {"lastupdated": "2017-09-01T13:35:20", "flag": false}
Fri Sep 1 15:35:31 CEST 2017: /rules/18: {"lasttriggered": "2017-09-01T15:35:20", "timestriggered": 2}
Fri Sep 1 15:35:31 CEST 2017: /rules/19: {"lasttriggered": "2017-09-01T15:35:20", "timestriggered": 2}
Fri Sep 1 15:35:35 CEST 2017: /sensors/19/state: set flag to true...
Fri Sep 1 15:35:36 CEST 2017: /sensors/19/state: {"lastupdated": "2017-09-01T13:35:35", "flag": true}
Fri Sep 1 15:35:36 CEST 2017: /sensors/20/state: {"lastupdated": "2017-09-01T13:35:35", "flag": false}
Fri Sep 1 15:35:36 CEST 2017: /rules/18: {"lasttriggered": "2017-09-01T15:35:35", "timestriggered": 3}
Fri Sep 1 15:35:36 CEST 2017: /rules/19: {"lasttriggered": "2017-09-01T15:35:35", "timestriggered": 3}
Fri Sep 1 15:35:40 CEST 2017: /sensors/19/state: set flag to true...
Fri Sep 1 15:35:41 CEST 2017: /sensors/19/state: {"lastupdated": "2017-09-01T13:35:40", "flag": true}
Fri Sep 1 15:35:41 CEST 2017: /sensors/20/state: {"lastupdated": "2017-09-01T13:35:41", "flag": false}
Fri Sep 1 15:35:42 CEST 2017: /rules/18: {"lasttriggered": "2017-09-01T15:35:41", "timestriggered": 4}
Fri Sep 1 15:35:42 CEST 2017: /rules/19: {"lasttriggered": "2017-09-01T15:35:41", "timestriggered": 4}
Time for some Friday rule hacking :)
Can you confirm my assumptions when the rule should trigger?
Note In the following examples I imply that rule last triggered has initial time stamp of deCONZ startup time when the rule was not triggered before.
/rules/9: {
"actions": [
{
"address": "/groups/1/scenes/2/recall",
"body": {},
"method": "PUT"
}
],
"conditions": [
{
"address": "/sensors/9/state/flag",
"operator": "eq",
"value": false
},
{
"address": "/sensors/9/state/lastupdated",
"operator": "dx"
},
{
"address": "/sensors/10/state/flag",
"operator": "eq",
"value": true
},
{
"address": "/sensors/10/state/lastupdated",
"operator": "dx"
}
]
}
dx lastupdated must have time stamp after rule last triggeredeq must be met, which could have happened before rule was last triggeredIn comparison artificial example (1):
"conditions": [
{
"address": "/sensors/9/state/flag",
"operator": "eq",
"value": false
},
{
"address": "/sensors/10/state/flag",
"operator": "eq",
"value": true
},
{
"address": "/sensors/10/state/lastupdated",
"operator": "dx"
}
]
dx lastupdated must have time stamp newer then rule last triggered time stampeq must be met, which could have happened before rule was triggered the last timeIn comparison artificial example (2):
"conditions": [
{
"address": "/sensors/9/state/flag",
"operator": "eq",
"value": false
},
{
"address": "/sensors/10/state/flag",
"operator": "eq",
"value": true
},
{
"address": "/sensors/11/state/flag",
"operator": "eq",
"value": true
}
]
eq must be metTime for some Friday rule hacking :)
YES, let's do this!
Can you confirm my assumptions when the rule should trigger?
I'm afraid I cannot. Sorry, I'm afraid you need to "unthink" the current rules triggering logic in deCONZ and take a fresh look. Your first example is, in fact, artificial; the other two are not - I've been using both extensively.
The Hue documentation is very vague, so my understanding is based on reverse-engineering and lots of trial and error.
The most confusing part (if you will: paradigm shift) is that each element (object) in the conditions array serves one of two distinct purposes:
The rule actions are only executed when a trigger happens and all conditions hold. No need to consider lasttriggered. When evaluating a rule, only one element serves as trigger; the other elements serve as conditions.
A trigger is always the result of a change, causing the element to _become_ true. What change, depends on the operator:
dx: when lastupdated changed just now;ddx: when localtime reached lastupdated+ value;in: when localtime reached the first time from value;not in: when localtime reached the last time from value;eq: when the attribute changed from another value to value;lt: when the attribute changed from a value >= value to a value < value;gt: when the attribute changed from a value <= value to a value > value;stable: never;not stable: never.When a trigger occurs, the conditions (i.e. the _other_ elements in the conditions array) are evaluated. Again, the logic depends on the operator:
dx: always evaluates to false;ddx: always evaluates to false;in: evaluates to true iff localtime is within the time range in value;not in: evaluates to true iff localtime is outside the range in value;eq: evaluaties to true iff attribute = value;lt: evaluates to true iff attribute < value;gt: evaluates to true iff attribute > value;stable: evaluates to true iff localtime >= lastupdated + value;not stable: evaluates to true iff localtime < lastudated + value.So dx and ddx only ever serve as trigger - consequently, you should only specify one of these operators in a rule. Also, when a rule contains one of these operators, you don't need to consider any triggers from other elements, because the dx or ddx element evaluates to false anyways. stable and not stable only serve as conditions - a rule with only elements with these operators is never even evaluated. The other operators might serve as trigger or as condition, but only one at a time.
Note the subtle differences: a rule with only an lt element executes when the attribute value _becomes_ less then value (the becoming less is the trigger). A rule with both a lt and a dx element executes when the attribute is less than value after the change, regardless of the previous value (lastupdated is the trigger). For example: a rule with status lt 2 executes when setting status from 2 to 1, but not when setting it from 0 to 1 or 1 to 0. A rule with status lt 2, lastupdated dx executes when setting status from 2 to 1, from 0 to 1, from 1 to 0, and even from 1 to 1. Likewise, a rule with dark eq true executes when lightlevel changes from above tholddark to below tholddark (becoming dark is the trigger), but not when it changes from one value below tholddark to another value below tholddark.
The conditions of _all_ rules linked to a trigger are to be evaluated before any action is executed. In particular the change of lastupdated that caused a dx or ddx trigger should evaluate to false for the changes caused by rule actions (see the Hue tap toggle example).
Hope this helps - it's not easy to explain.
Thanks a lot — this is indeed a very different view from what I thought how it works. Your description is much better than the one in the hue documentation. I slowly wrap my mind around the logic and understand now the trigger and condition roles.
Therefore the actual rule system should be refactored to take advantage of the event system. The event belonging to a resource item will then be evaluated for each rule thereby the trigger or condition role is applied according to your above description.
The conditions of all rules linked to a trigger are to be evaluated before any action is executed.
Not sure if I get this correctly, isn't each rule master on it's own? When evaluating each rule first without executing actions, the rules can't affect each other. Therefore it should be the same as executing the actions after a rule is evaluated and and the non-trigger conditions resolve to true?
Great analysis!
dx: whenlastupdatedchanged just now;
...
eq: when the attribute changed from another value to value;
Some additional clarification:
dx: when the value of the attribute specified by address changed just now;
Possible use cases:
{
"address": "/sensors/8/state/open",
"operator": "dx"
}
or
{
"address": "/lights/1/state/on",
"operator": "dx"
}
or
{
"address": "/groups/0/state/any_on",
"operator": "dx"
}
Last two won't be possible yet, because lights and groups aren't part of the resource system (#59). But it would still be nice to have.
Therefore the actual rule system should be refactored to take advantage of the event system.
If developing an api that is not compatible with the Hue api makes it easier, that would be fine by me. For example separation of triggers: [], conditions: [] and actions: [] and support for choosing and and or for the evaluations of specified conditions.
The conditions of all rules linked to a trigger are to be evaluated before any action is executed.
isn't each rule master on it's own?
Exactly.
When evaluating each rule first without executing actions, the rules can't affect each other.
That's what you want. Consider the set of rules to implement a toggle on a Hue tap, using a CLIP flag to remember whether the lights are on (this example is actually from the Hue Application Design Guidance):
If you would execute the actions of the first rule, before evaluating the second rule, both rules would execute, since the condition of the second rule has now been met by the action of the first rule.
Instead, the button pressed trigger should cause both rules to be evaluated while the flag is still false (causing only the first rule to execute). Then the action in the first rule becomes a _new_ trigger (flag set to true), which (theoretically) causes the second rule to be evaluated _for a second time_, but this time the flag is the trigger, and button pressed the condition (which evaluates to false, which we knew up front, since it's a dx operator, so we didn't need to trigger the rule for the second time in the first place - hence "theoretically").
Of course, there's many valid examples of chaining rules (motion sensor sets flag -> flag turns on lights), but here the second rule has a different trigger than the first rule.
Therefore it should be the same as executing the actions after a rule is evaluated and and the non-trigger conditions resolve to true?
Sorry, I'm not sure I follow your line of thinking here. I hope the example makes it clear(er).
Some additional clarification:
dx: when the value of the attribute specified by address changed just now;
I think the Hue bridge only allows dx on lastupdated? At least that's all I've ever seen and used.
Your first use case is equivalent to:
{
"address": "/sensors/8/state/lastupdated",
"operator": "dx"
}
for the other two, you'd need a state.lastupdated on lights and groups. The Hue bridge does allow the use of a light's state.on, and a group's state.any_on and state.all_on in conditions, but doesn't keep a lastupdated for these. I think introducing a light state.lastupdated is opening a can of worms and a group state.lastupdated would be even worse. Cf. the issues around polling lights and state.reachable.
If developing an api that is not compatible with the Hue api makes it easier
I love the extensions the deCONZ offers on top of the Hue API (like web sockets), but I would like apps (and scripts and homebridge plugins ;-) using the Hue api to work on deCONZ.
support for choosing
andandorfor the evaluations of specified conditions.
Love that. Also some more operators like !=, >= and <= (ne, ge, and le) and an in for a list of values:
{
"address": "/sensors/10/state/buttonevent",
"operator": "in",
"value": [ "2003", "3003" ]
}
to set bri_inc to 0 when releasing _DimUp_ or _DimDown_. Yes, this is another hint (#84 ;-).
Your first use case is equivalent to:
{
"address": "/sensors/8/state/lastupdated",
"operator": "dx"
}
Is it? This is may be not the best example, but if I PUT state open twice to a CLIPOpenClose sensor the lastupdated changes while state/open doesn't.
I think the Hue bridge only allows dx on lastupdated? At least that's all I've ever seen and used.
Hue allows dx on other attributes. A rule I used for 'arriving home after sunset' with a CLIPPresence sensor. It is executed when presence becomes true:
conditions": [
{
"address": "/sensors/1/state/daylight",
"operator": "eq",
"value": "false"
},
{
"address": "/sensors/8/state/presence",
"operator": "dx"
},
{
"address": "/sensors/8/state/presence",
"operator": "eq",
"value": "true"
},
{
"address": "/groups/1/state/any_on",
"operator": "eq",
"value": "false"
}
]
I love the extensions the deCONZ offers on top of the Hue API (like web sockets), but I would like apps (and scripts and homebridge plugins ;-) using the Hue api to work on deCONZ.
Web sockets are my main reason for switching to deCONZ 馃憤. I understand your point of view, however the Scene API is also quite different compared to Hue api. I'm also a user of your homebridge plugin. It is not my intention to give you extra work with this proposal. Although, recalling scenes using a HomeKit switch in homebridge-hue would be nice ;) Would result in one API call, instead of one for every light in a HomeKit scene.
Hue allows
dxon other attributes.
Cool! Shows you're never too old to learn ;-). Thanks, @snozzlebert. I think we really should start a Wiki about this, but in the meantime, I'll update the documentation in my head...
Is it? This is may be not the best example, but if I PUT state open twice to a CLIPOpenClose sensor the lastupdated changes while state/open doesn't.
You're right, of course.
So effectively, dx forces the attribute from address to become the only (!) trigger for the rule. By applying it to lastupdated any _update_ (incl. setting from true to true) to the resource state acts as trigger (because any change causes lastupdated to be changed); by applying it to another attribute, only a _change_ to that attribute acts as trigger. By leaving dx out, only a change that causes the element to _change_ to true acts as trigger. So there's actually five different patterns:
dx on lastupdated - trigger when lastupdated has changed, execute;dx on lastupdated and other operation on other attribute - trigger when lastupdated has changed, execute when other operation holds;dx on attribute - trigger when attribute has changed, execute;dx on attribute and other operation on attribute - trigger when attribute has changed, execute when other operation holds;dx) - trigger when attribute changes, from an old value where operation didn't hold to a new value where operation does hold. That's probably implemented like: trigger when attribute changes, execute when operation doesn't hold for old value and does hold for new value, but this is a different evaluation from when this operation is used as a condition.Typically, you'll want want (1) and/or (2) for switches (to capture the same button event twice in a row); you'll want (3) and (4) for other sensors (only react when the sensor actually reports a new value, like: motion sensor (or door sensor) to update the room master switch); and you'll want (5) for automations based on multiple inputs (like: room master switch, lightlevel, time of day).
Again, very subtle differences. Consider (1):
"conditions": [
{
"address": "/sensors/10/state/status",
"operator": "gt",
"value": "0"
},
{
"address": "/sensors/10/state/lastupdated",
"operator": dx"
}
]
which executes when setting state.status from 0 to 1, from 1 to 1, or from 2 to 1.
Whereas (4):
"conditions": [
{
"address": "/sensors/10/state/status",
"operator": "gt",
"value": "0"
},
{
"address": "/sensors/10/state/status",
"operator": dx"
}
]
executes when setting state.status from 0 to 1 or from 2 to 1, but not from 1 to 1.
And (5):
"conditions": [
{
"address": "/sensors/10/state/status",
"operator": "gt",
"value": "0"
}
]
executes only when setting state.status from 0 to 1, but not from 2 to 1 nor from 1 to 1.
the Scene API is also quite different compared to Hue api
Yes, see #29. I think we'll fix this eventually (or at least allow the Hue syntax in addition to the current deCONZ syntax), but the rules have my priority. And then a whole lot of other issues...
I'm also a user of your homebridge plugin. It is not my intention to give you extra work with this proposal.
That's appreciated!
Although, recalling scenes using a HomeKit switch in homebridge-hue would be nice ;)
Better discuss this in https://github.com/ebaauw/homebridge-hue/issues/158
Great examples! The Hue Tap toggle makes it more clear to me.
When the rules are evaluated after event fired, at the beginning a snapshot of current state, of only related resources will be made. Evaluation will be made only with this snapshot. This (should) support rules like the Hue Tap toggle.
To properly support operators lt, gtand similar, the resource item events will extended with previous value before set/change.
Therefore the actual rule system should be refactored to take advantage of the event system.
Shows the confusion: I though you (@manup) already had done that in the fast rule check. But yes, I think it should. However, I don't think the event system is involved in updating /config/localtime. It would need to be for the ddx and in operators.
I have to correct myself: a snapshot shouldn't be needed since as you have stated before it might be as simple as:
I don't think the event system is involved in updating /config/localtime. It would need to be for the ddx and in operators.
Not firing an event yet. The config/localtime is updated in the idle handler every second, so firing a event is therefore easy.
As an optimisation each resource has a reference to rules which have conditions referencing them.
As an optimisation each resource has a reference to rules which have conditions referencing them.
As a further optimisation, only resources which could potentially act as trigger need to be registered. So if a rule contains a dx operator, only that resource needs a reference to the rule. If a rule contains a ddx operator, only the reference from config.localtime is needed. If a rules contains neither dx nor ddx all resources need a reference (except those only used in stable and/or not stable).
As a further optimisation, only resources which could potentially act as trigger need to be registered. So if a rule contains a dx operator, only that resource needs a reference to the rule. If a rule contains a ddx operator, only the reference from config.localtime is needed. If a rules contains neither dx nor ddx all resources need a reference (except those only used in stable and/or not stable).
Agree, writing the indexer doing exactly this now :)
I'm currently testing c91c3ca - will post results there.
I can confirm that rule triggering has improved tremendously in my small setup in 2.04.75 compared to 2.04.73. Rules are closer to executing in a way that I'd expect them to.
Running production now on 2.04.75 - 195 rules. I haven't come across any issues yet, apart from the ones I mentioned in c91c3ca:
lastupdated, see log below. This is caused by the additional enqueueEvent(Event(RSensors, RStateLastUpdated, id)); after each enqueueEvent(e);.Wed Sep 06 2017 21:00:01: /sensors/273/state: {"lastupdated":"2017-09-06T19:00:01","lightlevel":0}
Wed Sep 06 2017 21:00:01: /sensors/273/state: {"lastupdated":"2017-09-06T19:00:01"}
Wed Sep 06 2017 21:00:13: /sensors/244/state: {"lastupdated":"2017-09-06T19:00:13","temperature":2066}
Wed Sep 06 2017 21:00:13: /sensors/244/state: {"lastupdated":"2017-09-06T19:00:13"}
Wed Sep 06 2017 21:00:15: /sensors/314/state: {"lastupdated":"2017-09-06T19:00:15","temperature":1974}
Wed Sep 06 2017 21:00:15: /sensors/314/state: {"lastupdated":"2017-09-06T19:00:15"}
Wed Sep 06 2017 21:00:16: /sensors/272/state: {"lastupdated":"2017-09-06T19:00:16","presence":false}
Wed Sep 06 2017 21:00:16: /sensors/272/state: {"lastupdated":"2017-09-06T19:00:16"}
Wed Sep 06 2017 21:00:19: /sensors/323/state: {"lastupdated":"2017-09-06T19:00:19","lightlevel":0}
Wed Sep 06 2017 21:00:19: /sensors/323/state: {"lastupdated":"2017-09-06T19:00:19"}
Wed Sep 06 2017 21:00:23: /sensors/264/state: {"lastupdated":"2017-09-06T19:00:23","temperature":2306}
Wed Sep 06 2017 21:00:23: /sensors/264/state: {"lastupdated":"2017-09-06T19:00:23"}
state.flag from false to true. Presumably once because of the first enqueueEvent(), once because of the second. When setting state.flag from true to true, only the second web socket event is issued and the rule executes only once."conditions": [
{
"address": "/sensors/1/state/flag",
"operator": "eq",
"value": "true"
},
{
"address": "/sensors/1/state/lastupdated",
"operator": "dx"
}
]
The events are fine here, the problem is that the dx is treated as normal condition when change to state/flag is the trigger.
Working on it should be fixed soon.
When updating a rule's conditions, the new conditions don't seem to take effect until deCONZ is restarted.
As far as I can tell, rules now execute correctly in v2.04.76.
Tip: After startup, a rule with a condition on config.localtime will execute, if the current time is within the range. This can be used to recognise the startup and turn off all lights, in response to power being restored after a power outage. On the Hue bridge I used the setting of the Daylight sensor for this, but deCONZ doens't yet support this builtin sensor.
Most helpful comment
I agree and suggest to adapt the behaviour of the fire then last condition becomes true. The sooner the better to not cause side effects when implementing it too late.