How to create a 'Shadow Climate Controller'?


I’m new to Home Assistant (an thus ESPHome), but having tons of fun with it so far! Unbelievable what has already been implemented!

I now seem to have hit a brick wall with what I want to do.

My situation
I have 2 Panasonic A/C units that I now control with this third-party integration, which works very well. However, we also use the IR-remotes that came with the A/C, but them being send-only they are mostly out-of-sync with what the A/C unit is actually doing! Leading to massive frustration with some members of the household…

So I decided to try and make a separate thermostat unit with ESPhome, based on a LilyGO TTGO ESP32 with integrated ePaper display, combined with a rotary encoder (I already have an external temp sensor in both rooms). I already got the display and rotary encoder set up with an internal Thermostat Climate component from ESPHome, to show and change the target temperature, as well as the current room temperature.

What I want to do
So now I want somehow couple this thermostat to the Panasonic A/C unit’s thermostat so it always shows it’s current state, while being able to control it as well. So whether you change the setpoint with the thermostat, or with the IR remote, or some automation in HA: the display should always reflect the current state! So I would need some kind of bidirectional link between the two of them.

I know there is a ‘homeassistant’ platform that lets you pull sensors and such from HA into an ESPHome device to work with. Alas, no homeassistant.climate implementation exists.

How would I tackle this one? I’m not afraid of doing C++ or Python coding: I already needed to implement an epaper_menu (based on lcd_menu) as that didn’t seem to exist as well.
How to get state updates from the real Panasonic Climate object in HA into my ESPHome device?
Should I try to implement the homeassistant.climate myself? Or is this just meant to reflect data from HA and not allow control? An external component?

I’m a bit lost at the moment…

I just noticed this in the ESPHome docs of homeassistant.sensor:

Entity state attributes can also be imported:

# Example configuration entry
  - platform: homeassistant
    id: current_temperature
    entity_id: climate.living_room
    attribute: current_temperature

Perhaps that’s the way to go then?

For those interested: I got it working by using the attribute config param on homeassistant.sensor and homeassistant.text_sensor.
But it’s very laborious!

It should be feasible to make a homeassistant.climate that uses those under the hood, but for the time being, I’m going to stick with this. Maybe when I find the time I’ll have a stab at that!

hi - i am struggling with something similar , would you be so kind as to post your code for me to look at ? it might help point me in the right direction . TIA :+1:

Well, it’s still very much a work in progress right now. I had something that worked fairly well, but as soon as I tried adding Deep Sleep to it, it all went to sh*t… Turns out the home assistant api and deep sleep don’t work so well together (connection times are too long and things like that.
MQTT seems like a better fit for that.

How I did it this far (so if you don’t plan on using deep sleep):
Let’s take the target temp (or setpoint) as an example:
First make a local ‘proxy var’ in you ESPHome device:

  - id: proxy_climate_temperature
    type: float
    initial_value: '0'
    restore_value: True

(restore_value is probably not needed without deep_sleep

Then pull in the value from HA into the ESPHome device and copy it to the proxy upon reception:

  - platform: homeassistant
    id: target_temperature
    entity_id: climate.living_room
    attribute: temperature
        - lambda: 'id(proxy_climate_temperature) = x;'

BTW, I use the proxy value to be displayed on my ePaper.
I also have the min and max from the climate component pulled in, but you could hard-code them (or use substitutions)

Then have a setpoint and a post_setpoint script to update the proxy value on input (I use a rotary encoder)

  - id: setpoint
    mode: queued
      change: float
      - lambda: |-
          id(proxy_climate_temperature) = std::max(std::min(id(proxy_climate_temperature) + change, id(proxy_climate_max_temp)), id(proxy_climate_min_temp));
      - script.execute:
          id: post_setpoint
          value: !lambda return id(proxy_climate_temperature);
      - script.execute: trigger_update
  - id: post_setpoint
    mode: restart
      value: float
      - delay: 100ms
      - homeassistant.service: 
          service: climate.set_temperature
            entity_id: climate.living_room
            temperature: !lambda return value;

setpoint has queued mode, so all changes are queued (handy with a rotary: 5 clicks is 2.5°C ).
post_setpoint has mode restart and a 100ms delay, to prevent it being spammed to HA.(may not be necessary.

In my rotary I call it like this:

      - script.execute: 
          id: setpoint
          change: +0.5
      - script.execute: 
          id: setpoint
          change: -0.5

That’s the gist of how I did it. But I had to do that for all the climate attributes I wanted to set. So quite laborious!

Does that help?