MyAir AC Zoning System, climate and Room Association for Components

This is good to know @Wayne, I now only show the Auto fan mode if it’s enabled by the system. If this is not correct, and you believe you should have auto mode without it being enabled please send me a diagnostic.

Only just found this thread, there may be some interest in the bodgy AppDaemon script I’ve been been working on.

Physically I have:

  • Advantage Air Zone10e w/ 5 dampers, controlled via Brett’s HA integration
  • Actron Air UltraSlim RCAC (rebranded Midea) controlled via ESPHome midea_ir component on an ESP32 in the roof next to the indoor unit
  • Xiaomi BLE temp/humidity sensors in each zone, flashed with pvvx firmware to expose 0.01 C precision

Initially I only wanted basic control via HA (e.g. turn off without walking downstairs), but the temperature regulation was awful across a 2 storey townhouse. I started thinking about how MyAir works with ITCs and one thing led to another…

On the frontend each zone has a virtual climate entity that displays the current temperature & allows the setpoint / mode to be set. Using GitHub - jcwillox/hass-template-climate: ❄️Templatable Climate Device for Home Assistant, Supports Running Actions On Service Calls.

For each zone in configuration.yaml

climate:
  - platform: climate_template
    name: Bed 1 Aircon
    modes: ["off", "heat", "cool"]
    temp_step: 0.1
    min_temp: 14
    max_temp: 30
    current_temperature_template: >
      {% if is_state('input_boolean.ac_use_feels_like', 'on') %}
        {{ states('sensor.bed_1_feels_like') }}
      {% else %}
        {{ states('sensor.bed_1_average_temperature') }}
      {% endif %}
    # no-op
    set_temperature:
      - delay: 0.0

The script looks reads its runtime config from these virtual climate entities & assumes that the same prefix is used for the damper e.g. climate.bed_1_aircon & cover.bed_1.

Internally there are 3 main stages to the script. Examples assume summer / cooling mode, but heating works too.

Zone control

PID for each zone to equalise temperature error.

e.g.
Room A, setpoint 20°C, actual 24°C
Room B, setpoint 24°C, actual 24°C

This stage of the controller makes as few assumptions as possible, it may be a bazillion degrees outside and the A/C is already running flat out with temps gradually climbing. Or it may be 25°C outside with a grossly oversized system so the temps are quickly plummeting inside. Doesn’t matter, for now the goal is to ensure that the occupants of each room are equally unhappy.

In this example the error for room A is 4°C, B is 0°C. The average error is 2°C, so all else being equal the controller will divert more air to bring room A such that it will cool down to 22°C. Air will be diverted from room B, allowing it to heat up to 26°C.

The output of each PID is scaled up such that one zone is always 100% open, & there’s a configurable deadband so that we don’t wear out the motors.

The derivative term of each PID controller that pre-empts changing conditions in each zone behaves much better with precise 0.01°C temperature sensors (I use Xiaomi BLE thermometers with pvvx firmware). With relatively large 0.1°C steps it was necessary to average over a relatively long period, diminishing the benefit.

Main AC control

An average of the errors for each zone is weighted by the position of each damper, as zones with less airflow aren’t as heavily influenced by changes to the compressor speed.

Once we have the error this stage could be very simple. If we can control the setpoint of the air conditioner, just increment it if an error accumulates.

If the system allows us to supply our own more accurate “follow me” temperature measurements, do that and let its controller handle the rest! A dummy setpoint can be configured e.g. always 20°C and we’ll just add the error to that e.g. on average it’s 1°C warmer than the setpoint for each zone, tell the AC that it’s “21°C” :wink:

Midea idiosyncrasy compensation

Oh dear… this was the real time sink. My AC has an inverter & can run the compressor at something like 20% to 100% power in 5% increments. When the cooling load is somewhere within this range, it should be able to find the right power level such that power consumption & ultimately the temperature of the air coming from the vents is near constant, rather than cycling off/on hot/cold like old school units.

