Where / how would I put the code to remote the generic_thermostat please?

I have just received another TTGO ESP32+st7789v display that I would like to be a remote display to my generic_thermostat please?

I would like it to repeat (display) the current temperature, potentially as reported by a Zigbee temp sensor and the target temperature, as held by the generic_thermostat function on HA.

I have duplicated / tweaked the code from my CO2-sensor that uses the same ESP / Display platform so I can play with it and it’s currently displaying blank for page one (correct as there is no CO2 sensor connected) and the current WiFi setting as page two (so I’m happy the display is working etc).

So I don’t really know where to start, eg, should / could the required code sit on the ESP32 and pull the target and actual temps from generic_thermostat somehow or would I use HA (automation or yaml in config etc) to push the values to the display please?

I would have to get a coding mate to help me with the actual code but I would like to know where best to start as he’s not familiar with HA etc.

FWIW, this is the code I have currently and I’ve left the CO2 stuff in in the hope it helps my mate re-code. eg, I could use the colour functions to indicate ‘heating’ (red) etc?

esphome:
  name: lounge-thermostat
  platform: ESP32
  board: "featheresp32"  

# Enable Home Assistant API
api:

ota:

wifi:
  ssid: !secret wifi_k_ssid
  password: !secret wifi_k_password
  
 # use_address: 192.168.0.202
  
  manual_ip:
   static_ip: 192.168.0.195
   gateway: 192.168.0.100
   subnet: 255.255.255.0      
  

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "lounge thermostat Hotspot"
    password: "1234"

captive_portal:

logger:
  level: DEBUG
  logs:
    component: ERROR

# CO2 sensor
uart:
  rx_pin: 27
  tx_pin: 26
  baud_rate: 9600

# Dipslay driver: ST7789
spi:
  clk_pin: GPIO18
  mosi_pin: GPIO19

font:
  - file: "Oswald-Light.ttf"
    id: font_70
    size: 70
    glyphs: 0123456789 # Only used for CO2 level

  - file: "Oswald-Light.ttf"
    id: font_30
    size: 30

color:
  - id: color_black
    red: 0%
    green: 0%
    blue: 0%
    white: 0%
  - id: color_green
    red: 0%
    green: 100%
    blue: 0%
  - id: color_yellow
    red: 100%
    green: 100%
    blue: 0%
  - id: color_orange
    red: 100%
    green: 55%
    blue: 0%
  - id: color_red
    red: 100%
    green: 0%
    blue: 0%
  - id: color_white
    red: 100%
    green: 100%
    blue: 100%

display:
  - platform: st7789v
    model: TTGO TDisplay 135x240  # added bit
    id: my_display
    backlight_pin: GPIO4
    # allow_other_uses: true
    cs_pin: GPIO5
    dc_pin: GPIO16
    reset_pin: GPIO23
 #   brightness: 100%
    rotation: 270
    pages:
      # Page 1: Current CO2 levels
      #    0    - 1000 -> Green
      #    1000 - 1600 -> Yellow
      #    1600 - 2000 -> Orange
      #    >2000       -> Red
      - id: page1
        lambda: |-
          if(!id(co2_sensor_3).has_state() ){
            it.print(
              it.get_width()/2,
              it.get_height()/2,
              id(font_70),
              color_white,
              TextAlign::CENTER,
              "Starting..."
            );
            return;
          }
         
          auto bg_color = id(color_black);
          auto text_color = id(color_green);
          auto co2 = id(co2_sensor_3).state;
          if(co2 > 1000) text_color = id(color_yellow);
          if(co2 > 1600) text_color = id(color_orange);
          if(co2 > 2000){
            text_color = id(color_white);
            bg_color = id(color_red);
          }
          it.filled_rectangle(0, 0, it.get_width(), it.get_height(), bg_color);
          it.printf(
            it.get_width()/2, 
            it.get_height()/2, 
            id(font_70), 
            text_color, 
            TextAlign::CENTER, 
            "%.0f",
            co2
          );
      # Page 2: WiFi information
      - id: page2
        lambda: |-
          it.print(
            0, 0,
            id(font_30),
            id(color_white),
            "WiFi details"
          );
          it.printf(
            0, 30,
            id(font_30),
            id(color_green),
            "%s",
            id(wifi_ssid).state.c_str()
          );
          it.printf(
            0, 60,
            id(font_30),
            id(color_yellow),
            "%s",
            id(wifi_ip_addr).state.c_str()
          );
