Skip to content

Notifications Module

The notifications module provides a pluggable, single-channel push-notification system for the ESP3D-X pendant firmware. When a notable event occurs — device boot, a manual command, or a gcode stream error — the module dispatches a short title + message to one externally configured service: Pushover, Email (SMTP/TLS), Telegram, IFTTT, WhatsApp, or Home Assistant.

Only one provider is active at a time. The active provider is selected at boot from NVS settings, instantiated by the ESP3DNotificationsService singleton, and remains live until end() is called or settings are reconfigured via [ESP610].

Feature guard: ESP3D_NOTIFICATIONS_FEATURE.


owns unique_ptr

sendHttpPost/Get

TLS handshake

SMTP commands

reads type + tokens

ESP3DNotificationsService

(singleton)

esp3dNotificationsService

INotificationProvider

(abstract interface)

HttpNotificationProvider

(shared HTTP/HTTPS base)

PushoverProvider

HTTPS POST

TelegramProvider

HTTPS POST

IFTTTProvider

HTTPS POST

WhatsAppProvider

HTTPS GET via CallMeBot

HomeAssistantProvider

HTTP POST (local LAN)

EmailNotificationProvider

SMTP via mbedTLS

(no HTTP base)

esp_http_client

(ESP-IDF)

mbedTLS

(ESP-IDF)

ESP3DSettings

(NVS)


owns (unique_ptr)

«abstract interface»

INotificationProvider

+send(title, message) : bool

+typeName() : const char

+getLastError() : ESP3DNotificationError

HttpNotificationProvider

#_lastError ESP3DNotificationError

#sendHttpPost(url, data, host, ssl, ct, auth) : bool

#sendHttpGet(url, host, ssl, auth) : bool

#mapStatusCode(code) : ESP3DNotificationError

+getLastError() : ESP3DNotificationError

PushoverProvider

-_token1 string

-_token2 string

+send(title, message) : bool

+typeName() : "pushover"

TelegramProvider

-_token1 string

-_token2 string

+send(title, message) : bool

+typeName() : "telegram"

#mapStatusCode(code) : ESP3DNotificationError

IFTTTProvider

-_token1 string

-_token2 string

+send(title, message) : bool

+typeName() : "IFTTT"

WhatsAppProvider

-_token1 string

-_token2 string

+send(title, message) : bool

+typeName() : "WhatsApp"

HomeAssistantProvider

-_token1 string

-_server string

-_port string

+send(title, message) : bool

+typeName() : "HomeAssistant"

EmailNotificationProvider

-_token1 string

-_token2 string

-_email string

-_server string

-_port string

-_method string

-_lastError ESP3DNotificationError

+send(title, message) : bool

+typeName() : "email"

+getLastError() : ESP3DNotificationError

-performTlsHandshake(ssl) : int

-writeSslAndGetResponse(ssl, buf, len) : int

-writeTlsAndGetResponse(sock, buf, len) : int

ESP3DNotificationsService

-_started bool

-_autonotification bool

-_notificationType ESP3DNotificationType

-_lastError ESP3DNotificationError

-_provider unique_ptr<INotificationProvider>

+begin(sendAutoNotificationMsg) : bool

+end()

+sendMSG(title, message) : bool

+sendAutoNotification(msg) : bool

+getTypeString() : const char

+getType() : ESP3DNotificationType

+started() : bool

+isAutonotification() : bool

+setAutonotification(value)

+getLastError() : ESP3DNotificationError


Enum valueESP3DNotificationTypeTransporttoken1token2token_setting (TS)
0none————
1pushoverHTTPS POST api.pushover.netuser keyapp token(unused)
2emailSMTP SSL (465) / STARTTLS (587)SMTP usernameSMTP passwordemail#server:port[:method]
3line(removed — gap preserved)———
4telegramHTTPS POST api.telegram.orgbot tokenchat id(unused)
5iftttHTTPS POST maker.ifttt.comevent namewebhook key(unused)
6whatsappHTTPS GET api.callmebot.comphone numberAPI key(unused)
7homeassistantHTTP POST (plain, local LAN)HA long-lived token(unused)server:port

⚠️ Enum value 3 was removed (LINE provider). The gap is intentional — persisted NVS values from older firmware may still contain 3. Do not reuse this value.


Setting indexSizeContent
esp3d_notification_typebyteESP3DNotificationType cast
esp3d_notification_token_164 B (SIZE_OF_SETTING_NOFIFICATION_T1)Primary credential (username, user key, bot token, phone …)
esp3d_notification_token_264 B (SIZE_OF_SETTING_NOFIFICATION_T2)Secondary credential (password, app token, chat id, API key …)
esp3d_notification_token_setting128 B (SIZE_OF_SETTING_NOFIFICATION_TS)Provider-specific extra config (see table above)
esp3d_auto_notificationbyte (bool)Send “online” message automatically at network boot