Inverter driven compressors has been widespread for years, powerful microcontrollers are dirt cheap & Midea is a huge manufacturer so surely they can design a suitable controller. You’d be wrong, of course - left to its own devices this thing was constantly overshooting & undershooting due to what I can only assume is buggy firmware & a budget conscious customer base that doesn’t notice or care. After all, how many fussy, obsessive, technically inclined home owners would choose a cheap rebranded Midea system over Actron’s home grown offering or something from one of the big Japanese brands?

I started to write up this section but it got too big. Suffice to say that after much experimentation I’ve been able to tame the quirky Midea AC to maintain a stable compressor speed & keep each zone around ±0.1°C of their respective setpoints.

Show me the code

It’s not pretty.

Hi Brett,

I’m new to this. Currently, I have my zone 10 e tablet And a wall control unit. I cannot turn on/off the aircon by using the zone 10e app.
I tried to add the integration, it’s been added successfully. But I still can’t control the aircon, I can only turn on/off the zone and adjust the flow.

Am I lacking of any hardware? I can see zone 10 e+ from the app can turn on/ off the aircon. Do I need to upgrade to zone 10 e+? Or I have to install the e-zone instead?

Make sure you app is fully up to date on the tablet. Failing that you would be best to send me a diagnostic from the integration so I can figure out if anything is different. Send it to [email protected] or via a private message here.

I just updated the tablet, still not working. Sent you the diagnostics, hope this can help.

Any luck? Sent you a private message again, just in case you haven’t received my email.

I looked at what you sent me and couldn’t see anything obvious as to why it wouldn’t be working.

I’ll have to write up a python script for you to run and try figure out what’s going on.

Restart your android tablet if you haven’t already.

Thanks, Brett, yes, I have restarted the tablet, still not working. I checked the Logbook. It looks like the Zone 10e app always becomes unavailable and then it just turned off



. Please see attached pic

Apologies for a slightly off topic post here. I’m trying to get an integration to my MyAir3 system, which seems to have a related but different (XML vs JSON) communication that goes directly to a controller in the roof rather than an android tablet (this system has a proprietary screen). If anyone here has some background in the MyAir3 system with the XML protocol I have posted more details in another posting:

If no one has any ideas I’ll start further reverse engineering and see if I can build my first integration leveraging an existing integration that is built on the JSON protocol with some tweaks for the different protocol.

Hi all

I am about to sign up for my built contract . The builder is offering advantage air as their controller for panasonic ducted air conditioner. From my priliminary understanding they provide myair5 . Please help me understand which option would be better my air5 or ezone

How did you go?

@Brett_Adams are you still active with this integration?
Trying to use it with our MyPlace Advantage Air system and we can not connect. Looking for advice please.

Yep, raise an issue on GitHub with a diagnostic from the integration or any errors.

This was useful but I’m still a fresh rookie when it comes to Node-Red and couldn’t see that you’ve shared your flow. I also have a seperate input_number entity within Home Assistant so that I can set a temp per room (instead of the whole house). This is my version of your flow that runs every 15 minutes, but only if the temperature has updated in the last 15 minutes:

