ESP8266 Ping Tester – Evolution

I just finished writing about my ESP8266+ESPHome Ping Tester – and realised that, as I was only using 43% of RAM and 48% of FLASH memory – it would be a crime to stop there – hence this short article.

ESP8266+ESPHome Ping Tester - Evolution

The device reads pings from the network and thanks to an ESPHome WebUI (i.e. web page on the device, accessible via a browser) it is easy to select both internal and external IP addresses to ping. You get visible ping time, IP adress being pinged and a fail-count which again can be reset at any time on the WebUI.

And all of this from a device that costs less than many ESP32s, even including the WS2812 LED and standard I2c SSD1306 128*64 OLED display. I as expecting some review items to arrive about now but when they didn’t turn up I started to wonder if this device could be improved in the meantime.

Sure enough, right now I’ve added a 200-ping history, held in the device (time, IP, ping-time for each ping). The pings are held in RAM and have taken the used-RAM up from around 43% to 47%, the FLASH usage increase being hardly noticeable at 48% up from just over 47%. The information is retrieved from any old MQTT client.

This of course demands a new control on the WebUI to pause queue build-up while it is being read hence a new photo of the WebUI. I figured I’d better leave the original project as-is and put the changes and additions in here. Bear in mind, once set up, this doesn’t need a PC with ESPHome – it runs all by itself.

ESP8266+ESPHome Ping Tester - Evolution

I’ve no doubt at some point I’ll get the urge to add more – all that spare memory doing nothing…

Meanwhile – the device is set up to use my MQTT broker at 192.168.1.20 and with my login credentials. When you compile this – check out your secrets file in ESPHome (not Home Assistant, the secrets file in the ESPHome folder).

Just as an example, this is my secrets file (details altered to protect the innocent) – I only have one password to serve multiple SSIDs as it’s a large house.

wifi_ssid: "myoffice"
wifi_password: "xxxxxxxx"
uk_wifi_ssid: "office"
uk_wifi_password: "xxxxxxxxy"
wifi_ssid2: "black"
wifi_ssid3: "mlo"
wifi_ssid4: "outside"
wifi_ssid5: "wififorus"
wifi_ssid6: "petes"
wifi_ssid7: "comfast"

mqtt_broker: 192.168.1.20
mqtt_username: aaaaa
mqtt_password: bbbbbb
abrobot_ota_password: ccccccccccccccccc
ttgo_ota_password: ccccccccccc

car_data_write_key: "blah1231blahblah"
car_data_read_key: "moreblah123blahblah"

And now, the YAML code for the latest Ping Tester

substitutions:
  device_name: oled-test
  friendly_name: ESP8266 Ping Tester with ESPHome
  device_version: "0.14"
  code_source: "https://tech.scargill.net"

esphome:
  name: ${device_name}
  friendly_name: ${friendly_name}

  libraries:
    - ESPping@1.0.5

  includes:
    - <ESPping.h>

  on_boot:
    priority: -100
    then:
      - light.turn_on:
          id: rgb_led
          red: 100%
          green: 40%
          blue: 0%

esp8266:
  board: nodemcuv2
  restore_from_flash: true

logger:
  level: DEBUG

api:
  reboot_timeout: 0s

mqtt:
  broker: !secret mqtt_broker
  username: !secret mqtt_username
  password: !secret mqtt_password
  id: mqtt_client
  discovery: false
  discover_ip: false

web_server:
  version: 3

ota:
  - platform: esphome

wifi:
  networks:
    - ssid: !secret wifi_ssid
      password: !secret wifi_password
    - ssid: !secret wifi_ssid2
      password: !secret wifi_password
    - ssid: !secret wifi_ssid3
      password: !secret wifi_password
    - ssid: !secret wifi_ssid4
      password: !secret wifi_password
    - ssid: !secret wifi_ssid5
      password: !secret wifi_password

  power_save_mode: none
  post_connect_roaming: true

  ap:
    ssid: "${device_name} Fallback"
    password: "12345678"

captive_portal:

preferences:
  flash_write_interval: 10s


# ==================================================
# GLOBALS
# ==================================================

