Struggling with old and new state variables

I am trying to write a function to apply some logic to when someone comes or leaves the home. I am using a zone as the controlling entity that reports the number of people in the zone as the state.

I want to have 4 different outcomes:

  1. Any number of people come home to an empty house.
  2. Any number of people come home to a house that already has any number of people in it.
  3. Any number of people leave home, but there are still people left home.
  4. Everyone leaves home.

Here is what I have in my function:

var newState = msg.data.new_state;
var oldState = msg.data.old_state;

if (newState > 0 && oldState == 0){
    msg.test = "Someone came home to an empty house";
    msg.o = oldState;
    msg.n = newState;
}
else if (newState > oldState && oldState != 0){
    msg.test = "Someone came home to an occupied house";
    msg.o = oldState;
    msg.n = newState;
}
else if (newState < oldState && newState != 0){
    msg.test = "Someone left and the house is still occupied";
    msg.o = oldState;
    msg.n = newState;
}
else if (newState == 0 && oldState != 0){
    msg.test = "House is empty";
    msg.o = oldState;
    msg.n = newState;
}
else{
    msg.test = "Something else happened";
    msg.o = oldState;
    msg.n = newState;
}
return msg;

I keep getting undefined variables in my debug output, which I can only assume means my variables are not correct, but I cannot find any documentation to indicate what they should be.

I am open to other methods to achieve the same functionality. I tired to use the trigger state with conditions, but I couldn’t get it to function as I wanted. I couldn’t apply the logic to ensure that the number was either bigger or less than the previous state (to indicate a person coming vs. going). The function seemed to be the easiest method if I could get the new/old state variables correct.

Here is the flow with the function in it:

[{"id":"e92baf13456eba5c","type":"debug","z":"fb29e58f011f5e34","name":"debug 59","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":620,"y":1300,"wires":[]},{"id":"2783fb182ec7f455","type":"api-current-state","z":"fb29e58f011f5e34","name":"# People Home","server":"58bff01.29ea91","version":3,"outputs":1,"halt_if":"","halt_if_type":"num","halt_if_compare":"is","entity_id":"zone.home","state_type":"num","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":280,"y":1300,"wires":[["d4adf10201329fed"]]},{"id":"8f1b60fdd6d23db8","type":"inject","z":"fb29e58f011f5e34","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":100,"y":1300,"wires":[["2783fb182ec7f455"]]},{"id":"d4adf10201329fed","type":"function","z":"fb29e58f011f5e34","name":"function 1","func":"var newState = msg.data.new_state;\nvar oldState = msg.data.old_state;\n\nif (newState > 0 && oldState == 0){\n    msg.test = \"Someone came home to an empty house\";\n    msg.o = oldState;\n    msg.n = newState;\n}\nelse if (newState > oldState && oldState != 0){\n    msg.test = \"Someone came home to an occupied house\";\n    msg.o = oldState;\n    msg.n = newState;\n}\nelse if (newState < oldState && newState != 0){\n    msg.test = \"Someone left and the house is still occupied\";\n    msg.o = oldState;\n    msg.n = newState;\n}\nelse if (newState == 0 && oldState != 0){\n    msg.test = \"House is empty\";\n    msg.o = oldState;\n    msg.n = newState;\n}\nelse{\n    msg.test = \"Something else happened\";\n    msg.o = oldState;\n    msg.n = newState;\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":460,"y":1300,"wires":[["e92baf13456eba5c"]]},{"id":"58bff01.29ea91","type":"server","name":"Home Assistant","addon":true}]

Figured it out.

Needed to use a trigger state node in order to get the current and previous states as part of the msg.data.

Function:

var newState = msg.payload;
var oldState = msg.data.event.old_state.state;

See the new flow:

[{"id":"e92baf13456eba5c","type":"debug","z":"fb29e58f011f5e34","name":"debug 59","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":500,"y":1460,"wires":[]},{"id":"d4adf10201329fed","type":"function","z":"fb29e58f011f5e34","name":"function 1","func":"var newState = msg.payload;\nvar oldState = msg.data.event.old_state.state;\n\nif (newState > 0 && oldState == 0){\n    msg.test = \"Someone came home to an empty house\";\n    msg.o = oldState;\n    msg.n = newState;\n}\nelse if (newState > oldState && oldState != 0){\n    msg.test = \"Someone came home to an occupied house\";\n    msg.o = oldState;\n    msg.n = newState;\n}\nelse if (newState < oldState && newState != 0){\n    msg.test = \"Someone left and the house is still occupied\";\n    msg.o = oldState;\n    msg.n = newState;\n}\nelse if (newState == 0 && oldState != 0){\n    msg.test = \"House is empty\";\n    msg.o = oldState;\n    msg.n = newState;\n}\nelse{\n    msg.test = \"Something else happened\";\n    msg.o = oldState;\n    msg.n = newState;\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":340,"y":1460,"wires":[["e92baf13456eba5c"]]},{"id":"9a57246a74336942","type":"trigger-state","z":"fb29e58f011f5e34","name":"","server":"58bff01.29ea91","version":2,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityid":"zone.home","entityidfiltertype":"exact","debugenabled":false,"constraints":[],"inputs":0,"outputs":2,"customoutputs":[],"outputinitially":false,"state_type":"num","enableInput":false,"x":130,"y":1460,"wires":[["d4adf10201329fed"],[]]},{"id":"58bff01.29ea91","type":"server","name":"Home Assistant","addon":true}]

Little confusing, but figured it out and feel like a bozo now. Hopefully this helps someone else.

1 Like

You might be better off using the “events: state” node, which also passes old and new states. You can tell it to ignore changes to/from unknown & unavailable. As it stands, these will be triggered with your current flow, and your code assumes they can be converted nicely to numbers so I’m not sure what will happen.

You’re right. I changed it over to an events:state node. I just used a switch statement on the output of the function to route it to each of the 4 use cases, it works, but probably not the most elegant.

Realistically, I only really want the “someone came home to an already occupied house” at the moment.
I am trying to figure out how to do it without the function, but I am struggling to get it to work.

It should be an easy JSONata comparison, but it’s not working correctly.

($entity().data.old_state.state < $entity().data.new_state.state) and ($entity().data.old_state.state != 0)

It certainly does help.
I did figure out from debug nodes that the “current_state node” doesn’t provide old_state informaton. (as the “events node” does)

But then these things are kinda not intuitive, and the syntax is confusing.

So, thanks for taking the time to report your solution