ESPHome, generic thermostat, Nextion display and target temperature

Hello everyone,

I hope I am posting at the right place… This is my first post!

after searching for houres, and not finding any helpful posts, i would like to share my problem with the community.

I am trying to set up a custome thermostate, using a nodumcu (through ESPHome) a Nextion display and a Generic Thermostat from Home Assistant.

The plan is the following:

  1. display the current temperature, humidity, and target temperature to the Nextion Display
  2. display the current temperature, humidity, and target temperature to the thermostate card in lovelace
  3. “conect” the target temperature of nextion display and thermostat card, so when changing the target temperature from the display, the lovelace card is being change as well and vice versa.

So far, 1 and 2 are working fine, but I am having difficulties on number 3.

Following are the YAML files of the ESPHome and the Home Assistant configuration

ESPHome YAML:

esphome:
  name: esp2
  platform: ESP8266
  board: nodemcuv2

wifi:
  ssid: "***"
  password: "****"
  manual_ip:
    static_ip: 192.168.1.113
    gateway: 192.168.1.1
    subnet: 255.255.255.0
    dns1: 192.168.1.1
    dns2: 192.168.1.1

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "****"
    password: "****"

captive_portal:

# Enable logging
logger:

# Enable Home Assistant API
api:

ota:

sensor:
  - platform: dht
    pin: D3
    model: dht11    
    temperature:
      name: "Thermostat Temperature"
      id: therm_temp
    humidity:
      name: "Thermostat Humidity"
      id: therm_hum
    update_interval: 30s
    
  - platform: homeassistant
    id: temperature_thermostat
    entity_id: sensor.thermostat_temperature
  - platform: homeassistant
    id: humidity_thermostat
    entity_id: sensor.thermostate_humidity
    
  - platform: template
    name: "Set Temperature"
    lambda: |-
      return {id(set_temp)};
    update_interval: 1s
  
switch:
  - platform: gpio
    name: "Heater"
    id: heater
    pin: D5
    inverted: yes
    
binary_sensor:
  - platform: gpio
    pin:
      number: D7
      mode: INPUT_PULLUP
      inverted: yes
    id: 'bouton_heater'
    name: "Bouton Heater"
    on_state:
      then:
        - switch.toggle: heater
        
  - platform: nextion
    page_id: 0
    component_id: 6
    id: minus_set_temp
    name: "Minus Set Temperature"
    on_press:
      lambda: |-
        id(set_temp) = id(set_temp) - 1;
        if (id(set_temp) == 14){
          id(set_temp) = 15;
        }
          
  - platform: nextion
    page_id: 0
    component_id: 5
    id: plus_set_temp
    name: "Plus Set Temperature"
    on_press:
      lambda: |-
        id(set_temp) = id(set_temp) + 1;
        if (id(set_temp) == 36){
          id(set_temp) = 35;
        }
    
i2c:

display:
  - platform: nextion
    id: teplomer
    update_interval: 1s
    lambda: |-
      // Do not wait for ack (this delays the whole procedure a lot, and has no use)
      it.set_wait_for_ack(false);
      
      it.set_component_text_printf("temperature","%2.1f",id(therm_temp).state);
      it.set_component_text_printf("humidity","%2.1f",id(therm_hum).state);
      it.send_command_printf("n0.val=%d",id(set_temp));
      it.send_command_printf("n1.val=%d",id(set_temp));
   
uart:
  rx_pin: GPIO1
  tx_pin: GPIO3
  baud_rate: 9600
  
globals:
  - id: set_temp
    type: int
    initial_value: '15'
    restore_value: no

configuration YAML: (only what is relevant)

climate:
  - platform: generic_thermostat
    name: Heater
    heater: switch.heater
    target_sensor: sensor.thermostat_temperature
    min_temp: 15

So the question is, what do I have to do, in order to connect “set_temp” from the ESPHome YAML (the dispay variable) with the thermostat target temperature, so when I change, the other changes as well.

In the configuration YAML I also tryied to do this:

set_temp: '{{ ((states(''sensor.set_temperature_2'') }}'