#switch:
#  - platform: gpio
#    pin: GPIO4
#     allow_other_uses: true
#    id: backlight
#    internal: true

sensor:
  - platform: mhz19
    co2:
      name: "CO2 Sensor 3"
      id: "co2_sensor_3"
    temperature:
      name: "Lounge thermostat temperature"
      internal: true
    update_interval: 60s
    automatic_baseline_calibration: false
    
  - platform: wifi_signal
    name: "Lounge thermostat WiFi"
    update_interval: 60s   

text_sensor:
  - platform: wifi_info
    ip_address:
      internal: true
      id: wifi_ip_addr
    ssid:
      internal: true
      id: wifi_ssid

binary_sensor:
  # Button to cycle through pages on the display
  - platform: gpio
    pin:
      number: GPIO35
      inverted: true
    id: button_1
    on_click:
      then:
        - display.page.show_next: my_display
        - component.update: my_display

  # Button to toggle the backlight (for use at night)
  #- platform: gpio
  #  pin:
  #    number: GPIO0
  #    inverted: true
  #  id: button_2
  #  on_click:
  #    then:
  #      - switch.toggle: backlight
        
button:
  - platform: restart
    name: "Lounge thermostat restart"

You pull the data from Home Assistant using platform: homeassistant sensors. Below is the link to the text sensor, there are similar sensors for sensor: and binary_sensor: entities.

Thanks very much for the reply and pointer and I think I’ve added the code to my ESP32?

text_sensor:
  - platform: wifi_info
    ip_address:
    #  internal: true
      id: wifi_ip_addr
    ssid:
    #  internal: true
      id: wifi_ssid
    mac_address:
      id: wifi_mac_address
    scan_results:
      id: wifi_scan_results

  - platform: homeassistant
    name: "Lounge temperature test"
    entity_id: sensor.meter_1676_temperature 

But I’m not sure how I would then make use of that to be able to update the ESP32/TTGO display to show it (either the target temp as set in generic_thermostat or the actual temp from a Zigbee temperature sensor)?

This is the code for my generaic_thermostat from configuration.yaml

climate:
  - platform: generic_thermostat
    name: Lounge
    heater: switch.lounge_heater
    # heater: switch.gosundplug04
    # target_sensor: sensor.lounge_t_and_h_sensor_temperature
    target_sensor: sensor.meter_1676_temperature    
    min_temp: 10
    max_temp: 28
    ac_mode: false
    target_temp: 12
    cold_tolerance: 0.3
    hot_tolerance: 0
    min_cycle_duration:
      seconds: 5
    keep_alive:
      minutes: 3
    initial_hvac_mode: "heat"
    precision: 0.5

And where I'm trying to send it to the ESP display from the ESP32 code:

  - id: page1
    lambda: |-
        it.print(
          it.get_width()/2,
          it.get_height()/2,
          id(font_40),
          color_red,
          TextAlign::CENTER,
          "20 DegC"
        );

I’ve managed to at least make it display the fixed text, ‘20 DegC’. :wink:

Firstly, give your sensor an id.

Then use printf to print it.

  - platform: homeassistant
    name: "Lounge temperature test"
    id: temp
    entity_id: sensor.meter_1676_temperature 

  - id: page1
    lambda: |-
        it.printf(
          it.get_width()/2,
          it.get_height()/2,
          id(font_40),
          color_red,
          TextAlign::CENTER,
          "%s °C", 
          id(temp).state.c_str());

Note you may be better using sensor: rather than text_sensor: - this would mean you have greater control over formatting, as you would be returned a numeric float value rather than text. Up to you…

Wow. Can I first thank you for both your prompt reply and solution, that once I had realised was all I needed, (no ); after the block of text) it worked first time!

