Publish timestamp into text_sensor

Hi guys,

Pretty new to ESPHome and need some help from the gurus out there :blush:

I’ve a D1 mini on ESPHome used for my frontdoor bell. All is working fine when someone rings the bell:

  • the standard house bell rings (used a relay on the D1 mini)
  • notifications are sent to my television and different iPhones together with live-stream video from my camera
  • google home is playing “Ding Dong”
  • a template sensor keeps track on how many times the bell was pressed (counter reset on new years)

The only thing I can’t get to work/figured out is how to publish the timestamp when the push button / bell (binary sensor) last was pressed.

So in short need to have the ??? replaced by some code :slight_smile:

text_sensor:
  - platform: template
    name: "Last bell press on"
    id: last_bell_press_on
    icon: mdi:calendar-clock

binary_sensor:
  - platform: gpio
    name: "doorbell"
    id: doorbell
    pin:
      number: D3
      inverted: True
      mode: INPUT_PULLUP
    filters:
      - delayed_on: 100ms
    on_press:
      then:
        - switch.turn_on: relays_doorbell
        - delay: 500ms
        - switch.turn_off: relays_doorbell
        - lambda: 'id(bell_nr_int) += 1;'
        - sensor.template.publish:
            id: nr_bell_presses
            state: !lambda 'return id(bell_nr_int);'
        - text_sensor.template.publish:
            id: last_bell_press_on
            **???????????????????**

Thanks a lot in advance for your valuable inputs!

1 Like

Homeassistant logs everything in the database, so you have the timestamp recorded.

Thx for your reply!
That would be a good alternative if there is no solution in ESPHome to capture and store the time stamp the button was pressed (which I prefer as I would like to use a kind a like setup for my garage doors, first trying to find the bell working as it has less impact than my garage doors which currently work on tasmota/MQTT)

While what you want to do is doable. There’s another option:

In Lovelace I have some motion sensor configured this way.

entities:
  - entity: binary_sensor.movimiento_galeria
    secondary_info: last-changed

So it renders when was the last time a movement was triggered.
1 hour ago, 5 minutes ago, etc.
and if you click on the entity you will see a chart when this happened and also the timestamps in the logbook.

Now if you really want the string with the formatted string, that is doable, you need the time: component, look at the strftime you need to combine that with a lambda call on your text sensor to id(text_sensor).publish_state(strftime(...)).

I really can’t figure out why you need to store this in esphome, but maybe I am just missing the point.

