Virtual Thermostat

I had a pretty good setup on Hubitat with the Advanced vThermostat from nclark where all of my motion and contact sensors served as temperature sensors for each room, and the various fans or space heaters served as “HVAC” since we have no central or split HVAC. But since I switched off of using HE as a Z* hub, obviously all of my sensors and plugs can no longer communicate easily with that software.

Has anyone been able to find anything like that either in NR directly or in Home Assistant? I have been unsuccessful thus far. The goal is to have a virtual thermostat per room with the temperature sensors configurable, and the heating and cooling endpoints configurable, bonus points for an eco-mode/occupancy-checks to lower/raise the temp setpoints based on if the room actually has people in it.

From a safety perspective, fans I think are whatever, even portable or window AC’s are whatever. The real risk is with heaters, and I think how nclark handled that was if a sensor did not check in at least once every 65 minutes, it would go into a panic mode and turn all endpoints off. So something like that would be great too, but I have a feeling I would have to program that manually.

Thanks for anyone that can help.

Side Note: Is this the kind of thing that would be available OOTB from CORE? This along with an easy way to share devices to alexa have been my main pain points since moving off of HE.

Have you looked into using AI? Maybe ChatGPT 4? It’s a paid version, but it might be able to generate something that works for you.

I have not, though I am not sure if you are being serious or not haha :rofl:

Below I attached my code for a subflow I call Heater Control. It has a deadman, variable setpoint and hysteresis capability.

If you input msg.setpoint it changes the setpoint, else it expects msg.payload to be a temperature.

When you double click the node you can manually set the setpoint/hysteresis/deadman wait.

It outputs a true or false if the heater should be on.

Here is a usage where I AND the output of the heater control with if I have been in the room in the last 30 minutes and an enable button I have at my desk.

Heater Node