globals:

  - id: ping_state
    type: int
    restore_value: no
    initial_value: "0"

  - id: ping_ms
    type: int
    restore_value: no
    initial_value: "0"

  - id: heartbeat
    type: bool
    restore_value: no
    initial_value: "false"

  # Persistent ping target IP
  - id: ip1
    type: int
    restore_value: yes
    initial_value: "192"

  - id: ip2
    type: int
    restore_value: yes
    initial_value: "168"

  - id: ip3
    type: int
    restore_value: yes
    initial_value: "1"

  - id: ip4
    type: int
    restore_value: yes
    initial_value: "1"

  # Persistent failure counter
  - id: failed_ping_count
    type: uint32_t
    restore_value: yes
    initial_value: "0"

  # Reset switch state
  - id: reset_switch_state
    type: bool
    initial_value: 'false'

  # In-RAM ping history. These arrays are deliberately not restored to flash.
  - id: history_sequence
    type: uint32_t[200]
    restore_value: no

  - id: history_ms
    type: uint16_t[200]
    restore_value: no

  - id: history_status
    type: uint8_t[200]
    restore_value: no

  - id: history_ip1
    type: uint8_t[200]
    restore_value: no

  - id: history_ip2
    type: uint8_t[200]
    restore_value: no

  - id: history_ip3
    type: uint8_t[200]
    restore_value: no

  - id: history_ip4
    type: uint8_t[200]
    restore_value: no

  - id: history_index
    type: uint8_t
    restore_value: no
    initial_value: '0'

  - id: history_count
    type: uint16_t
    restore_value: no
    initial_value: '0'

  - id: history_sequence_number
    type: uint32_t
    restore_value: no
    initial_value: '0'

  - id: history_paused
    type: bool
    restore_value: no
    initial_value: 'false'


# ==================================================
# FONT
# ==================================================

font:

  - file: "gfonts://Roboto"
    id: font_small
    size: 12

  - file: "gfonts://Roboto"
    id: font_heading
    size: 14


# ==================================================
# I2C OLED
# ==================================================

i2c:
  sda: D2
  scl: D1


# ==================================================
# OLED DISPLAY
# ==================================================

display:
  - platform: ssd1306_i2c
    model: "SSD1306 128x64"
    address: 0x3C
    update_interval: 2s

    lambda: |-

      // OLED disabled
      if (!id(oled_display).state) {
        it.fill(COLOR_OFF);
        return;
      }

      // Header
      it.print(0, 0, id(font_heading), "PING TEST v${device_version}");
      it.horizontal_line(0,15,128);
      // Heartbeat
      if (id(heartbeat)) {
        it.print(118, 0, id(font_small), "*");
      }

      // Ping status
      if (id(ping_state) == 0) {

        it.print(0, 20, id(font_small), "SETTING UP");

      } else if (id(ping_state) == 1) {

        it.printf(
          0, 20,
          id(font_small),
          "OK   %d ms",
          id(ping_ms)
        );

      } else {

        if (id(ping_ms) > 500) {

          it.printf(
            0, 20,
            id(font_small),
            "FAILED %d ms",
            id(ping_ms)
          );

        } else {

          it.print(0, 20, id(font_small), "** FAILED **");

        }
      }

      // Target IP
      it.printf(
        0, 36,
        id(font_small),
        "%d.%d.%d.%d",
        id(ip1),
        id(ip2),
        id(ip3),
        id(ip4)
      );

      // Persistent failure counter
      char fail_text[20];

      sprintf(
        fail_text,
        "Failures: %d",
        (int) id(failed_ping_count)
      );

      int fail_width;
      int x_offset;
      int baseline;
      int height;

      id(font_small).measure(
        fail_text,
        &fail_width,
        &x_offset,
        &baseline,
        &height
      );

      it.print(
        128 - fail_width,
        50,
        id(font_small),
        fail_text
      );


# ==================================================
# RGB LED
# ==================================================

light:
  - platform: neopixelbus
    id: rgb_led
    type: GRB
    variant: WS2812
    pin: D6
    num_leds: 1
    name: "RGB LED"
    gamma_correct: 1.0

    initial_state:
      brightness: 26%

    restore_state: all


# ==================================================
# TEXT SENSORS
# ==================================================

text_sensor:

  - platform: template
    name: "Firmware Version"
    lambda: |-
      return {"${device_version}"};
    update_interval: 60s

  - platform: template
    name: "code_source"
    lambda: |-
      return {"${code_source}"};
    update_interval: 60s


# ==================================================
# PING TARGET DROPDOWN
# ==================================================