Sometimes I think people expect to put too much into an esphome device. While some automation on the esp device is understandable (such as the automation suggested in the docs of a button and a switch on the same esp https://esphome.io/guides/automations.html)[1], I prefer home assistant to be doing most of the controlling, and to hold the state information. One of the reasons for HA is to have everything centralised.

[1] At heart this is no more than what a smart plug has - a switch and a button.

1 Like

Bit late, but just implemented this myself:

    on_press:
      then:
        - text_sensor.template.publish:
            id: last_bell_press
            state: !lambda |-
                char str[17];
                time_t currTime = id(homeassistant_time).now().time;
                strftime(str, sizeof(str), "%Y-%m-%d %H:%M", localtime(&currTime));
                return  { str };

Also requires:

time:
  - platform: homeassistant
    id: homeassistant_time

(The reason I’ve added this rather than doing it in home assistant is that I’ve had a few instances of missed notifications, so I wanted a backup mechanism to check the last time the doorbell was pressed.)

HTH,

James

2 Likes

Thanks James!

Will they it out over the weekend

Hey James

I just came across your solution and wanted to implement it. Unfortunately this way seems to be deprecated now. May I ask you whether you still have a working solution for this?

My relay is only on for 0.5s and won’t update its status in HA.

Thank you in advance!

I’m still using the same method described above. It’s working very well.

Which aspect has been deprecated?

James

Thanks for your fast answer - really appreciate it.

Here’s what I got as log output:

src/main.cpp: In lambda function:
src/main.cpp:226:40: warning: 'esphome::time::ESPTime::<anonymous union>::time' is deprecated: .time is deprecated, use .timestamp instead [-Wdeprecated-declarations]
       time_t currTime = ha_time->now().time;
                                        ^
In file included from src/esphome/components/homeassistant/time/homeassistant_time.h:4:0,
                 from src/esphome.h:14,
                 from src/main.cpp:3:
src/esphome/components/time/real_time_clock.h:35:73: note: declared here
     ESPDEPRECATED(".time is deprecated, use .timestamp instead") time_t time;
                                                                         ^
src/main.cpp:226:40: warning: 'esphome::time::ESPTime::<anonymous union>::time' is deprecated: .time is deprecated, use .timestamp instead [-Wdeprecated-declarations]
       time_t currTime = ha_time->now().time;
                                        ^
In file included from src/esphome/components/homeassistant/time/homeassistant_time.h:4:0,
                 from src/esphome.h:14,
                 from src/main.cpp:3:
src/esphome/components/time/real_time_clock.h:35:73: note: declared here
     ESPDEPRECATED(".time is deprecated, use .timestamp instead") time_t time;
                                                                         ^
src/main.cpp:226:40: warning: 'esphome::time::ESPTime::<anonymous union>::time' is deprecated: .time is deprecated, use .timestamp instead [-Wdeprecated-declarations]
       time_t currTime = ha_time->now().time;
                                        ^
In file included from src/esphome/components/homeassistant/time/homeassistant_time.h:4:0,
                 from src/esphome.h:14,
                 from src/main.cpp:3:
src/esphome/components/time/real_time_clock.h:35:73: note: declared here
     ESPDEPRECATED(".time is deprecated, use .timestamp instead") time_t time;

Yesterday when I tried this, I assumed it was an error and went back to my old yaml - but now I realize it’s only a warning & the sensor basically works perfectly fine :crazy_face:


I tried a few things to get rid of the warning and here’s my solution if you’re interested:

time_t currTime = id(homeassistant_time).now().time;

to:

time_t currTime = id(homeassistant_time).now().timestamp;

6 Likes

I had a similar use case, so if someone stumbles across this old thread, this might be useful. When the goal is to publish a datetime to Home Assistant, the approach is a lot easier.

ESPHome sensor configuration:

time:
  - platform: homeassistant
    id: homeassistant_time

sensor:
  - platform: template
    name: "Display Last Update"
    device_class: timestamp
    id: display_last_update

Next you can write the current timestamp to the “Last Update” sensor inside the lambda of your choosing:

id(display_last_update).publish_state(id(homeassistant_time).now().timestamp);

The fact that we told Home Assistant that device_class is “timestamp” is all that is needed to generate a pretty localized timestamp from it:

grafik

2 Likes

You can just use the sensor.template.publish action instead of having the whole thing be a lambda:

    - sensor.template.publish:                                                                                                                                           
        id: display_last_update                                                                                                                                                   
        state: !lambda 'return id(homeassistant_time).now().timestamp;'

That’s certainly another option but it depends on your use case. In my scenario I do not need an action but a lambda one-liner. So something to consider. Just want to make this clear for others playing along at home.

Got it, I wasn’t clear on what you were replying to and now realize I mostly just repeated the earlier thing.

A question for anyone involved here: when I use a Template Sensor (or Template Text Sensor, etc.), esphome feels the need to report its state every minute. You can modify the interval though, so I made mine every 12 hours, but ideally it’d never do it except when the state changes (when we call sensor.template.publish) since MQTT retain is on anyway. Is there a way to disable this regular updating?

1 Like

Thanks for this, just what I needed, any Idea how I can show just the updated elapsed time on my display?

image

Hey, I am not super sure what you mean. The timestamp on the right is the actual time when “Last Fed” happened. The “9 minutes ago” is when the Home Assistant entity was last updated. Those are not necessarily the same and you would miss the point of this entity if you went with the latter.

In lovelace, just define a simple card like this:

Sorry, I was referring to a display attached to the Esp32 running Esphome, I get the time by using a template sensor extracting just the time (date not required), but I wanted to be able to show the elapsed time (9 minutes ago ) on the Esphome display.

Ah! What comes to mind:

  1. Store the last update timestamp in a variable
  2. Calculate the difference between timestamp and now() in seconds
  3. Present int(seconds/60) + " minutes ago"

More or less :slight_smile: Does that make sense?

Sure, but I’m a real noob at templates.

you can set the update interval to never:

sensor:
  - platform: template
    name: My Sensor
    id: my_sensor
    update_interval: never

One thing to keep in mind is that upon startup, the value will be nan until a publish command is received by that sensor. To address that, you can put a publish command in the on_boot section of esphome:

esphome:
  name: $devicename
  comment: ${device_description}
  on_boot:
    priority: 250.0 # 250=after sensors are set up; when wifi is initializing
    then:
      - lambda: id(my_sensor).publish_state('42.0');