Print Sensor to LCD Screen

So I have one of those 16x2 LCD Displays. It’s connected to a nodemcu and it’s working and I can print simple text to it no problems.

What I want to be able to do is print a state from a sensor from Home Assistant.

My yaml looks like this:

esphome:
  name: node_lcd
  platform: ESP8266
  board: nodemcuv2

wifi:
  ssid: "MY-SSID"
  password: "MY-PASS"

  # Optional manual IP
  manual_ip:
    static_ip: 10.90.11.57
    gateway: 10.90.11.1
    subnet: 255.255.255.0
    
# Enable logging
logger:

# Enable Home Assistant API
api:

ota:

i2c:
  sda: D2
  scl: D1

display:
  - platform: lcd_pcf8574
    dimensions: 16x2
    address: 0x27
    lambda: |-
      it.print("Weather: %s", id(weather).state.c_str());
      it.print(1, 0, "Sun: %s", id(sun).state.c_str());

web_server:
  port: 80

text_sensor:
  - platform: homeassistant
    id: weather
    name: weather
    entity_id: weather.home
    internal: true
  - platform: homeassistant
    id: sun
    name: sun
    entity_id: sun.sun
    internal: true

My errors on compilation are:

src/main.cpp: In lambda function:
src/main.cpp:167:53: error: no matching function for call to 'esphome::lcd_base::LCDDisplay::print(const char [12], const char*)'
it.print("Weather: %s", weather->state.c_str());
^
src/main.cpp:167:53: note: candidates are:
In file included from src/esphome.h:16:0,
from src/main.cpp:3:
src/esphome/components/lcd_base/lcd_display.h:31:8: note: void esphome::lcd_base::LCDDisplay::print(uint8_t, uint8_t, const char*)
void print(uint8_t column, uint8_t row, const char *str);
^
src/esphome/components/lcd_base/lcd_display.h:31:8: note:   candidate expects 3 arguments, 2 provided
src/esphome/components/lcd_base/lcd_display.h:33:8: note: void esphome::lcd_base::LCDDisplay::print(uint8_t, uint8_t, const string&)
void print(uint8_t column, uint8_t row, const std::string &str);
^
src/esphome/components/lcd_base/lcd_display.h:33:8: note:   candidate expects 3 arguments, 2 provided
src/esphome/components/lcd_base/lcd_display.h:35:8: note: void esphome::lcd_base::LCDDisplay::print(const char*)
void print(const char *str);
^
src/esphome/components/lcd_base/lcd_display.h:35:8: note:   candidate expects 1 argument, 2 provided
src/esphome/components/lcd_base/lcd_display.h:37:8: note: void esphome::lcd_base::LCDDisplay::print(const string&)
void print(const std::string &str);
^
src/esphome/components/lcd_base/lcd_display.h:37:8: note:   candidate expects 1 argument, 2 provided
src/main.cpp:168:51: error: no matching function for call to 'esphome::lcd_base::LCDDisplay::print(int, int, const char [8], const char*)'
it.print(1, 0, "Sun: %s", sun->state.c_str());
^
src/main.cpp:168:51: note: candidates are:
In file included from src/esphome.h:16:0,
from src/main.cpp:3:
src/esphome/components/lcd_base/lcd_display.h:31:8: note: void esphome::lcd_base::LCDDisplay::print(uint8_t, uint8_t, const char*)
void print(uint8_t column, uint8_t row, const char *str);
^
src/esphome/components/lcd_base/lcd_display.h:31:8: note:   candidate expects 3 arguments, 4 provided
src/esphome/components/lcd_base/lcd_display.h:33:8: note: void esphome::lcd_base::LCDDisplay::print(uint8_t, uint8_t, const string&)
void print(uint8_t column, uint8_t row, const std::string &str);
^
src/esphome/components/lcd_base/lcd_display.h:33:8: note:   candidate expects 3 arguments, 4 provided
src/esphome/components/lcd_base/lcd_display.h:35:8: note: void esphome::lcd_base::LCDDisplay::print(const char*)
void print(const char *str);
^
src/esphome/components/lcd_base/lcd_display.h:35:8: note:   candidate expects 1 argument, 4 provided
src/esphome/components/lcd_base/lcd_display.h:37:8: note: void esphome::lcd_base::LCDDisplay::print(const string&)
void print(const std::string &str);
^
src/esphome/components/lcd_base/lcd_display.h:37:8: note:   candidate expects 1 argument, 4 provided
*** [/data/nick_lcd/.pioenvs/nick_lcd/src/main.cpp.o] Error 1