T1 and T2 are protected keys — they are scrambled in .ok config exports and never echoed back by [ESP610] GET queries.

All other providers

TS field ignored

HomeAssistant TS: server:port

server

:

port

Email TS: email#server:port[:method]

email

#

server

:

port

[:method]


yes

no

no

yes

Caller

(ESP600 cmd / gcode host / auto-notification)

esp3d_string::expandString()

expand %ESP_NAME% %ESP_IP% …

message

empty?

_lastError = empty_message

return false

esp3dWsWebUiService

.pushNotification()

guard: ESP3D_HTTP_FEATURE

esp3dXValues

.set_value(status_bar_label)

guard: ESP3D_HAS_STATUS_BAR

provider

configured

& started?

_provider->send(title, message)

return true

return send() result

Key invariant: The local UI echo (WebUI push + status bar) always fires regardless of provider state or send result. Even type=none will echo locally.


yes

no

pushover

telegram

ifttt

whatsapp

email

homeassistant

other

ok

fail

ok

fail

yes

no

begin(sendAutoNotificationMsg)

end()

reset _provider

_started = false

Read esp3d_notification_type

from NVS

type == none?

_started = true

return true

Read T1, T2, TS

from NVS (fixed-size buffers)

Switch on

provider type

parseEmailSettings(TS)

email#server:port[:method]

parseServerPort(TS)

server:port

make_unique EmailNotificationProvider

(T1, T2, email, server, port, method)

make_unique PushoverProvider(T1, T2)

make_unique TelegramProvider(T1, T2)

make_unique IFTTTProvider(T1, T2)

make_unique WhatsAppProvider(T1, T2)

make_unique HomeAssistantProvider

(T1, server, port)

end()

return false

Read esp3d_auto_notification

_autonotification = value

_started = true

sendAutoNotificationMsg

&& _autonotification?

sendAutoNotification

(ESP3D_NOTIFICATION_ONLINE)

return true


Unlike HTTP-based providers, EmailNotificationProvider implements a full SMTP conversation over mbedTLS directly, bypassing esp_http_client.

TLS fixes (a14):

  • Certificate bundle actually used. mbedtls_ssl_config_defaults() is now called before esp_crt_bundle_attach() (canonical ESP-IDF order). esp_crt_bundle_attach() installs its CA verify callback into the config, and the later mbedtls_ssl_config_defaults() call used to reset the config and silently wipe the bundle. The unused empty cacert chain was removed.
  • Verification failure is fatal. With VERIFY_REQUIRED, a non-zero verification result means the server could not be authenticated: the session is aborted (MBEDTLS_ERR_X509_CERT_VERIFY_FAILED, error log with the verification info) instead of continuing with a warning, which would silently expose the SMTP credentials to a man-in-the-middle.
SMTP ServermbedTLS (net + ssl)EmailNotificationProviderSMTP ServermbedTLS (net + ssl)EmailNotificationProvideralt[method == "SSL" (implicit TLS, e.g. port 465)][method == "TLS" (STARTTLS, e.g. port 587)]mbedtls_net_connect(server, port)performTlsHandshake()TLS ClientHelloTLS ServerHello + Certificatehandshake OKEHLO [hostname]250 capabilitiesEHLO [hostname]250 capabilitiesSTARTTLS220 ReadyperformTlsHandshake()TLS ClientHelloTLS ServerHello + Certificatehandshake OKEHLO [hostname]250 capabilitiesAUTH LOGIN334 (username prompt)base64(username)334 (password prompt)base64(password)235 Authentication successfulMAIL FROM:<email>250 OKRCPT TO:<email>250 OKDATA354 Start inputSubject: [title]\r\n\r\n[message]\r\n.250 OKQUIT221 Bye

Buffer constraints: Fixed 512 B (BUF_SIZE) for all SMTP I/O, 128 B for base64 encoding. No VLAs. calloc() failures are checked and logged. Connection timeout: 5000 ms.


All providers except Email share this path through HttpNotificationProvider.

Remote Serviceesp_http_clientHttpNotificationProviderConcreteProviderRemote Serviceesp_http_clientHttpNotificationProviderConcreteProvideralt[status == 200][status != 200]sendHttpPost(url, data, host, ssl, ct, auth)esp_http_client_init(config)\ncrt_bundle_attach (when ssl=true)set_header(Host, Content-Type, User-Agent …)set_post_field(data)esp_http_client_perform()HTTPS/HTTP POSTHTTP responsestatus code_lastError = no_error, return truemapStatusCode(code) → error enum_lastError set, return falseesp_http_client_cleanup()