select:

  - platform: template
    name: "Ping Target"
    id: ping_target
    optimistic: true
    restore_value: true

    initial_option: "Manual / Custom"

    options:

      - "Manual / Custom"

      - "Google DNS - 8.8.8.8"
      - "Google DNS - 8.8.4.4"

      - "Cloudflare - 1.1.1.1"
      - "Cloudflare - 1.0.0.1"

      - "Quad9 - 9.9.9.9"
      - "Quad9 - 149.112.112.112"

      - "OpenDNS - 208.67.222.222"
      - "OpenDNS - 208.67.220.220"

      - "AdGuard - 94.140.14.14"
      - "AdGuard - 94.140.15.15"

      - "Router - 192.168.1.1"
      - "Router - 192.168.0.1"
      - "Router - 192.168.1.254"
      - "Router - 192.168.0.254"

      - "Local - 10.0.0.1"
      - "Local - 10.10.0.1"
      - "Local - 10.10.10.1"

      - "Local - 172.16.0.1"
      - "Local - 172.16.1.1"

    on_value:
      then:

        - lambda: |-

            if (x == "Google DNS - 8.8.8.8") {

              id(ip1) = 8;
              id(ip2) = 8;
              id(ip3) = 8;
              id(ip4) = 8;

            } else if (x == "Google DNS - 8.8.4.4") {

              id(ip1) = 8;
              id(ip2) = 8;
              id(ip3) = 4;
              id(ip4) = 4;

            } else if (x == "Cloudflare - 1.1.1.1") {

              id(ip1) = 1;
              id(ip2) = 1;
              id(ip3) = 1;
              id(ip4) = 1;

            } else if (x == "Cloudflare - 1.0.0.1") {

              id(ip1) = 1;
              id(ip2) = 0;
              id(ip3) = 0;
              id(ip4) = 1;

            } else if (x == "Quad9 - 9.9.9.9") {

              id(ip1) = 9;
              id(ip2) = 9;
              id(ip3) = 9;
              id(ip4) = 9;

            } else if (x == "Quad9 - 149.112.112.112") {

              id(ip1) = 149;
              id(ip2) = 112;
              id(ip3) = 112;
              id(ip4) = 112;

            } else if (x == "OpenDNS - 208.67.222.222") {

              id(ip1) = 208;
              id(ip2) = 67;
              id(ip3) = 222;
              id(ip4) = 222;

            } else if (x == "OpenDNS - 208.67.220.220") {

              id(ip1) = 208;
              id(ip2) = 67;
              id(ip3) = 220;
              id(ip4) = 220;

            } else if (x == "AdGuard - 94.140.14.14") {

              id(ip1) = 94;
              id(ip2) = 140;
              id(ip3) = 14;
              id(ip4) = 14;

            } else if (x == "AdGuard - 94.140.15.15") {

              id(ip1) = 94;
              id(ip2) = 140;
              id(ip3) = 15;
              id(ip4) = 15;

            } else if (x == "Router - 192.168.1.1") {

              id(ip1) = 192;
              id(ip2) = 168;
              id(ip3) = 1;
              id(ip4) = 1;

            } else if (x == "Router - 192.168.0.1") {

              id(ip1) = 192;
              id(ip2) = 168;
              id(ip3) = 0;
              id(ip4) = 1;

            } else if (x == "Router - 192.168.1.254") {

              id(ip1) = 192;
              id(ip2) = 168;
              id(ip3) = 1;
              id(ip4) = 254;

            } else if (x == "Router - 192.168.0.254") {

              id(ip1) = 192;
              id(ip2) = 168;
              id(ip3) = 0;
              id(ip4) = 254;

            } else if (x == "Local - 10.0.0.1") {

              id(ip1) = 10;
              id(ip2) = 0;
              id(ip3) = 0;
              id(ip4) = 1;

            } else if (x == "Local - 10.10.0.1") {

              id(ip1) = 10;
              id(ip2) = 10;
              id(ip3) = 0;
              id(ip4) = 1;

            } else if (x == "Local - 10.10.10.1") {

              id(ip1) = 10;
              id(ip2) = 10;
              id(ip3) = 10;
              id(ip4) = 1;

            } else if (x == "Local - 172.16.0.1") {

              id(ip1) = 172;
              id(ip2) = 16;
              id(ip3) = 0;
              id(ip4) = 1;

            } else if (x == "Local - 172.16.1.1") {

              id(ip1) = 172;
              id(ip2) = 16;
              id(ip3) = 1;
              id(ip4) = 1;
            }

        - component.update: ping_ip1
        - component.update: ping_ip2
        - component.update: ping_ip3
        - component.update: ping_ip4