[{“id”:“cd72f043d3c30165”,“type”:“subflow”,“name”:“Heater Control”,“info”:“”,“category”:“”,“in”:[{“x”:60,“y”:380,“wires”:[{“id”:“36ea054028726ff2”}]}],“out”:[{“x”:1100,“y”:480,“wires”:[{“id”:“aac0d08884b39eac”,“port”:0}]}],“env”:[{“name”:“Deadman”,“type”:“num”,“value”:“1800”,“ui”:{“type”:“input”,“opts”:{“types”:[“num”]}}},{“name”:“Setpoint”,“type”:“num”,“value”:“72”,“ui”:{“type”:“input”,“opts”:{“types”:[“num”]}}},{“name”:“Hysterisis”,“type”:“num”,“value”:“.25”,“ui”:{“type”:“input”,“opts”:{“types”:[“num”]}}}],“meta”:{},“color”:“#DDAA99”,“status”:{“x”:1240,“y”:700,“wires”:[{“id”:“ed0f6eed115d649f”,“port”:0},{“id”:“626ca8c4422166d3”,“port”:0},{“id”:“15f6134e5e2d061b”,“port”:0}]}},{“id”:“c38f605f469d288a”,“type”:“junction”,“z”:“cd72f043d3c30165”,“x”:640,“y”:420,“wires”:[[“128f2cc777c897e4”]]},{“id”:“aac0d08884b39eac”,“type”:“junction”,“z”:“cd72f043d3c30165”,“x”:1040,“y”:540,“wires”:[[“19f4a5df9510ac19”]]},{“id”:“281f57c8fa3f0f59”,“type”:“change”,“z”:“cd72f043d3c30165”,“name”:“set temperature vars”,“rules”:[{“t”:“set”,“p”:“temperature”,“pt”:“flow”,“to”:“payload”,“tot”:“msg”},{“t”:“set”,“p”:“deadman”,“pt”:“flow”,“to”:“true”,“tot”:“bool”}],“action”:“”,“property”:“”,“from”:“”,“to”:“”,“reg”:false,“x”:460,“y”:320,“wires”:[[“7d7467d8719355cd”,“c38f605f469d288a”]]},{“id”:“7d7467d8719355cd”,“type”:“stoptimer-varidelay”,“z”:“cd72f043d3c30165”,“duration”:“Deadman”,“durationType”:“env”,“units”:“Second”,“payloadtype”:“num”,“payloadval”:“0”,“name”:“”,“reporting”:“none”,“persist”:false,“ignoretimerpass”:false,“x”:790,“y”:380,“wires”:[[“c2a0cb4460ae7fc5”],[],[]]},{“id”:“c2a0cb4460ae7fc5”,“type”:“change”,“z”:“cd72f043d3c30165”,“name”:“set deadman”,“rules”:[{“t”:“set”,“p”:“deadman”,“pt”:“flow”,“to”:“false”,“tot”:“bool”}],“action”:“”,“property”:“”,“from”:“”,“to”:“”,“reg”:false,“x”:1030,“y”:360,“wires”:[[“9e33747691b16133”]]},{“id”:“f8cd1f1205490235”,“type”:“change”,“z”:“cd72f043d3c30165”,“name”:“Get Temp Diff”,“rules”:[{“t”:“delete”,“p”:“payload”,“pt”:“msg”},{“t”:“set”,“p”:“setpoint”,“pt”:“msg”,“to”:“Setpoint”,“tot”:“flow”},{“t”:“set”,“p”:“currentTemp”,“pt”:“msg”,“to”:“temperature”,“tot”:“flow”},{“t”:“set”,“p”:“payload”,“pt”:“msg”,“to”:“msg.currentTemp - msg.setpoint”,“tot”:“jsonata”}],“action”:“”,“property”:“”,“from”:“”,“to”:“”,“reg”:false,“x”:420,“y”:500,“wires”:[[“d137275b06425345”]]},{“id”:“128f2cc777c897e4”,“type”:“switch”,“z”:“cd72f043d3c30165”,“name”:“Heating”,“property”:“heating”,“propertyType”:“flow”,“rules”:[{“t”:“true”},{“t”:“false”}],“checkall”:“true”,“repair”:false,“outputs”:2,“x”:220,“y”:520,“wires”:[[“f8cd1f1205490235”],[“df3a3f28f4a0994f”]]},{“id”:“d137275b06425345”,“type”:“switch”,“z”:“cd72f043d3c30165”,“name”:“”,“property”:“payload”,“propertyType”:“msg”,“rules”:[{“t”:“gte”,“v”:“Hysterisis”,“vt”:“env”},{“t”:“lt”,“v”:“Hysterisis”,“vt”:“env”}],“checkall”:“true”,“repair”:false,“outputs”:2,“x”:590,“y”:500,“wires”:[[“9e33747691b16133”],[]]},{“id”:“9e33747691b16133”,“type”:“change”,“z”:“cd72f043d3c30165”,“name”:“Turn Off Heater”,“rules”:[{“t”:“delete”,“p”:“payload”,“pt”:“msg”},{“t”:“set”,“p”:“payload”,“pt”:“msg”,“to”:“false”,“tot”:“bool”},{“t”:“set”,“p”:“heating”,“pt”:“flow”,“to”:“false”,“tot”:“bool”},{“t”:“set”,“p”:“topic”,“pt”:“msg”,“to”:“HeaterControl”,“tot”:“str”}],“action”:“”,“property”:“”,“from”:“”,“to”:“”,“reg”:false,“x”:900,“y”:500,“wires”:[[“aac0d08884b39eac”]]},{“id”:“d1dacd6cdf736af6”,“type”:“switch”,“z”:“cd72f043d3c30165”,“name”:“”,“property”:“payload”,“propertyType”:“msg”,“rules”:[{“t”:“gte”,“v”:“Hysterisis”,“vt”:“env”},{“t”:“lt”,“v”:“Hysterisis”,“vt”:“env”}],“checkall”:“true”,“repair”:false,“outputs”:2,“x”:590,“y”:540,“wires”:[[“b079e1372bf6e02a”],[]]},{“id”:“b079e1372bf6e02a”,“type”:“change”,“z”:“cd72f043d3c30165”,“name”:“Turn On Heater”,“rules”:[{“t”:“delete”,“p”:“payload”,“pt”:“msg”},{“t”:“set”,“p”:“payload”,“pt”:“msg”,“to”:“true”,“tot”:“bool”},{“t”:“set”,“p”:“heating”,“pt”:“flow”,“to”:“true”,“tot”:“bool”},{“t”:“set”,“p”:“topic”,“pt”:“msg”,“to”:“HeaterControl”,“tot”:“str”}],“action”:“”,“property”:“”,“from”:“”,“to”:“”,“reg”:false,“x”:900,“y”:540,“wires”:[[“aac0d08884b39eac”]]},{“id”:“df3a3f28f4a0994f”,“type”:“change”,“z”:“cd72f043d3c30165”,“name”:“Get Temp Diff”,“rules”:[{“t”:“delete”,“p”:“payload”,“pt”:“msg”},{“t”:“set”,“p”:“setpoint”,“pt”:“msg”,“to”:“Setpoint”,“tot”:“flow”},{“t”:“set”,“p”:“currentTemp”,“pt”:“msg”,“to”:“temperature”,“tot”:“flow”},{“t”:“set”,“p”:“payload”,“pt”:“msg”,“to”:“msg.setpoint-msg.currentTemp”,“tot”:“jsonata”},{“t”:“set”,“p”:“tempDiff”,“pt”:“flow”,“to”:“payload”,“tot”:“msg”}],“action”:“”,“property”:“”,“from”:“”,“to”:“”,“reg”:false,“x”:420,“y”:540,“wires”:[[“d1dacd6cdf736af6”]]},{“id”:“19f4a5df9510ac19”,“type”:“switch”,“z”:“cd72f043d3c30165”,“name”:“not Deadman?”,“property”:“deadman”,“propertyType”:“flow”,“rules”:[{“t”:“false”},{“t”:“true”}],“checkall”:“true”,“repair”:false,“outputs”:2,“x”:700,“y”:660,“wires”:[[“ed0f6eed115d649f”],[“d5b0e732e3a2642b”]]},{“id”:“ed0f6eed115d649f”,“type”:“change”,“z”:“cd72f043d3c30165”,“name”:“”,“rules”:[{“t”:“set”,“p”:“payload”,“pt”:“msg”,“to”:“{"fill":"red","text":"Deadman"}”,“tot”:“json”}],“action”:“”,“property”:“”,“from”:“”,“to”:“”,“reg”:false,“x”:1080,“y”:660,“wires”:[[]]},{“id”:“d5b0e732e3a2642b”,“type”:“switch”,“z”:“cd72f043d3c30165”,“name”:“not heating?”,“property”:“heating”,“propertyType”:“flow”,“rules”:[{“t”:“false”},{“t”:“true”}],“checkall”:“true”,“repair”:false,“outputs”:2,“x”:870,“y”:700,“wires”:[[“626ca8c4422166d3”],[“15f6134e5e2d061b”]]},{“id”:“626ca8c4422166d3”,“type”:“change”,“z”:“cd72f043d3c30165”,“name”:“”,“rules”:[{“t”:“set”,“p”:“payload”,“pt”:“msg”,“to”:“{"fill":"red","text":"off"}”,“tot”:“json”}],“action”:“”,“property”:“”,“from”:“”,“to”:“”,“reg”:false,“x”:1080,“y”:700,“wires”:[[]]},{“id”:“15f6134e5e2d061b”,“type”:“change”,“z”:“cd72f043d3c30165”,“name”:“”,“rules”:[{“t”:“set”,“p”:“payload”,“pt”:“msg”,“to”:“{"fill":"green","text":"on"}”,“tot”:“json”}],“action”:“”,“property”:“”,“from”:“”,“to”:“”,“reg”:false,“x”:1080,“y”:740,“wires”:[[]]},{“id”:“e1e1861cf279e7b5”,“type”:“inject”,“z”:“cd72f043d3c30165”,“name”:“”,“props”:[{“p”:“payload”},{“p”:“topic”,“vt”:“str”}],“repeat”:“”,“crontab”:“”,“once”:true,“onceDelay”:0.1,“topic”:“”,“payload”:“”,“payloadType”:“date”,“x”:210,“y”:100,“wires”:[[“46acee4992eeaaf9”]]},{“id”:“46acee4992eeaaf9”,“type”:“change”,“z”:“cd72f043d3c30165”,“name”:“”,“rules”:[{“t”:“set”,“p”:“heating”,“pt”:“flow”,“to”:“false”,“tot”:“bool”},{“t”:“set”,“p”:“Setpoint”,“pt”:“flow”,“to”:“Setpoint”,“tot”:“env”}],“action”:“”,“property”:“”,“from”:“”,“to”:“”,“reg”:false,“x”:380,“y”:100,“wires”:[[]]},{“id”:“36ea054028726ff2”,“type”:“switch”,“z”:“cd72f043d3c30165”,“name”:“Setpoint message?”,“property”:“setpoint”,“propertyType”:“msg”,“rules”:[{“t”:“nnull”},{“t”:“else”}],“checkall”:“false”,“repair”:false,“outputs”:2,“x”:210,“y”:380,“wires”:[[“1b28cde477752fac”],[“281f57c8fa3f0f59”]]},{“id”:“1b28cde477752fac”,“type”:“change”,“z”:“cd72f043d3c30165”,“name”:“”,“rules”:[{“t”:“set”,“p”:“Setpoint”,“pt”:“flow”,“to”:“setpoint”,“tot”:“msg”}],“action”:“”,“property”:“”,“from”:“”,“to”:“”,“reg”:false,“x”:440,“y”:380,“wires”:[[“c38f605f469d288a”]]}]

3 Likes

I was being very serious… It’s scary what ChatGPT 4 is capable of. Very scary. And Even though a paid version, it’s very reasonably priced. I’ve used it for sql statements in MS Access.

2 Likes

Have a look at :

2 Likes

after few generic prompts I provided chatgpt with such an input (some of my sensors/actuator status):

{TH_SALOTTO:{temperature:21.9},MT_SALOTTO_DIVANO:{motion:True},TH_LETTO:{temperature:27.1},SW_SALOTTO_SOFFITTO:{on:False}}

chatgpt answer:

Thank you for the example. This is a JSON object representing readings from various sensors. Each key is the sensor name, and the value is another JSON object that contains the sensor readings. Here’s a brief description of how I might interpret these data:

TH_SALOTTO: This appears to be a temperature and humidity (TH) sensor located in the living room. The current temperature is 21.9 degrees.

MT_SALOTTO_DIVANO: This appears to be a motion sensor (MT) located in the living room, specifically near the sofa. It currently detects motion (True).

TH_LETTO: This is another temperature and humidity sensor located in the bedroom. The current temperature is 27.1 degrees.

SW_SALOTTO_SOFFITTO: This appears to be a switch (SW) located in the living room, specifically on the ceiling. It is currently off (False).

Now, tell me what questions you would like to ask about this data, or what kind of analysis you would like me to perform. For example, I could help you find the average temperature, determine if there has been movement in a certain location, check the status of a switch, etc.

Please note i never mentioned that TH is a temperature sensor prefix, nor that I have actuators (switches). I merely stated the general format of device name as “devicetype_location[_sublocation]”. Chatgpt deduced the sensor type from sensor attribute and he/it understood that SW_SALOTTO_SOFFITTO is an actuator (never said what an actuator is) from attribute “on”.

prompt: please answer me only with json formatted , possibly boolean when it makes sense.
question: is there someone at home?:
answer: {
“home_status”: {
“is_someone_home”: true
}
}

question: are some lights on at home?
answer:{
“are_lights_on”: false
}

question: which is the average temperature at home?
answer:{
“average_temperature”: 24.5
}

question: in which room would you open the window in the summer?
answer:{
“room_to_open_window”: “bedroom”
}

Impressive, is’nt it?

One point to consider: if you use ChatGPT in a script you have to subscribe a specific dev pay-per-use fee. It is not very expensive, but i depend on how big are your prompts (and the prompt history if any) and how many interactions you have with your CORE

1 Like

Btw, I have moved to using the home assistant generic thermostat, which also had the characteristics you are looking for. I can provide some direction if needed.

1 Like

Its amazing how good it is at doing database queries for pretty much any database out their,