Interestingly it initially just shows the DegC symbol (as that’s ‘local’ etc), then slightly later fills in the actual temperature. :wink:

I think I like the idea of being able to have more flexibility re display and I tried moving the platform bit from under text_sensor: to under sensor: and I get compile errors? Should I also change something else please?

Paste your log here and we’ll have a look.

Before I do, can I just confirm it’s just a matter of moving that code from under text_sensor: to sensor:, as is, like this?

sensor:
  - platform: homeassistant
    name: "Lounge temperature test"
    id: temp
    entity_id: sensor.meter_1676_temperature 
    
  - platform: wifi_signal
    name: "Lounge thermostat WiFi"
    update_interval: 60s  

Yes - that should be fine.

I only suggested this because with a number rather than text you can have more complex printf statements, to control the number of decimal points displayed for instance.

Thanks again for the prompt reply!

This is the install log if that’s what you meant?

INFO ESPHome 2023.12.6
INFO Reading configuration /config/esphome/lounge-thermostat.yaml...
WARNING GPIO5 is a strapping PIN and should only be used for I/O with care.
Attaching external pullup/down resistors to strapping pins can cause unexpected failures.
See https://esphome.io/guides/faq.html#why-am-i-getting-a-warning-about-strapping-pins
INFO Generating C++ source...
INFO Compiling app...
Processing lounge-thermostat (board: featheresp32; framework: arduino; platform: platformio/[email protected])
--------------------------------------------------------------------------------
HARDWARE: ESP32 240MHz, 320KB RAM, 4MB Flash
 - toolchain-xtensa-esp32 @ 8.4.0+2021r2-patch5
Dependency Graph
|-- AsyncTCP-esphome @ 2.0.1
|-- WiFi @ 2.0.0
|-- FS @ 2.0.0
|-- Update @ 2.0.0
|-- ESPAsyncWebServer-esphome @ 3.1.0
|-- DNSServer @ 2.0.0
|-- ESPmDNS @ 2.0.0
|-- noise-c @ 0.1.4
|-- SPI @ 2.0.0
Compiling .pioenvs/lounge-thermostat/src/main.cpp.o
<unicode string>: In lambda function:
<unicode string>:106:21: error: request for member 'c_str' in 'temp->esphome::homeassistant::HomeassistantSensor::<anonymous>.esphome::sensor::Sensor::state', which is of non-class type 'float'
*** [.pioenvs/lounge-thermostat/src/main.cpp.o] Error 1
========================= [FAILED] Took 12.07 seconds =========================

Line 106 is this one:

              id(temp).state.c_str());

What have I done wrong? ;-(

Ah, that’s because it’s now a number, as I mentioned above.

Read this:

Then change your printf statement to:

          "%.1f °C", 

This changes the %s for string to %f for float, with one digit after the decimal place.

As I said - you may not need it but it’s handy to know when you want to display numbers with 6 decimal places but you only want to display 2 of them… :slight_smile:

EDIT: oops!

          "%.1f °C", 
          id(temp).state);

Hehe, your update just beat my reply with the new install error. :wink:

That now works perfectly thanks. :wink:

Well, it looks the same on the TTGO display as it did previously of course but I now have the increased flexibility.

One interesting observation is when you reboot it displays ‘nan’ before it replaces it with the temperature a couple of seconds later. Is there any relevance to that it says ‘nan DegC’ OOI?

Cheers …

nan stands for “not a number”, it’s just because until it retrieves the value from HA it is “unknown” or “unavailable”.

The display does it’s first update well before the API connection and sensor updates are done.

Brilliant, thanks. I really do appreciate having access to good folk like you who obviously know your stuff AND are willing to help a keen but ‘code blind’ person like me. :wink:

I love HA and have built (and rely on in many cases) about 10 ESP8266/32’s and it’s mostly because I have been able to stand on the shoulders of giants I have been able to do what I really want, the electronics and HA / ESPHome to make things work for me.

Not just for the fun of it (although that is a big part, when it works) but because of the features it provides.

Thanks.

1 Like