# ==================================================
# PING IP ADDRESS
# ==================================================

number:

  - platform: template
    name: "Ping IP 1"
    id: ping_ip1
    min_value: 0
    max_value: 255
    step: 1
    mode: box

    lambda: |-
      return id(ip1);

    set_action:
      - lambda: |-
          id(ip1) = (int)x;

      - select.set:
          id: ping_target
          option: "Manual / Custom"

  - platform: template
    name: "Ping IP 2"
    id: ping_ip2
    min_value: 0
    max_value: 255
    step: 1
    mode: box

    lambda: |-
      return id(ip2);

    set_action:
      - lambda: |-
          id(ip2) = (int)x;

      - select.set:
          id: ping_target
          option: "Manual / Custom"

  - platform: template
    name: "Ping IP 3"
    id: ping_ip3
    min_value: 0
    max_value: 255
    step: 1
    mode: box

    lambda: |-
      return id(ip3);

    set_action:
      - lambda: |-
          id(ip3) = (int)x;

      - select.set:
          id: ping_target
          option: "Manual / Custom"

  - platform: template
    name: "Ping IP 4"
    id: ping_ip4
    min_value: 0
    max_value: 255
    step: 1
    mode: box

    lambda: |-
      return id(ip4);

    set_action:
      - lambda: |-
          id(ip4) = (int)x;

      - select.set:
          id: ping_target
          option: "Manual / Custom"


# ==================================================
# PING FAILURE COUNTER SENSOR
# ==================================================

sensor:

  - platform: template
    name: "Ping Failures"
    id: failed_ping_counter_sensor
    accuracy_decimals: 0
    update_interval: 5s

    lambda: |-
      return (float) id(failed_ping_count);


  - platform: template
    name: "Ping History Length"
    id: ping_history_length_sensor
    accuracy_decimals: 0
    update_interval: 5s

    lambda: |-
      return (float) id(history_count);


# ==================================================
# OLED ON/OFF SWITCH
# ==================================================