TelegramProvider overrides mapStatusCode(): HTTP 401 → invalid_token1, 400 → invalid_token2, 404 → invalid_url. All other providers use the default mapping (non-200 → invalid_data).


Side-channel outputs (always fire)

Gcode Host

esp3d_gcode_host_service.cpp:2096

ESP-Commands

Network Boot

esp3d_network_services.cpp:143

begin(sendAutoMsg=true)

sendMSG()

begin() / end()

getType() / started()

begin()

sendMSG()

if provider set

esp3dNetworkServices.begin()

ESP600

Send notification now

auth: user

ESP610

Get/Set notification config

set auth: admin

ESP420

Firmware info report

ESP401

Settings write → restart svc

Stream error handler

esp3dNotificationsService

WebUI WebSocket

pushNotification()

ESP3D_HTTP_FEATURE

Status bar label

status_bar_label

ESP3D_HAS_STATUS_BAR

Active INotificationProvider

(if configured)


no_error - Operation succeeded

empty_message - sendMSG called with empty string

invalid_message - Provider-level message validation failed

invalid_data - HTTP non-200 (default mapping)

invalid_url - URL build failed or HTTP 404

invalid_token1 - HTTP 401 (Telegram) or bad primary credential

invalid_token2 - HTTP 400 (Telegram) or bad secondary credential

error - Network or TLS failure

ESP3DNotificationsService::getLastError() delegates to _provider->getLastError() when a provider is active; it falls back to its own _lastError (e.g. empty_message) when no provider exists. [ESP600] reports the numeric error value on send failure.


Auto-notification message templates are defined per-board in customizations/notifications/customizations.h (overridable per board under boards/<board>/customizations/notifications/):

// Default (customizations/notifications/customizations.h)
#define ESP3D_NOTIFICATION_TITLE "Hi from ESP3D"
#define ESP3D_NOTIFICATION_ONLINE "Hi, %ESP_NAME% is now online at %ESP_IP%"
// PiBot board override (boards/pibot_pendant_v1_0/customizations/notifications/)
#define ESP3D_NOTIFICATION_TITLE "PiBot CNC Pendant"
#define ESP3D_NOTIFICATION_ONLINE "Hi, %ESP_NAME% is now online at %ESP_IP%"

The %ESP_NAME% and %ESP_IP% placeholders (and any others supported by esp3d_string::expandString()) are expanded in both title and message before every send.


CommandDirectionAuth levelDescription
[ESP600]<message>WriteuserSend a notification immediately using the active provider
[ESP610]Read—Return current type, AUTO, TS (never returns T1/T2)
[ESP610] type=… T1=… T2=… TS=… AUTO=…WriteadminUpdate notification settings and restart the service live (no reboot)
[ESP420]Read—Firmware info report — includes active notification type string

FileRole
main/modules/notifications/esp3d_notifications_service.h/.cppSingleton orchestrator — settings parsing, provider lifecycle, sendMSG()
main/modules/notifications/esp3d_notification_provider.hINotificationProvider abstract interface + ESP3DNotificationError enum
main/modules/notifications/esp3d_http_notification_provider.h/.cppShared HTTP/HTTPS POST+GET base (esp_http_client) for all HTTP providers
main/modules/notifications/esp3d_email_notification.h/.cppEmail: raw mbedTLS SMTP client (SSL implicit + STARTTLS)
main/modules/notifications/esp3d_pushover_notification.h/.cppPushover HTTPS POST
main/modules/notifications/esp3d_telegram_notification.h/.cppTelegram HTTPS POST + custom mapStatusCode()
main/modules/notifications/esp3d_ifttt_notification.h/.cppIFTTT webhooks HTTPS POST
main/modules/notifications/esp3d_whatsapp_notification.h/.cppWhatsApp via CallMeBot HTTPS GET
main/modules/notifications/esp3d_homeassistant_notification.h/.cppHome Assistant local HTTP POST
main/core/commands/esp600.cpp[ESP600] — send notification now
main/core/commands/esp610.cpp[ESP610] — get/set config, restart service without reboot
main/modules/network/esp3d_network_services.cpp:143Auto-notification trigger on network ready
main/modules/gcode_host/esp3d_gcode_host_service.cpp:2096Auto-notification trigger on stream error
customizations/notifications/customizations.hTitle + online message templates

  • authentication.md — authentication levels required by ESP600 (user) and ESP610 SET (admin)
  • network.md — network lifecycle that triggers the “online” auto-notification via esp3dNetworkServices.begin()
  • gcode_host.md — gcode streaming layer that triggers error notifications
  • mdns.md — notification TXT record advertising the active provider type on _device-info._tcp
  • websocket_server.md — WebUI WebSocket service that receives the side-channel pushNotification() call
  • values.md — ESP3DValues observable that receives the status_bar_label update on every sendMSG()