I am simply wanting to print the weather state and the sun state…
ie Weather: sunny
sun: above_horizon
image

This code:

display:
  - platform: lcd_pcf8574
    dimensions: 16x2
    address: 0x27
    lambda: |-
      it.print("Weather");
      it.print(0, 1, "Sun");

Just prints 2 lines without the state but it works…

ok… this seems to work:

it.printf(0, 0, "Sun: %s", id(sun).state.c_str());

So now I can talk to it, I want to use a sensor state in Home Assistant (say the state will be On or Off) to trigger a countdown timer… say 60 seconds and then for the display to show that timer value.

I think that’s probably not too hard… has anyone done anything like that?

I haven’t done it but I would imagine it should be easy enough. Do you want to have that countdown timer value adjustable? That could complicate things a little but maybe try the below as a start

I’d imagine you can use theHome Assistant binary_sensor to retrieve the on/off from HA and use that to trigger an ESPhome automation to count down a global variable. You would then use code similar to what you have already to display the value of that global variable.

Not immediately obvious how to trigger the countdown…

Could potentially use a HA automation to trigger a switch on the nodemcu as well maybe? Not sure how to add the switch to esphome though either…

I think you would use this, but replace platform: gpio with platform: homeassistant and then specify your HA entity that was to be switching to ‘on’

Alternative method is to de-couple the nodeMCU and have it simply be a reporter of an MQTT topic you send it.

Then you can use automations in HASS to update the “print on my MCU” MQTT topic to whatever you want.

Keeps the logic in HASS with the MCU simply always showing what it is told.

This is what I did (in the olden days of arduino coding) here

Thanks Phil… while I love MQTT, this particular project doesn’t use it - only esphome.

It doesn’t appear like it’s that hard to do this in esphome but it’s a bit of a foreign language in there and not that intuitive to me.

Actually I’m not even 100% sure how I would do a countdown timer in Home Assistant anyway…

I’m quite interested in this little project of yours so you have me hooked now… (and I’m away from home so can’t tinker :smirk: )

You could probably use the timer component in HA and then read that with the ESP HA sensor. From there you would use your existing code to display the variable (the timer value) and the idea I had above to use that value to trigger an ESPhome automation

I don’t think the timer will do it. I want to run a pump for 60 seconds and have the screen display if the pump is on or off and if On I want it to count down from 60 seconds until it turns off. There’s actually 2 pumps - so one line for each pump…

There are counters and delays in Esphome - I just can’t figure out how to put all the pieces together mainly because I don’t get the logic of esphome really - this is the first thing I have tried to do with it other than toying with it for some basic switches a while ago which had me heading back to Tasmota again after I couldn’t do some pretty simple things in a logical manner…

Just in case you hadn’t seen it, there is a whole section on time here https://esphome.io/components/time.html

Forgive me if it is unhelpful, or already mentioned. I am in the middle of cooking dinner, and the water has just gone off. Hard to cook rice…

If I get some time in the next day or so I’ll try and right up some code to test

1 Like

Appreciate any help. Thanks.

Hey David…

I would start creating int globals, one for each pump
In your switch (I believe I would use a template switch optimistic) the on turn on action would set this global variable to e.g. 60

then there will be an interval: setup, to run every second, in this interval I check the value of the global and decremented by 1 if it is bigger than 1.

Let us know if you need more specific info. Try to put together these ideas in code so we can start working on there.

OK so I’m back on this now…
Here is my code:

display:
  - platform: lcd_pcf8574
    dimensions: 20x4
    address: 0x27
    lambda: |-
      it.printf(0, 0, "Nitrite %3s for %3.0fs", id(nitritepump).state ? "ON" : "OFF", id(nitritepump).state ? id(nitriteontime).state : id(nitriteofftime).state);
      it.printf(0, 1, "Twode %5s for %3.0fs", id(twodepump).state ? "ON" : "OFF", id(twodepump).state ? id(twodeontime).state : id(twodeofftime).state);

web_server:
  port: 80