switch:

  - platform: template
    name: "OLED Display"
    id: oled_display

    restore_mode: RESTORE_DEFAULT_ON

    optimistic: true

    turn_on_action:
      - lambda: |-
          // OLED enabled

    turn_off_action:
      - lambda: |-
          // OLED disabled


  - platform: template
    name: "Reset Ping Counter"
    icon: "mdi:gesture-tap"
    id: this_dummy_switch_id

    lambda: |-
      return id(reset_switch_state);

    turn_on_action:

      - globals.set:
          id: reset_switch_state
          value: 'true'

      - lambda: |-
          id(failed_ping_count) = 0;

      - component.update: failed_ping_counter_sensor

      - delay: 150ms

      - switch.turn_off: this_dummy_switch_id

    turn_off_action:

      - globals.set:
          id: reset_switch_state
          value: 'false'


  - platform: template
    name: "Clear Ping History"
    icon: "mdi:delete-sweep"
    id: clear_ping_history
    optimistic: true

    turn_on_action:
      - lambda: |-
          id(history_index) = 0;
          id(history_count) = 0;
          id(history_sequence_number) = 0;

          char topic[24];
          for (int n = 0; n < 200; n++) {
            snprintf(topic, sizeof(topic), "pinger/%d", n + 1);
            id(mqtt_client).publish(topic, "", 0, 0, true);
          }

          id(mqtt_client).publish("pinger/count", "0", 1, 0, true);
          if (id(history_paused)) {
            id(mqtt_client).publish("pinger/status", "PAUSED", 6, 0, true);
          } else {
            id(mqtt_client).publish("pinger/status", "RUNNING", 7, 0, true);
          }

      - component.update: ping_history_length_sensor
      - delay: 150ms
      - switch.turn_off: clear_ping_history

    turn_off_action:
      - lambda: |-
          // Momentary switch.


  - platform: template
    name: "Pause Ping History"
    id: pause_ping_history
    optimistic: true

    turn_on_action:
      - lambda: |-
          id(history_paused) = true;

          char topic[24];
          char payload[96];

          // Publish a retained snapshot: newest entry is pinger/1.
          for (int n = 0; n < id(history_count); n++) {
            int idx = ((int)id(history_index) + 200 - 1 - n) % 200;
            snprintf(topic, sizeof(topic), "pinger/%d", n + 1);

            if (id(history_status)[idx] == 1) {
              snprintf(payload, sizeof(payload),
                "#%lu | %d.%d.%d.%d | %d ms | OK",
                (unsigned long)id(history_sequence)[idx],
                (int)id(history_ip1)[idx], (int)id(history_ip2)[idx],
                (int)id(history_ip3)[idx], (int)id(history_ip4)[idx],
                (int)id(history_ms)[idx]);
            } else if (id(history_status)[idx] == 2) {
              snprintf(payload, sizeof(payload),
                "#%lu | %d.%d.%d.%d | %d ms | SLOW",
                (unsigned long)id(history_sequence)[idx],
                (int)id(history_ip1)[idx], (int)id(history_ip2)[idx],
                (int)id(history_ip3)[idx], (int)id(history_ip4)[idx],
                (int)id(history_ms)[idx]);
            } else {
              snprintf(payload, sizeof(payload),
                "#%lu | %d.%d.%d.%d | FAILED",
                (unsigned long)id(history_sequence)[idx],
                (int)id(history_ip1)[idx], (int)id(history_ip2)[idx],
                (int)id(history_ip3)[idx], (int)id(history_ip4)[idx]);
            }

            id(mqtt_client).publish(topic, payload, strlen(payload), 0, true);
          }

          // Clear any old retained entries beyond the current history length.
          for (int n = id(history_count); n < 200; n++) {
            snprintf(topic, sizeof(topic), "pinger/%d", n + 1);
            id(mqtt_client).publish(topic, "", 0, 0, true);
          }

          snprintf(payload, sizeof(payload), "%u", id(history_count));
          id(mqtt_client).publish("pinger/count", payload, strlen(payload), 0, true);
          id(mqtt_client).publish("pinger/status", "PAUSED", 6, 0, true);

    turn_off_action:
      - lambda: |-
          id(history_paused) = false;

          char topic[24];
          char payload[96];

          // Publish the current history snapshot and resume live updates.
          for (int n = 0; n < id(history_count); n++) {
            int idx = ((int)id(history_index) + 200 - 1 - n) % 200;
            snprintf(topic, sizeof(topic), "pinger/%d", n + 1);

            if (id(history_status)[idx] == 1) {
              snprintf(payload, sizeof(payload),
                "#%lu | %d.%d.%d.%d | %d ms | OK",
                (unsigned long)id(history_sequence)[idx],
                (int)id(history_ip1)[idx], (int)id(history_ip2)[idx],
                (int)id(history_ip3)[idx], (int)id(history_ip4)[idx],
                (int)id(history_ms)[idx]);
            } else if (id(history_status)[idx] == 2) {
              snprintf(payload, sizeof(payload),
                "#%lu | %d.%d.%d.%d | %d ms | SLOW",
                (unsigned long)id(history_sequence)[idx],
                (int)id(history_ip1)[idx], (int)id(history_ip2)[idx],
                (int)id(history_ip3)[idx], (int)id(history_ip4)[idx],
                (int)id(history_ms)[idx]);
            } else {
              snprintf(payload, sizeof(payload),
                "#%lu | %d.%d.%d.%d | FAILED",
                (unsigned long)id(history_sequence)[idx],
                (int)id(history_ip1)[idx], (int)id(history_ip2)[idx],
                (int)id(history_ip3)[idx], (int)id(history_ip4)[idx]);
            }

            id(mqtt_client).publish(topic, payload, strlen(payload), 0, true);
          }

          for (int n = id(history_count); n < 200; n++) {
            snprintf(topic, sizeof(topic), "pinger/%d", n + 1);
            id(mqtt_client).publish(topic, "", 0, 0, true);
          }

          snprintf(payload, sizeof(payload), "%u", id(history_count));
          id(mqtt_client).publish("pinger/count", payload, strlen(payload), 0, true);
          id(mqtt_client).publish("pinger/status", "RUNNING", 7, 0, true);


# ==================================================
# PING TEST
# ==================================================

