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);
}
}






