In short: How can I tell apart, if a Item changed due to a user interaction or from a rule. I need to tell those two apart.
I cant find the right search term - sorry for that, my issue must have been on the table before.
I do have a switch with three states “holiday”, “auto” and “manual”.
In auto, the temperature of heaters is changed on a time basis using sendCommand. But when someone changes the temperature manually via e.g. the app, the switch should to go manual and the time based triggers shall be inactive.
rule "Heizung geändert, gehe zu manual mode" when Item HeizungArbeitszimmer_SetpointTemperature changed or Item HeizungSchlafzimmer_SetpointTemperature changed or Item HeizungWohnzimmer_SetpointTemperature changed or Item$ then sendCommand(behaviour,3) // goes to manual end
The issue is, that the above rule is also triggered, when the auto mode executes a sendcommand.
You can’t. You also cannot tell if it was binding that changed an Item state.
What you can do is segregate your Items.
You might have, say, a dummy temperature Item in your UI.
When the user commands that, you know exactly who has done it becase you have provided no other way for that to happen.
So you can have a rule that does whatever it is you want with that - like for instance, copying the command to a real device.
And probably the inverse - a rule that copies incoming real device updates to the dummy, for display.
Dear all,
many thanks for your help! Excellent design pattern post - the image within is just perfect. I have to read all of the design pattern posts, that will help for sure. On this topic I was hoping for a more out of the box solution, but I’ll go for #3.
Almost got it working with #3, but as I want to control a heater, I don’t use Switch items, but Number:Temperature. From the code it looked to me, that I only need to adapt the item definitions to make it work with a number:temperature. The heater_device gets the command, but never “gets it done”. I double checked, and I think all variables are numbers, but I guess the error lies somewhere in a type conversion.
Rule
rule "Heater control received command"
when
Member of Heizung_SetpointTemperature received command
then
// Get access to all the relevant Items
val lightName = triggeringItem.name.split("_").get(0) + "_" + triggeringItem.name.split("_").get(1) // because I added additional _ in the variable name, not effcient, but work$
val source = triggeringItem.name.split("_").get(2)
logInfo("heater",lightName)
logInfo("heater",source)
val proxy = Heizung_SetpointTemperature.members.findFirst[ l | l.name == lightName + "_Proxy" ]
val device = Heizung_SetpointTemperature.members.findFirst[ l | l.name == lightName + "_Device" ]
val ui = Heizung_SetpointTemperature.members.findFirst[ l | l.name == lightName + "_UI" ]
val rules = Heizung_SetpointTemperature.members.findFirst[ l | l.name == lightName + "_Rules" ]
// The Proxy Item should never receive a command
if(source == "Proxy") {
logWarn("light", "Received command on " + triggeringItem.name + ", this should not occur, ignoring.")
return;
}
// When a command comes in from any source not the Device, a command gets sent to the Device
// This let's us skip this command so we don't end up in an infinite loop.
if(source == "Device") {
logInfo("light","sleeping")
Thread::sleep(150) // experiment, may not be needed, may need to be longer, give the Item registry time to update the proxy
if(receivedCommand == proxy.state) {
logInfo("light","returning, because rec and proxy are equal")
return;
}
logInfo("light","continuing")
}
// Detect whether the light was triggered manually or automatically and do what needs to be done
if(source == "Device" || source == "UI") {
logInfo("light","manual event")
}
else {
}
// Forward the new state to those Items that are not already in the new state. Use sendCommand
// for the device so the light actually turns on/off.
if(proxy.state != receivedCommand) proxy.postUpdate(receivedCommand)
if(ui.state != receivedCommand) ui.postUpdate(receivedCommand)
if(rules.state != receivedCommand) rules.postUpdate(receivedCommand)
if(device.state != receivedCommand) device.sendCommand(receivedCommand)
logInfo("light","---")
end