Waveshare Epaper ESPHOME and Mqtt Notification over secure mqtt

Last Updated or created 2024-02-22

UPDATE: AccessPoint on Arduino implemented with captive portal for Wifi Configuration

Got my Waveshare Epaper Cloud running on ESPHome

This is a Epaper display with a 2000mAh Lipo and a passive buzzer.
Running parts of my Smoker monitor.

Below a little movie clip with RTTTL sound notification.
(Send from Home Assistant)
B.t.w. RTTTL are those ringtones we used to have. (Ring Tone Text Transfer Language)

Sending from HA

Parts of the ESPHOME Yaml
NOTE: For the time, you need the time integration to get hours:minutes as a sensor!

esphome:
  name: epaperesp32

esp32:
  board: esp32dev
  framework:
    type: arduino

# Enable logging
logger:

# Enable Home Assistant API
api:
  services:
    - service: play_rtttl
      variables:
        song_str: string
      then:
        - rtttl.play:
            rtttl: !lambda 'return song_str;'

output:
  - platform: ledc
    pin: GPIO22
    id: rtttl_out

rtttl:
  output: rtttl_out
  on_finished_playback:
    - logger.log: 'Song ended!'

ota:
  password: "xxxxxxxxxxxxxxxxxxxxxxxxxxx"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Epaperesp32 Fallback Hotspot"
    password: "xxxxxxxxxxxxxxxxx"

captive_portal:

font:
  - file: 'fonts/tahoma.ttf'
    id: font1
    size: 16
  - file: 'fonts/tahoma.ttf'
    id: font2
    size: 32

sensor:
  - platform: adc
    pin: GPIO36
    name: "epaperesp32 Battery voltage"
    id: battery_voltage
    icon: mdi:battery
    device_class: voltage
    attenuation: auto 
    filters:
     - multiply: 3
    update_interval: 60s

text_sensor:
  - platform: homeassistant
    entity_id: sensor.bbqenv
    name: "mystate"
    id: mystate
    internal: true
  - platform: homeassistant
    entity_id: sensor.bbqcore
    name: "mystate1"
    id: mystate1
    internal: true
  - platform: homeassistant
    entity_id: sensor.time
    name: "mytime"
    id: mytime
    internal: true

spi:
  clk_pin: GPIO13
  mosi_pin: GPIO14

binary_sensor:
  - platform: gpio
    pin:
      number: GPIO12
      inverted: true 
      mode:          
        input: true
        pullup: true
    name: "epaperesp32 button"
    filters:
      - delayed_on: 50ms
    on_press:
      - logger.log: "Button pressed"

display:
  - platform: waveshare_epaper
    cs_pin: GPIO15
    dc_pin: GPIO27
    busy_pin: GPIO25
    reset_pin: GPIO26
    model: 2.13in-ttgo
    rotation: 270
    full_update_every: 12
    update_interval: 10s
    lambda: |-
      it.print(0, 0, id(font2), "BBQ Meter V3");
      it.printf( 35, 32, id(font2), "%s", id(mystate).state.c_str());
      it.printf( 155, 32, id(font2), "%s", id(mystate1).state.c_str());

MQTT Notifier over Internet

This is part of a test where my friends and me can have notifications LEDs over the internet.

Using certificate parts from:
Controlling the led will be done using Mattermost webhooks, or slashcommand with custom scripting.
(Mattermost is my own hosted chat server)

I flashed a Wemos with below code:
(Rotary/display/button part removed.)

#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <time.h>
#include <PubSubClient.h>
#include <Adafruit_NeoPixel.h>

#define encoderCLK 5   //D1
#define encoderDT 4    //D2
#define rgbled D4       //D4

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(1, rgbled, NEO_RGB + NEO_KHZ400);

int servoAngle = 0;
int crntCLK;
int prvsCLK;

String myString;
char ang[50];


#ifndef SECRET
const char ssid[] = "MYSSID";
const char pass[] = "MYPASS";

#define HOSTNAME "henrimqtt"

const char MQTT_HOST[] = "www.henriaanstoot.nl";
const int MQTT_PORT = 9883;
const char MQTT_USER[] = "xxxxxx"; // leave blank if no credentials used
const char MQTT_PASS[] = "xxxxxx"; // leave blank if no credentials used

const char MQTT_SUB_TOPIC[] = "notification/" HOSTNAME "/in";
const char MQTT_PUB_TOPIC[] = "notification/" HOSTNAME "/out";
const char MQTT_PUB_TOPIC_angle[] = "notification/" HOSTNAME "/send";

#ifdef CHECK_CA_ROOT
static const char digicert[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
MIIFtTCCA52gAwIBAgIUXEEQRLHhYox8a95YiAYX/wQ/XeMwDQYJKoZIhvcNAQEN
//--------------- SNIP SNIP ... generated cert here
vht8GyCCgCH55Syvy9ls6gCyLjTT2rtllw==
-----END CERTIFICATE-----
)EOF";
    #endif

    #ifdef CHECK_PUB_KEY
    // Extracted by: openssl x509 -pubkey -noout -in ca.crt
    static const char pubkey[] PROGMEM = R"KEY(
    -----BEGIN PUBLIC KEY-----
    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    xxxxxxxx
    -----END PUBLIC KEY-----
    )KEY";
    #endif

    #ifdef CHECK_FINGERPRINT
        // Extracted by: openssl x509 -fingerprint -in ca.crt
    static const char fp[] PROGMEM = "AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD";
    #endif
#endif