interval:

  - interval: 5s

    then:

      - lambda: |-

          id(heartbeat) = !id(heartbeat);

          IPAddress target(
            id(ip1),
            id(ip2),
            id(ip3),
            id(ip4)
          );

          // History status: 1=OK, 2=SLOW, 3=FAILED.
          uint8_t history_result = 3;

          if (Ping.ping(target, 3)) {

            id(ping_ms) = (int) Ping.averageTime();

            bool was_running = (id(ping_state) != 0);

            // Count successful pings taking longer than 500ms.
            // Do not count the first successful ping after startup.
            if (was_running && id(ping_ms) > 500) {
              id(failed_ping_count)++;
            }

            if (id(ping_ms) > 500) {
              id(ping_state) = 2;
              history_result = 2;
            } else {
              id(ping_state) = 1;
              history_result = 1;
            }

            auto call = id(rgb_led).turn_on();

            bool local_target =
              (id(ip1) == 192 &&
               id(ip2) == 168);

            if (local_target) {

              if (id(ping_ms) < 20) {

                call.set_rgb(0.0, 1.0, 0.0);

              } else if (id(ping_ms) < 50) {

                call.set_rgb(0.5, 1.0, 0.0);

              } else if (id(ping_ms) <= 100) {

                call.set_rgb(1.0, 1.0, 0.0);

              } else {

                call.set_rgb(1.0, 0.4, 0.0);
              }

            } else {

              if (id(ping_ms) < 75) {

                call.set_rgb(0.0, 1.0, 0.0);

              } else if (id(ping_ms) < 125) {

                call.set_rgb(0.5, 1.0, 0.0);

              } else if (id(ping_ms) <= 175) {

                call.set_rgb(1.0, 1.0, 0.0);

              } else {

                call.set_rgb(1.0, 0.4, 0.0);
              }
            }

            call.perform();

          } else {

            // Complete ping failure.

            if (id(ping_state) == 0) {

              // First ping failed.
              // Establish that the tester is now running,
              // but don't count this initial failure.

              id(ping_state) = 2;
              id(ping_ms) = 0;

              auto call = id(rgb_led).turn_on();
              call.set_rgb(1.0, 0.0, 0.0);
              call.perform();

            } else {

              // Subsequent complete ping failure.
              // Count it as a failure.

              id(failed_ping_count)++;

              id(ping_state) = 2;
              id(ping_ms) = 0;

              auto call = id(rgb_led).turn_on();
              call.set_rgb(1.0, 0.0, 0.0);
              call.perform();
            }
          }

          // Store this result in the fixed-size RAM ring buffer.
          uint8_t h = id(history_index);
          id(history_sequence_number)++;
          id(history_sequence)[h] = id(history_sequence_number);
          id(history_ms)[h] = (id(ping_ms) < 65535) ? id(ping_ms) : 65535;
          id(history_status)[h] = history_result;
          id(history_ip1)[h] = id(ip1);
          id(history_ip2)[h] = id(ip2);
          id(history_ip3)[h] = id(ip3);
          id(history_ip4)[h] = id(ip4);

          id(history_index) = (h + 1) % 200;
          if (id(history_count) < 200) {
            id(history_count)++;
          }

          // While running, publish only the newest result and small status values.
          // The full 200-entry retained snapshot is published when paused.
          if (!id(history_paused)) {
            char latest[96];

            if (history_result == 1) {
              snprintf(latest, sizeof(latest),
                "#%lu | %d.%d.%d.%d | %d ms | OK",
                (unsigned long)id(history_sequence_number),
                id(ip1), id(ip2), id(ip3), id(ip4), id(ping_ms));
            } else if (history_result == 2) {
              snprintf(latest, sizeof(latest),
                "#%lu | %d.%d.%d.%d | %d ms | SLOW",
                (unsigned long)id(history_sequence_number),
                id(ip1), id(ip2), id(ip3), id(ip4), id(ping_ms));
            } else {
              snprintf(latest, sizeof(latest),
                "#%lu | %d.%d.%d.%d | FAILED",
                (unsigned long)id(history_sequence_number),
                id(ip1), id(ip2), id(ip3), id(ip4));
            }

            id(mqtt_client).publish("pinger/latest", latest, strlen(latest), 0, false);

            char count_text[12];
            snprintf(count_text, sizeof(count_text), "%u", id(history_count));
            id(mqtt_client).publish("pinger/count", count_text, strlen(count_text), 0, true);
            id(mqtt_client).publish("pinger/status", "RUNNING", 7, 0, true);
          }

To get the history info from MQTT – the following subscribes are available:

pinger/1
pinger/2
pinger/3
…
pinger/200
pinger/latest
pinger/count
pinger/status
For a quick check just subscribe to pinger/#

Leave a Reply

Your email address will not be published. Required fields are marked *

Leave the field below empty!

Are you human? Please solve:Captcha


The maximum upload file size: 512 MB. You can upload: image, audio, video, document, spreadsheet, interactive, text, archive, code, other. Links to YouTube, Facebook, Twitter and other services inserted in the comment text will be automatically embedded. Drop file here