but it does not convert to float, so no luck theire!

Any help will be much appreciate!!

Thank you in advance.

I also put on a thermostat with nextion in this way and I have the same problem that you have, indeed maybe I have 2 problems. I need to import the setpoint from esphome - home assistant and from home assistant - esphome

Hello @Giuseppe-P, thank you for your reply!

I finaly got it to work!!

Following you will find my code with explanation on how it works. Feel free to ask anything you don’t anderstand!

For starters this is how I set up the Nextion display:

I asume I do not need to give more details. I use two same pages.

Page 0:
image

Page 1:
image

In page 0 for b0, b1, b2 I’ve checked the “send component ID” check box for press and release event. I also put the following on b2 release event to change the page “page 1”

Same thing on page 1 for b0, b1, b2. to change the page back to page 0 on release event of b2 i put “page 0”. also I plased “page1.n0.val=page0.n0.val” to the preinitialize event of the page to refresh the value of n0.

t0 and t1 are the sensor’s values for temperature and humidity and n0 is the set temperature. The “+” and “-” signs are for seting the n0 field.

On home assistant this is what happens:

Yaml file on the ESPHome sensor (I use a nodemcu v3):

esphome:
  name: esp2
  platform: ESP8266
  board: nodemcuv2

wifi:
  ssid: "*****"
  password: "****"
  manual_ip:
    static_ip: 192.168.1.113
    gateway: 192.168.1.1
    subnet: 255.255.255.0
    dns1: 192.168.1.1
    dns2: 192.168.1.1

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "***"
    password: "***"

captive_portal:

# Enable logging
logger:

# Enable Home Assistant API
api:

ota:

sensor:
  - platform: dht
    pin: D3
    model: dht11    
    temperature:
      name: "Thermostat Temperature"
      id: therm_temp
    humidity:
      name: "Thermostat Humidity"
      id: therm_hum
    update_interval: 30s
    
  - platform: template
    name: "Set Temperature"
    lambda: |-
      id(set_temp) = id(set_temperature).state;
      return id(set_temp);
    update_interval: 1s
    
  - platform: homeassistant #configuration.yaml sensor for the "set temperature" value
    entity_id: sensor.set_temp
    id: set_temperature

text_sensor:
  - platform: homeassistant #configuration.yaml sensor for the state of the thermostat
    entity_id: sensor.hvac_mode
    id: hvac_mode
  
switch:
  - platform: gpio
    name: "Heater"
    id: heater
    pin: D5
    inverted: no
    
binary_sensor:
  - platform: gpio
    pin:
      number: D7 #Realay pin
      mode: INPUT_PULLUP
      inverted: yes
    id: 'bouton_heater'
    name: "Bouton Heater"
    on_press:
      - switch.turn_on: heater
    on_release:
      - switch.turn_off: heater
      
  - platform: nextion
    page_id: 0
    component_id: 6
    id: minus_set_temp #custom sensor for the "-" button on the display
    name: "Minus Set Temperature"
    on_press:
      lambda: |- 
        id(set_temp) = id(set_temp) - 1; if (id(set_temp) == 14) {id(set_temp) = 15;}
  - platform: nextion
    page_id: 1
    component_id: 5
    id: plus_set_temp_1 #custom sensor for the "+" button on the display
    name: "Plus Set Temperature 1"
    on_press:
      lambda: |-
        id(set_temp) = id(set_temp) + 1;
        if (id(set_temp) == 36){
          id(set_temp) = 35;
        }
        
  - platform: nextion
    page_id: 1
    component_id: 6
    id: minus_set_temp_1 #custom sensor for the "-" button on the display
    name: "Minus Set Temperature 1"
    on_press:
      lambda: |-
        id(set_temp) = id(set_temp) - 1; if (id(set_temp) == 14) {id(set_temp) = 15;}
  - platform: nextion
    page_id: 0
    component_id: 5
    id: plus_set_temp #custom sensor for the "+" button on the display
    name: "Plus Set Temperature"
    on_press:
      lambda: |-
        id(set_temp) = id(set_temp) + 1;
        if (id(set_temp) == 36){
          id(set_temp) = 35;
        }
        
  - platform: nextion
    page_id: 0
    component_id: 8
    id: heater_off #custom sensor for the power button on the display
    name: "Turn Heater Off"
        
  - platform: nextion
    page_id: 1
    component_id: 8
    id: heater_on #custom sensor for the power button on the display
    name: "Turn Heater On"
        