//////////////////////////////////////////////////////

#if (defined(CHECK_PUB_KEY) and defined(CHECK_CA_ROOT)) or (defined(CHECK_PUB_KEY) and defined(CHECK_FINGERPRINT)) or (defined(CHECK_FINGERPRINT) and defined(CHECK_CA_ROOT)) or (defined(CHECK_PUB_KEY) and defined(CHECK_CA_ROOT) and defined(CHECK_FINGERPRINT))
  #error "cant have both CHECK_CA_ROOT and CHECK_PUB_KEY enabled"
#endif

BearSSL::WiFiClientSecure net;
PubSubClient client(net);

time_t now;
unsigned long lastMillis = 0;

void mqtt_connect()
{
  while (!client.connected()) {
    Serial.print("Time: ");
    Serial.print(ctime(&now));
    Serial.print("MQTT connecting ... ");
    if (client.connect(HOSTNAME, MQTT_USER, MQTT_PASS)) {
      Serial.println("connected.");
      client.subscribe(MQTT_SUB_TOPIC);
    } else {
      Serial.print("failed, status code =");
      Serial.print(client.state());
      Serial.println(". Try again in 5 seconds.");
      /* Wait 5 seconds before retrying */
      delay(5000);
    }
  }


}

void receivedCallback(char* topic, byte* payload, unsigned int length) {
    //  pixels.clear(); // Set all pixel colors to 'off'
 
  Serial.print("Received [");
  Serial.print(topic);
  Serial.print("]: ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
if (!strncmp((char *)payload, "0", length)) {
       pixels.setPixelColor(0, pixels.Color(0, 0, 0));
      pixels.show();   // Send the updated pixel colors to the hardware.
}
if (!strncmp((char *)payload, "1", length)) {
       pixels.setPixelColor(0, pixels.Color(150, 0, 0));
      pixels.show();   // Send the updated pixel colors to the hardware.
}
if (!strncmp((char *)payload, "2", length)) {
       pixels.setPixelColor(0, pixels.Color(0, 0, 150));
      pixels.show();   // Send the updated pixel colors to the hardware.
}
if (!strncmp((char *)payload, "3", length)) {
       pixels.setPixelColor(0, pixels.Color(0, 150, 0));
      pixels.show();   // Send the updated pixel colors to the hardware.
}
}

void setup()
{
  pixels.begin(); // INITIALIZE NeoPixel strip object (REQUIRED)

  pinMode (encoderCLK,INPUT_PULLUP);
  pinMode (encoderDT,INPUT_PULLUP);
  prvsCLK = digitalRead(encoderCLK);
  Serial.begin(115200);
  Serial.println();
  Serial.println();
  Serial.print("Attempting to connect to SSID: ");
  Serial.print(ssid);
  WiFi.hostname(HOSTNAME);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, pass);
  while (WiFi.status() != WL_CONNECTED)
  {
    Serial.print(".");
    delay(1000);
  }
  Serial.println("connected!");

  Serial.print("Setting time using SNTP");
  configTime(1 * 3600, 0, "pool.ntp.org", "time.nist.gov");
  now = time(nullptr);
  while (now < 1510592825) {
    delay(500);
    Serial.print(".");
    now = time(nullptr);
  }
  Serial.println("done!");
  struct tm timeinfo;
  gmtime_r(&now, &timeinfo);
  Serial.print("Current time: ");
  Serial.print(asctime(&timeinfo));

  #ifdef CHECK_CA_ROOT
    BearSSL::X509List cert(digicert);
    net.setTrustAnchors(&cert);
  #endif
  #ifdef CHECK_PUB_KEY
    BearSSL::PublicKey key(pubkey);
    net.setKnownKey(&key);
  #endif
  #ifdef CHECK_FINGERPRINT
    net.setFingerprint(fp);
  #endif
  #if (!defined(CHECK_PUB_KEY) and !defined(CHECK_CA_ROOT) and !defined(CHECK_FINGERPRINT))
    net.setInsecure();
  #endif

      
  client.setServer(MQTT_HOST, MQTT_PORT);
  client.setCallback(receivedCallback);
  mqtt_connect();
       pixels.setPixelColor(0, pixels.Color(0, 0, 0));
      pixels.show();   // Send the updated pixel colors to the hardware.

}

void loop()
{
   crntCLK = digitalRead(encoderCLK);

 if (crntCLK != prvsCLK){
      // If the encoderDT state is different than the encoderCLK state then the rotary encoder is rotating counterclockwise
        if (digitalRead(encoderDT) != crntCLK) {
          servoAngle ++;

        }
        else {
          servoAngle --;
         }
         Serial.println(servoAngle);
          String myString = String(servoAngle);
          myString.toCharArray(ang, myString.length() + 1);
          client.publish(MQTT_PUB_TOPIC_angle, ang, false);
 }
  prvsCLK = crntCLK;

  now = time(nullptr);
  if (WiFi.status() != WL_CONNECTED)
  {
    Serial.print("Checking wifi");
    while (WiFi.waitForConnectResult() != WL_CONNECTED)
    {
      WiFi.begin(ssid, pass);
      Serial.print(".");
      delay(10);
    }
    Serial.println("connected");
  }
  else
  {
    if (!client.connected())
    {
      mqtt_connect();
    }
    else
    {
      client.loop();
    }
  }

  if (millis() - lastMillis > 5000) {
    lastMillis = millis();
    client.publish(MQTT_PUB_TOPIC, ctime(&now), false);
  }
}

Leave a Reply

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