[{"id":"a7340f1f81284020","type":"function","z":"e0caf8ef8900ef72","name":"Temp recent?","func":"msg.temp_age = ((msg.room.timeSinceChangedMs / 1000)/60)\n\n// If the temp is within xx minutes\nif (((msg.room.timeSinceChangedMs / 1000)/60) < 15 ) {\n    // Then return the first output\n    return [msg, null];\n} else {\n    // Else return the first output (so we can ignore it)\n    return [null, msg];\n}","outputs":2,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":660,"y":1180,"wires":[["9fbf7b32938f5690"],[]]},{"id":"ed01ba6855a1c4ec","type":"api-current-state","z":"e0caf8ef8900ef72","name":"Room temp","server":"e785b29af2bbcdbe","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"sensor.cot_temp_temperature","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"room","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":490,"y":1180,"wires":[["a7340f1f81284020"]]},{"id":"9fbf7b32938f5690","type":"api-current-state","z":"e0caf8ef8900ef72","name":"Target temp","server":"e785b29af2bbcdbe","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"input_number.maisie_climate_target_temperature","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"target","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":830,"y":1180,"wires":[["08aa6f14c3e4394c"]]},{"id":"b1e9ff6c1493b51d","type":"api-current-state","z":"e0caf8ef8900ef72","name":"AC: Heat/Cool?","server":"e785b29af2bbcdbe","version":3,"outputs":2,"halt_if":"cool,heat","halt_if_type":"str","halt_if_compare":"includes","entity_id":"climate.ac","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"ac","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":320,"y":1180,"wires":[["ed01ba6855a1c4ec"],[]]},{"id":"08aa6f14c3e4394c","type":"api-current-state","z":"e0caf8ef8900ef72","name":"Cover pos","server":"e785b29af2bbcdbe","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"cover.ac_maisie","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"cover","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":990,"y":1180,"wires":[["3f4ab7bcb47d0593"]]},{"id":"1ae51198a01b6da8","type":"inject","z":"e0caf8ef8900ef72","name":"15 mins","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"900","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":160,"y":1180,"wires":[["b1e9ff6c1493b51d"]]},{"id":"3f4ab7bcb47d0593","type":"function","z":"e0caf8ef8900ef72","name":"New pos","func":"msg.temp_current = msg.room.state\nmsg.temp_target = msg.target.state\nmsg.temp_difference = msg.temp_target - msg.temp_current\nmsg.cover_change = msg.temp_difference * 5\n\nif (msg.ac.state == \"heat\"){\n    msg.cover_change = -msg.cover_change\n}\n\nmsg.position = Math.round(msg.cover.attributes.current_position + msg.cover_change)\nmsg.position =  Math.min(Math.max(msg.position,5),100)\nmsg.payload = { data: { \"entity_id\": msg.cover.entity_id, \"position\": msg.position } };\n\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1140,"y":1180,"wires":[["b4bdf88a4b1c7dce"]]},{"id":"b4bdf88a4b1c7dce","type":"api-call-service","z":"e0caf8ef8900ef72","name":"Set pos","server":"e785b29af2bbcdbe","version":5,"debugenabled":false,"domain":"cover","service":"set_cover_position","areaId":[],"deviceId":[],"entityId":[],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1280,"y":1180,"wires":[["b4e39e9342ce4e38"]]},{"id":"b4e39e9342ce4e38","type":"debug","z":"e0caf8ef8900ef72","name":"debug 2","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1420,"y":1180,"wires":[]},{"id":"e785b29af2bbcdbe","type":"server","name":"Home Assistant","version":5,"addon":false,"rejectUnauthorizedCerts":false,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":"30","areaSelector":"friendlyName","deviceSelector":"friendlyName","entitySelector":"friendlyName","statusSeparator":": ","statusYear":"hidden","statusMonth":"short","statusDay":"numeric","statusHourCycle":"default","statusTimeFormat":"h:m","enableGlobalContextStore":false}]

Edit:
New version which supports multiple rooms. It requires you to have some helper nodes: An input_boolean and input_number for enabling/disabling these nodes and setting your desired temperature. I’ll keep working on this to improve it but I won’t share updates unless people are interested. I don’t typically visit this forum :o

[{"id":"1862af56ca28813a","type":"function","z":"e0caf8ef8900ef72","name":"Temp recent?","func":"msg.temp_age = ((msg.room.timeSinceChangedMs / 1000)/60)\n\n// If the temp is within xx minutes\nif (((msg.room.timeSinceChangedMs / 1000)/60) < 15 ) {\n    // Then return the first output\n    return [msg, null];\n} else {\n    // Else return the first output (so we can ignore it)\n    return [null, msg];\n}","outputs":2,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":700,"y":1260,"wires":[["eb46e7944bc47e53"],[]]},{"id":"59e0be3b27a24001","type":"api-current-state","z":"e0caf8ef8900ef72","name":"Room temp","server":"e785b29af2bbcdbe","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"sensor.master_bedroom_temp_temperature","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"room","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":530,"y":1260,"wires":[["1862af56ca28813a"]]},{"id":"eb46e7944bc47e53","type":"api-current-state","z":"e0caf8ef8900ef72","name":"Target temp","server":"e785b29af2bbcdbe","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"input_number.master_climate_target_temperature","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"target","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":870,"y":1260,"wires":[["19835d9505ff0d24"]]},{"id":"3414078f229a8354","type":"api-current-state","z":"e0caf8ef8900ef72","name":"Master","server":"e785b29af2bbcdbe","version":3,"outputs":2,"halt_if":"true","halt_if_type":"bool","halt_if_compare":"is","entity_id":"input_boolean.master_climate_auto","state_type":"habool","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"room","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":390,"y":1260,"wires":[["59e0be3b27a24001"],[]]},{"id":"19835d9505ff0d24","type":"api-current-state","z":"e0caf8ef8900ef72","name":"Cover pos","server":"e785b29af2bbcdbe","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"cover.ac_master","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"cover","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":1030,"y":1260,"wires":[["3f4ab7bcb47d0593"]]},{"id":"b1e9ff6c1493b51d","type":"api-current-state","z":"e0caf8ef8900ef72","name":"AC: Heat/Cool?","server":"e785b29af2bbcdbe","version":3,"outputs":2,"halt_if":"cool,heat","halt_if_type":"str","halt_if_compare":"includes","entity_id":"climate.ac","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"ac","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":240,"y":1260,"wires":[["5bb1ef6b8f4c4af0","3414078f229a8354","031e2147c4aac679"],[]]},{"id":"3f4ab7bcb47d0593","type":"function","z":"e0caf8ef8900ef72","name":"New pos","func":"msg.temp_current = msg.room.state\nmsg.temp_target = msg.target.state\nmsg.temp_difference = msg.temp_current - msg.temp_target \nmsg.cover_change = msg.temp_difference * 5\nmsg.room_name = msg.cover.entity_id\n\nif (msg.ac.state == \"heat\"){\n    msg.cover_change = -msg.cover_change\n}\n\nmsg.position = Math.round(msg.cover.attributes.current_position + msg.cover_change)\nmsg.position = Math.min(Math.max(msg.position,5),100)\nmsg.payload = { data: { \"entity_id\": msg.cover.entity_id, \"position\": msg.position } };\n\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1200,"y":1260,"wires":[["b4bdf88a4b1c7dce"]]},{"id":"1ae51198a01b6da8","type":"inject","z":"e0caf8ef8900ef72","name":"10 mins","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"600","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":80,"y":1260,"wires":[["b1e9ff6c1493b51d"]]},{"id":"5bb1ef6b8f4c4af0","type":"api-current-state","z":"e0caf8ef8900ef72","name":"Maisie","server":"e785b29af2bbcdbe","version":3,"outputs":2,"halt_if":"true","halt_if_type":"bool","halt_if_compare":"is","entity_id":"input_boolean.maisie_climate","state_type":"habool","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"room","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":390,"y":1200,"wires":[["ed01ba6855a1c4ec"],[]]},{"id":"031e2147c4aac679","type":"api-current-state","z":"e0caf8ef8900ef72","name":"Living","server":"e785b29af2bbcdbe","version":3,"outputs":2,"halt_if":"true","halt_if_type":"bool","halt_if_compare":"is","entity_id":"input_boolean.living_climate_auto","state_type":"habool","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"room","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":390,"y":1320,"wires":[["ce17adbd0c4a014e"],[]]},{"id":"08aa6f14c3e4394c","type":"api-current-state","z":"e0caf8ef8900ef72","name":"Cover pos","server":"e785b29af2bbcdbe","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"cover.ac_maisie","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"cover","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":1030,"y":1200,"wires":[["3f4ab7bcb47d0593"]]},{"id":"98da14c41de9548f","type":"api-current-state","z":"e0caf8ef8900ef72","name":"Cover pos","server":"e785b29af2bbcdbe","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"cover.ac_enter","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"cover","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":1030,"y":1320,"wires":[["3f4ab7bcb47d0593"]]},{"id":"b4bdf88a4b1c7dce","type":"api-call-service","z":"e0caf8ef8900ef72","name":"Set pos","server":"e785b29af2bbcdbe","version":5,"debugenabled":false,"domain":"cover","service":"set_cover_position","areaId":[],"deviceId":[],"entityId":[],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1340,"y":1260,"wires":[["b4e39e9342ce4e38"]]},{"id":"ed01ba6855a1c4ec","type":"api-current-state","z":"e0caf8ef8900ef72","name":"Room temp","server":"e785b29af2bbcdbe","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"sensor.cot_temp_temperature","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"room","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":530,"y":1200,"wires":[["a7340f1f81284020"]]},{"id":"ce17adbd0c4a014e","type":"api-current-state","z":"e0caf8ef8900ef72","name":"Room temp","server":"e785b29af2bbcdbe","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"sensor.living_temp_1_temperature","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"room","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":530,"y":1320,"wires":[["a792014ed7133c5e"]]},{"id":"9fbf7b32938f5690","type":"api-current-state","z":"e0caf8ef8900ef72","name":"Target temp","server":"e785b29af2bbcdbe","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"input_number.maisie_climate_target_temperature","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"target","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":870,"y":1200,"wires":[["08aa6f14c3e4394c"]]},{"id":"97fb8ecabbfb1bbc","type":"api-current-state","z":"e0caf8ef8900ef72","name":"Target temp","server":"e785b29af2bbcdbe","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"input_number.living_climate_target_temperature","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"target","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":870,"y":1320,"wires":[["98da14c41de9548f"]]},{"id":"b4e39e9342ce4e38","type":"debug","z":"e0caf8ef8900ef72","name":"debug 2","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1340,"y":1340,"wires":[]},{"id":"a7340f1f81284020","type":"function","z":"e0caf8ef8900ef72","name":"Temp recent?","func":"msg.temp_age = ((msg.room.timeSinceChangedMs / 1000)/60)\n\n// If the temp is within xx minutes\nif (((msg.room.timeSinceChangedMs / 1000)/60) < 15 ) {\n    // Then return the first output\n    return [msg, null];\n} else {\n    // Else return the first output (so we can ignore it)\n    return [null, msg];\n}","outputs":2,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":700,"y":1200,"wires":[["9fbf7b32938f5690"],[]]},{"id":"a792014ed7133c5e","type":"function","z":"e0caf8ef8900ef72","name":"Temp recent?","func":"msg.temp_age = ((msg.room.timeSinceChangedMs / 1000)/60)\n\n// If the temp is within xx minutes\nif (((msg.room.timeSinceChangedMs / 1000)/60) < 15 ) {\n    // Then return the first output\n    return [msg, null];\n} else {\n    // Else return the first output (so we can ignore it)\n    return [null, msg];\n}","outputs":2,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":700,"y":1320,"wires":[["97fb8ecabbfb1bbc"],[]]},{"id":"e785b29af2bbcdbe","type":"server","name":"Home Assistant","version":5,"addon":false,"rejectUnauthorizedCerts":false,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":"30","areaSelector":"friendlyName","deviceSelector":"friendlyName","entitySelector":"friendlyName","statusSeparator":": ","statusYear":"hidden","statusMonth":"short","statusDay":"numeric","statusHourCycle":"default","statusTimeFormat":"h:m","enableGlobalContextStore":false}]

One more thing I have added are some nodes to check the sum of open vents is at least 100%, and if not, to open my digital constant to make up the difference. This will hopefully protect my aircon and its ducts over the long term. Please improve on this if you can!

[{"id":"9b013e386d2d27df","type":"api-current-state","z":"e0caf8ef8900ef72","name":"AC is on","server":"e785b29af2bbcdbe","version":3,"outputs":2,"halt_if":"off","halt_if_type":"str","halt_if_compare":"is_not","entity_id":"climate.ac","state_type":"str","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":940,"wires":[["bc429c44b1f4a89e"],[]]},{"id":"3d2b2fefb1ed4fc9","type":"inject","z":"e0caf8ef8900ef72","name":"1 min","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"60","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":110,"y":940,"wires":[["9b013e386d2d27df"]]},{"id":"bc429c44b1f4a89e","type":"junction","z":"e0caf8ef8900ef72","x":360,"y":940,"wires":[["39cdb0d82a8701f8","27d88d2ab2ee3c83","7f57b8f551584388","35c74d5db98d6692","3f1619b899178ff2","50a4ef28badd2c3a","92ba8f7d86131042"]]},{"id":"39cdb0d82a8701f8","type":"api-current-state","z":"e0caf8ef8900ef72","name":"Maisie","server":"e785b29af2bbcdbe","version":3,"outputs":2,"halt_if":"open","halt_if_type":"str","halt_if_compare":"is","entity_id":"cover.ac_maisie","state_type":"str","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":470,"y":760,"wires":[["f51a62c959bc9a81"],[]]},{"id":"27d88d2ab2ee3c83","type":"api-current-state","z":"e0caf8ef8900ef72","name":"Entertainment","server":"e785b29af2bbcdbe","version":3,"outputs":2,"halt_if":"open","halt_if_type":"str","halt_if_compare":"is","entity_id":"cover.ac_enter","state_type":"str","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":500,"y":820,"wires":[["f51a62c959bc9a81"],[]]},{"id":"7f57b8f551584388","type":"api-current-state","z":"e0caf8ef8900ef72","name":"Master","server":"e785b29af2bbcdbe","version":3,"outputs":2,"halt_if":"open","halt_if_type":"str","halt_if_compare":"is","entity_id":"cover.ac_master","state_type":"str","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":470,"y":880,"wires":[["f51a62c959bc9a81"],[]]},{"id":"35c74d5db98d6692","type":"api-current-state","z":"e0caf8ef8900ef72","name":"Dining","server":"e785b29af2bbcdbe","version":3,"outputs":2,"halt_if":"open","halt_if_type":"str","halt_if_compare":"is","entity_id":"cover.ac_dining","state_type":"str","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":470,"y":940,"wires":[["f51a62c959bc9a81"],[]]},{"id":"3f1619b899178ff2","type":"api-current-state","z":"e0caf8ef8900ef72","name":"Bed3","server":"e785b29af2bbcdbe","version":3,"outputs":2,"halt_if":"open","halt_if_type":"str","halt_if_compare":"is","entity_id":"cover.ac_bed3","state_type":"str","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":470,"y":1000,"wires":[["f51a62c959bc9a81"],[]]},{"id":"50a4ef28badd2c3a","type":"api-current-state","z":"e0caf8ef8900ef72","name":"Bed4","server":"e785b29af2bbcdbe","version":3,"outputs":2,"halt_if":"open","halt_if_type":"str","halt_if_compare":"is","entity_id":"cover.ac_bed4","state_type":"str","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":470,"y":1060,"wires":[["f51a62c959bc9a81"],[]]},{"id":"92ba8f7d86131042","type":"api-current-state","z":"e0caf8ef8900ef72","name":"Study","server":"e785b29af2bbcdbe","version":3,"outputs":2,"halt_if":"open","halt_if_type":"str","halt_if_compare":"is","entity_id":"cover.ac_study","state_type":"str","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":470,"y":1120,"wires":[["f51a62c959bc9a81"],[]]},{"id":"f51a62c959bc9a81","type":"change","z":"e0caf8ef8900ef72","name":"Save values","rules":[{"t":"set","p":"payload","pt":"msg","to":"data.attributes.current_position","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":650,"y":940,"wires":[["96ec523a7aab9638"]]},{"id":"96ec523a7aab9638","type":"join","z":"e0caf8ef8900ef72","name":"","mode":"custom","build":"array","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":false,"timeout":"5","count":"","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":790,"y":940,"wires":[["fb2b9b08b9749f26"]]},{"id":"fb2b9b08b9749f26","type":"calculator","z":"e0caf8ef8900ef72","name":"","inputMsgField":"payload","outputMsgField":"payload","operation":"sum","constant":"","round":false,"decimals":0,"x":910,"y":940,"wires":[["0fb9e46cc83956b6"]]},{"id":"0fb9e46cc83956b6","type":"switch","z":"e0caf8ef8900ef72","name":"<100","property":"payload","propertyType":"msg","rules":[{"t":"lt","v":"100","vt":"str"},{"t":"gt","v":"100","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":1030,"y":940,"wires":[["e87dfa7bc0862974"],[]]},{"id":"e87dfa7bc0862974","type":"calculator","z":"e0caf8ef8900ef72","name":"","inputMsgField":"payload","outputMsgField":"payload","operation":"sub","constant":"100","round":false,"truncate":false,"decimals":0,"decimals2":"0","x":1160,"y":940,"wires":[["caf97206de663c8e"]]},{"id":"caf97206de663c8e","type":"calculator","z":"e0caf8ef8900ef72","name":"","inputMsgField":"payload","outputMsgField":"payload","operation":"mult","constant":"-1","round":false,"truncate":false,"decimals":0,"decimals2":"0","x":1300,"y":940,"wires":[[]]},{"id":"e785b29af2bbcdbe","type":"server","name":"Home Assistant","version":5,"addon":false,"rejectUnauthorizedCerts":false,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":"30","areaSelector":"friendlyName","deviceSelector":"friendlyName","entitySelector":"friendlyName","statusSeparator":": ","statusYear":"hidden","statusMonth":"short","statusDay":"numeric","statusHourCycle":"default","statusTimeFormat":"h:m","enableGlobalContextStore":false}]

Hey @Tockers,

Your design looks pretty nice, do you mind sharing what is your card code settings for the zone control for the advantage air / ezone control?

Cheers,
Dario

               - cards:
                  - type: vertical-stack
                    cards:
                      - type: entities
                        entities:
                          - entity: climate.ac
                            type: custom:simple-thermostat
                            name: A/C
                            control:
                              hvac:
                                _name: Mode
                                dry: false
                                mode:
                                  icon: true
                            style:
                              .: |
                                #states > * {
                                  margin: -1px -15px !important;
                                }
                                ha-card {
                                  --st-font-size-xl: 32px;
                                  --st-font-size-m: 15px;
                                  height: 100%;
                                  box-shadow: none;
                                background: none;
                                  background-color: rgba(255, 255, 255, 0);
                                }
                            layout:
                              step: row
                              mode:
                                names: false
                            header: false
                            hide:
                              temperature: true
                            step_size: 1
                            decimals: 0
                            sensors:
                              - entity: sensor.temperature_4
                                name: Current
                          - type: divider
                          - type: buttons
                            entities:
                              - entity: cover.lounge
                                name: Lounge
                                icon: mdi:air-filter
                                secondary_info: position
                                tap_action:
                                  action: toggle
                              - entity: cover.bedroom
                                name: Bedroom
                                icon: mdi:air-filter
                                tap_action:
                                  action: toggle
                              - entity: cover.nursery
                                name: Nursery
                                icon: mdi:air-filter
                                tap_action:
                                  action: toggle
                              - entity: cover.wineroom
                                name: Wineroom
                                icon: mdi:air-filter
                                tap_action:
                                  action: toggle
                          - type: divider
                          - entity: input_number.lounge
                            name: Lounge
                            icon: mdi:thermometer-lines
                            type: custom:numberbox-card
                            style: |
                              .info{font-size:15px !important}
                              .cur-num{font-size:20px !important}
                              .cur-unit{font-size:60% !important}
                              .padr{padding:12px !important}
                              .padl{padding:12px !important}
                          - entity: input_number.bedroom
                            name: Bedroom
                            icon: mdi:thermometer-lines
                            type: custom:numberbox-card
                            style: |
                              .info{font-size:15px !important}
                              .cur-num{font-size:20px !important}
                              .cur-unit{font-size:60% !important}
                              .padr{padding:12px !important}
                              .padl{padding:12px !important}
                          - entity: input_number.study
                            name: Nursery
                            icon: mdi:thermometer-lines
                            type: custom:numberbox-card
                            card_mod: null
                            style: |
                              .info{font-size:15px !important}
                              .cur-num{font-size:20px !important}
                              .cur-unit{font-size:60% !important}
                              .padr{padding:12px !important}
                              .padl{padding:12px !important}
                          - entity: input_number.wineroom
                            name: Wineroom
                            icon: mdi:thermometer-lines
                            type: custom:numberbox-card
                            style: |
                              .info{font-size:15px !important}
                              .cur-num{font-size:20px !important}
                              .cur-unit{font-size:60% !important}
                              .padr{padding:12px !important}
                              .padl{padding:12px !important}