ESP heartbeat?

Does anyone know of a heartbeat capability in ESPhome?
I am familiar with the binary_sensor of the “status” platform

  - platform: status
    name: "${hostname}_status"

But I’d like to get an indicator that shows if my code (the loop) that runs on the board is functioning…something like an input boolean that is turned on and off every x-seconds.
I got close by (ab-)using a GPIO port of the board, but I was wondering if this could be done without having to sacrifice a GPIO port for it.
This is what I have:

# Heartbeat
  - interval: 10s
      - switch.turn_on: d6
      - delay: 5s
      - switch.turn_off: d6

Depends on what is outside of your loop and what you want to happen when it breaks.
If you have the esphome connected to a ha instance you could send regular events by API or mqtt and check them there.

Thank you @elfrinjo

that is exactly what I would like to do…
Do you happen to have any example code? I tried with importing an “input boolean” from HA, but I got stuck

Last edit, this time with a proper editor…

When connected via api, you can create events for the homeassistant event bus with this code on the esphome-device. Ideally, this would include some actual health-checks.

  - interval: 30s
      - homeassistant.event:
          event: esphome.myImportantEsphomeDevice.stillAlive

Next, these events can be received by an automation in homeassistant and update a date/time helper (called myImportantEsphomeDevice.lastHealthChec) with the current timestamp.

alias: Update Healthcheck for myImportantEsphomeDevice
  - platform: event
    event_type: esphome.myImportantEsphomeDevice.stillAlive
condition: []
  - service: input_datetime.set_datetime
      entity_id: input_datetime.myimportantesphomedevice_lasthealthcheck
      datetime: '{{ now() }}'
mode: single

Andy finally, a binary sensor can check the age of the timestamp:

  - binary_sensor:
      - name: "myimportantesphomedevice_lasthealthcheck older than 60 seconds"
        state: "{{ as_timestamp(now()) - as_timestamp(strptime(states.input_datetime.myimportantesphomedevice_lasthealthcheck.state, '%Y-%m-%d  %H:%M:%S')) > 60 }}"

Perfect !
Danke sehr @elfrinjo
The thing that I was missing was homeassistant.event

This is fantastic, thanks! I just wanted to add that it nice to be able to use the Developer Tools to listen to * events to see what’s going on.

Question for you and the OP @chrisV : What do you think about using the uptime sensor to solve your problem?

  - platform: uptime
    name: Uptime Sensor
    update_interval: 30s

It takes the update_interval argument, which serves as a heartbeat, and gives you the uptime as well, which is useful in this sort of situation in case there was a reboot.

Does the uptime sensor “shows if my code (the loop) that runs on the board is functioning” sufficiently?

I also want to throw in the very valuable debug component which allows to actually print the loop time, free heap and other useful metrics :muscle:

Thanks for the tip about the debug component! It would be very helpful to know why the device reset, for example.

I’m getting a strange error when adding the component:

Compiling /data/s3-dev-kit-3/.pioenvs/s3-dev-kit-3/src/esphome/components/debug/debug_component.cpp.o
In file included from /data/cache/platformio/packages/framework-arduinoespressif32/tools/sdk/esp32s3/include/esp_rom/include/esp32/rom/rtc.h:18,
                 from src/esphome/components/debug/debug_component.cpp:15:
/data/cache/platformio/packages/framework-arduinoespressif32/tools/sdk/esp32s3/include/esp_rom/include/esp32/rom/ets_sys.h:29:2: error: #error "This header should only be included when building for ESP32"
 #error "This header should only be included when building for ESP32"

Could it be this component doesn’t support ESP32S3?
Or is it a bug?

Argh, I have my answer: Debug Component doesn't work on ESP32-S2 and ESP32-S3 · Issue #3433 · esphome/issues · GitHub

Pitching in my solution too, in case it’s useful for someone.

The requirements were to send heartbeats to

  1. a self-hosted instance of
  2. a self-hosted instance of Uptime Kuma
  3. a specific MQTT topic, with the free heap as payload

Relevant parts of the config looks like below. Adapt settings as needed to your local config.
Settings below have been obfuscated a bit.

  - platform: template
    name: "Free heap"
    lambda: |-
      int freeHeap = ESP.getFreeHeap();
      return freeHeap / 1024.0;
    unit_of_measurement: "kB"
    icon: mdi:memory
    entity_category: "diagnostic"
    id: free_heap

  topic_prefix: sometopic/sensor/my-fine-device/data
  discovery: false
  broker: <ip of MQTT broker>
  port: <port of MQTT broker>
    topic: sometopic/sensor/my-fine-device/status
    payload: online
    topic: sometopic/sensor/my-fine-device/status
    payload: offline

  useragent: esphome/my-fine-device
  timeout: 10s

  # Send heartbeat
  - interval: 1min
      # Publish free heap as heartbeat to MQTT
      - mqtt.publish:
          topic: sometopic/sensor/my-fine-device/heartbeat
          payload: !lambda |-
            char buf[25];
            sprintf(buf, "%1.3f", id(free_heap).state);
            return ((std::string) buf).c_str();
      # Send heartbeat to healthchecks
      - http_request.get: http://<IP where healthchecks is running>:<port>/ping/23a8a195-c706-4b06-92ec-7695a730f18d
      # Send heartbeat to Kuma
      - http_request.get: http://<IP where Kuma is running>:<port>/api/push/fKoBnnpWQ0?status=up&msg=OK&ping=

You also have to create the appropriate tests in Healthchecks and Kuma, and adapt the URLs above wrt to the URLs generated by the two monitoring tools.

Works really well, looks like both ESP8266 and ESP32 handles this nicely also over time.

The Kuma status page gives good overview.
Kuma and both integrate with tons of different alerting channels, so it’s possible to forward device-is-down messages as needed.

1 Like