i2c:

display:
  - platform: nextion
    id: teplomer
    update_interval: 1s
    lambda: |-
      // Do not wait for ack (this delays the whole procedure a lot, and has no use)
      it.set_wait_for_ack(false);
      
      it.set_component_text_printf("temperature","%.0f",id(therm_temp).state); //Set the sensor's temperature on the display
      it.set_component_text_printf("humidity","%.0f",id(therm_hum).state); //Set the sensor's humidity on the display
      it.send_command_printf("n0.val=%d",id(set_temp)); //populate the "set temperature" on the display for the "+" and "-" buttons
      it.send_command_printf("n0.val=%.0f",id(set_temperature).state); //populate the "set temperature" on the display from the lovelace card
      it.set_component_text_printf("t2","%s",id(hvac_mode).state.c_str()); //set the state of the heater on the display
   
uart:
  rx_pin: GPIO1
  tx_pin: GPIO3
  baud_rate: 9600
  
globals:
  - id: set_temp
    type: int
    initial_value: '15'
    restore_value: no

On configuration.yaml:

sensor:
  - platform: template
    sensors:
      set_temp:
        value_template: "{{states.climate.heater.attributes.temperature}}" #get the "set temperature" from lavelace card"
 
  - platform: template
    sensors:
      hvac_mode:
        value_template: "{{state_attr('climate.heater', 'hvac_action')}}" #get the heater state from lavelace card"
    
climate:
  - platform: generic_thermostat
    name: Heater
    heater: switch.heater
    target_sensor: sensor.thermostat_temperature
    min_temp: 15

automations.yaml:

- id: '1585489895859' #if the "-" button is pressed on the display, set the new value on card, page 0 of desplay
  alias: Set Temperature
  description: ''
  trigger:
  - entity_id: binary_sensor.minus_set_temperature 
    from: 'off'
    platform: state
    to: 'on'
  condition: []
  action:
  - data_template:
      temperature: '{{states.sensor.set_temperature_2.state | float - 1}}'
    entity_id: climate.heater
    service: climate.set_temperature
- id: '1585496046082' #if the "+" button is pressed on the display, set the new value on card page 0 of desplay
  alias: Set Temperature up
  description: ''
  trigger:
  - entity_id: binary_sensor.plus_set_temperature
    from: 'off'
    platform: state
    to: 'on'
  condition: []
  action:
  - data_template:
      temperature: '{{states.sensor.set_temperature_2.state | float + 1}}'
    entity_id: climate.heater
    service: climate.set_temperature
- id: '1585489895853' #if the "-" button is pressed on the display, set the new value on card, page 1 of desplay
  alias: Set Temperature Down p1
  description: ''
  trigger:
  - entity_id: binary_sensor.minus_set_temperature
    from: 'off'
    platform: state
    to: 'on'
  condition: []
  action:
  - data_template:
      temperature: '{{states.sensor.set_temperature_2.state | float - 1}}'
    entity_id: climate.heater
    service: climate.set_temperature
- id: '1585496046085' #if the "+" button is pressed on the display, set the new value on card page 1 of desplay
  alias: Set Temperature Up p1
  description: ''
  trigger:
  - entity_id: binary_sensor.plus_set_temperature
    from: 'off'
    platform: state
    to: 'on'
  condition: []
  action:
  - data_template:
      temperature: '{{states.sensor.set_temperature_2.state | float + 1}}'
    entity_id: climate.heater
    service: climate.set_temperature
- id: '1585577983660' #turn the heater off from the power button of the diplay
  alias: Turn Heater Off
  description: ''
  trigger:
  - entity_id: binary_sensor.turn_heater_off
    from: 'off'
    platform: state
    to: 'on'
  condition: []
  action:
  - data_template:
      hvac_mode: 'off'
    entity_id: climate.heater
    service: climate.set_hvac_mode