sensor:
  - platform: homeassistant
    id: nitriteofftime
    name: nitriteofftime
    entity_id:  input_number.nitrite_pump_off
    internal: true
    accuracy_decimals: 0
  - platform: homeassistant
    id: nitriteontime
    name: nitriteontime
    entity_id:  input_number.nitrite_pump_on
    internal: true
    accuracy_decimals: 0
  - platform: homeassistant
    id: twodeofftime
    name: twodeofftime
    entity_id:  input_number.twode_pump_off
    internal: true
    accuracy_decimals: 0
  - platform: homeassistant
    id: twodeontime
    name: wtwodeontime
    entity_id:  input_number.twode_pump_on
    internal: true
    accuracy_decimals: 0

binary_sensor:
  - platform: homeassistant
    id: nitritepump
    name: nitritepump
    entity_id:  switch.nitrite_pump
    internal: true
  - platform: homeassistant
    id: twodepump
    name: twodepump
    entity_id:  switch.twode_pump
    internal: true

I have 2 pumps in Home Assistant. They are either on or off
I have an input_select so I can set the time on and time off for each pump.

On the display, I want it to show if the pump is on or off and how long it has till the state will switch from off to on or on to off

Right now, it will display say:

Nitrite ON  for 420
Twode   OFF for 900

So:
When the pump switches on (or off) I want the number to count down the seconds to 0 (when it will switch on/off). Not sure how to do this in esphome…

So it’s reading everything correctly from Home assistant…

1 Like

The following code compiles, hopefully it also works.

globals:
  - id: nitrite_secs
    type: int
    restore_value: no
    initial_value: '0'
  - id: twode_secs
    type: int
    restore_value: no
    initial_value: '0'

display:
  - platform: lcd_pcf8574
    dimensions: 20x4
    address: 0x27
    id: lcd
    lambda: |-
      it.printf(0, 0, "Nitrite %3s for %3ds", id(nitritepump).state ? "ON" : "OFF", id(nitrite_secs));
      it.printf(0, 1, "Twode %5s for %3ds", id(twodepump).state ? "ON" : "OFF", id(twode_secs));

interval:
  - interval: 1s
    then:
      - lambda: |-
          if (id(nitrite_secs) > 0)
            id(nitrite_secs)--;
          if (id(twode_secs) > 0)
            id(twode_secs)--;
      - component.update: lcd

sensor:
  - platform: homeassistant
    id: nitriteofftime
    name: nitriteofftime
    entity_id:  input_number.nitrite_pump_off
    internal: true
    accuracy_decimals: 0
  - platform: homeassistant
    id: nitriteontime
    name: nitriteontime
    entity_id:  input_number.nitrite_pump_on
    internal: true
    accuracy_decimals: 0
  - platform: homeassistant
    id: twodeofftime
    name: twodeofftime
    entity_id:  input_number.twode_pump_off
    internal: true
    accuracy_decimals: 0
  - platform: homeassistant
    id: twodeontime
    name: wtwodeontime
    entity_id:  input_number.twode_pump_on
    internal: true
    accuracy_decimals: 0

binary_sensor:
  - platform: homeassistant
    id: nitritepump
    name: nitritepump
    entity_id:  switch.nitrite_pump
    internal: true
    on_press:
      then: 
        lambda: |-
          id(nitrite_secs) = id(nitriteontime).state;
    on_release:
      then:
        lambda: |-
          id(nitrite_secs) = id(nitriteofftime).state;
  - platform: homeassistant
    id: twodepump
    name: twodepump
    entity_id:  switch.twode_pump
    internal: true
    on_press:
      then:
        lambda: |-
          id(twode_secs) = id(twodeontime).state;
    on_release:
      then:
        lambda: |-
          id(twode_secs) = id(twodeofftime).state;
1 Like

So that works great.

Only one thing, if I manually trigger the on/off, when it gets back to 0 it stays on for another cycle (similar if I manually switch it off)

Is there a way to overide the countdown and restart it if the switch is manually triggered?

Thanks!

You will need to post your pump config if you want help with that.

There’s a delay in the automation setting the on/off so I suspect that’s what it is. In general use it won’t be an issue anyway.

Thanks again.

A little off topic, but does the lcd_pcf8574 platform support clear screen command? I imagine it’s it.clear() however it’s not documented.

The lambda starts with a clear screen, but if necessary, there is a .clear() function as well. Most of the C++ functions that you can use with a lambda are not directly documented, but there’s an API reference link at the bottom of each page.