- id: '1585582208172' #turn the heater on from the power button of the diplay
  alias: Turn Heater ON
  description: ''
  trigger:
  - entity_id: binary_sensor.turn_heater_on
    from: 'off'
    platform: state
    to: 'on'
  condition: []
  action:
  - data_template:
      hvac_mode: heat
    entity_id: climate.heater
    service: climate.set_hvac_mode
- id: '1585645628892' #send notification for the status change of the heater
  alias: Heater mode
  description: ''
  trigger:
  - entity_id: sensor.hvac_mode
    from: 'off'
    platform: state
    to: heating
  - entity_id: sensor.hvac_mode
    from: heating
    platform: state
    to: 'off'
  - entity_id: sensor.hvac_mode
    from: heating
    platform: state
    to: idle
  - entity_id: sensor.hvac_mode
    from: idle
    platform: state
    to: heating
  condition: []
  action:
  - data:
      message: Heater is {{state_attr('climate.heater', 'hvac_action')}}
      title: Heater Status
    service: persistent_notification.create
  - data:
      message: Heater is {{state_attr('climate.heater', 'hvac_action')}}
      title: Heater Status
    service: notify.notify

I hope I am not forgetting anything…

Please let me know if that helps you out and if there is anything I can do to help you!

Thanks for sharing and for your answer … My layout for the thermostat will be like the one in the attached photo … Identical to the project I have already created with the souliss framework
2OFF

I’m new to esphome therefore I have to ask for help … It would be nice to be able to set a timer … It could be done by increasing a variable in esphome yaml called at one second interval and when it meets the condition for example 60 minutes send off … … With local logic and not dependent on home assistant, so as to function even in the absence of connection to HA

I forgot … You are using a generic thermostat in which its logic depends on HA, so in case of anomaly of the same the heaters remain on … Now they are out … But I would like to use your data for a thermostat bang bang so as to have the logic on the node in case of anomaly on the home assistant … Let’s keep up to date

Then from your yaml I see that the globals variable is increased only to pass it as given to the home assistant … It should, however, also be controlled on the node so as to manage the thermostat logic locally even in the absence of the home assistant … What do you think?

Example temperature higher than +1 or - 1 with respect to the setpoint. Turn the heaters on or off

1 Like

exactly, this is the next thing I am going to do, so in case that HA is not working i can control the heater directly from the nodemcu.

I also forgot to mention that at the moment the smart thermostat is working in parallel with the existing (not smart at all) thermostat. this is why in the esp yaml file the relay (D7 pin) switches the heater on and off, depending on the “non smart” thermostat.

I will emplement the functionality for the “stand alone” operation and will let you know about the outcome.

Thank you for sharing your project as well!

I took a look at your project.

Basically you are using a thermostat with logic managed on the home assistant and not on the node. in this case there is a risk that if the server stops working due to any anomaly, you lose control of the heaters. and if these are on they will stay long

why did you create double nextion buttons to increase and lend the setpoint?
you can attach the .hmi nextion file.

Thank you @Morpheas1983

I put your project up … But I made some substantial changes. In practice, your code every second writes the data on the nextion monitor. It is okay to insert 1 second of the update to be reactive, but it is not okay to leave the writing in lambda even when no state changes. Therefore I blocked the flows with variables, because the ESP8266 writing every second as well as giving strange strings in the logs, restarted losing connection with the API. Same thing with sending temp data to home assistant. The latter I run through the publish with each press on the touch.

@Morpheas1983

I know this is an odd question, but how would the code look for the esp controller if there was no display and only a relay to control heating?

and so that it can work without HA, just in case it crash’s during a holiday etc

EDIT: think i found my answer here: https://www.reddit.com/r/homeassistant/comments/j622me/esphome_thermostat/

does not have to be anything fancy.

Hi @Morpheas1983,
could you please share the .hmi nextion file.
I would try on your project first. Later I have a plan to make a sauna controller.