From 1eeec20678831ea0117e756da6a2833e2449930f Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 19:26:39 +0200 Subject: [PATCH 01/22] feat: add Command observable monitor --- src/command/ESPressio_CommandMonitor.hpp | 56 ++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 src/command/ESPressio_CommandMonitor.hpp diff --git a/src/command/ESPressio_CommandMonitor.hpp b/src/command/ESPressio_CommandMonitor.hpp new file mode 100644 index 0000000..fdd2cc3 --- /dev/null +++ b/src/command/ESPressio_CommandMonitor.hpp @@ -0,0 +1,56 @@ +#pragma once + +#if !__has_include() +#error "CommandMonitor requires ESPressio Command >= 0.3.0 < 1.0.0." +#endif + +#include +#include +#include + +namespace ESPressio::Serial { + +class CommandMonitor final : + public ESPressio::Command::ICommandRegistryObserver { +private: + Print* _output = nullptr; + ESPressio::Observable::ObserverHandlePtr _handle; + + void Line(const char* operation, const std::vector& path) { + if (!_output) return; + _output->print("[ESPressio Command] "); + _output->print(operation); + if (!path.empty()) { + _output->print(" "); + for (std::size_t i = 0; i < path.size(); ++i) { + if (i) _output->print("/"); + _output->print(path[i].c_str()); + } + } + _output->println(); + } + +public: + bool Initialize(Print& output, ESPressio::Command::CommandRegistry& registry = ESPressio::Command::CommandRegistry::GetInstance()) { + if (_handle) return true; + _output = &output; + _handle = registry.RegisterObserver(this); + if (!_handle) { _output = nullptr; return false; } + return true; + } + + void Shutdown() { + _handle.reset(); + _output = nullptr; + } + + void OnCommandRegistered(const std::vector& path) override { + Line("Registered", path); + } + + void OnCommandUnregistered(const std::vector& path) override { + Line("Unregistered", path); + } +}; + +} // namespace ESPressio::Serial From 9e2fd573d9212474d811fb60ceadf116d1c8ff9d Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 19:27:41 +0200 Subject: [PATCH 02/22] feat: expose Command observable monitor --- src/ESPressio_CommandMonitor.hpp | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 src/ESPressio_CommandMonitor.hpp diff --git a/src/ESPressio_CommandMonitor.hpp b/src/ESPressio_CommandMonitor.hpp new file mode 100644 index 0000000..a3d8b95 --- /dev/null +++ b/src/ESPressio_CommandMonitor.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "command/ESPressio_CommandMonitor.hpp" From 1a8d0f5c77ba09e5eeae195fe2c393ec44343f29 Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 19:27:48 +0200 Subject: [PATCH 03/22] feat: add Security observable monitor --- src/security/ESPressio_SecurityMonitor.hpp | 72 ++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 src/security/ESPressio_SecurityMonitor.hpp diff --git a/src/security/ESPressio_SecurityMonitor.hpp b/src/security/ESPressio_SecurityMonitor.hpp new file mode 100644 index 0000000..611b54f --- /dev/null +++ b/src/security/ESPressio_SecurityMonitor.hpp @@ -0,0 +1,72 @@ +#pragma once + +#if !__has_include() +#error "SecurityMonitor requires ESPressio Security >= 0.2.0 < 1.0.0." +#endif + +#include +#include +#include + +namespace ESPressio::Serial { + +class SecurityMonitor final : + public ESPressio::Security::ITransportSecurityObserver { +private: + Print* _output = nullptr; + ESPressio::Observable::ObserverHandlePtr _handle; + + void Line(const char* operation) { + if (!_output) return; + _output->print("[ESPressio Security] "); + _output->println(operation); + } + +public: + bool Initialize(Print& output, ESPressio::Security::TransportSecurity& security) { + if (_handle) return true; + _output = &output; + _handle = security.RegisterObserver(this); + if (!_handle) { _output = nullptr; return false; } + return true; + } + + void Shutdown() { + _handle.reset(); + _output = nullptr; + } + + void OnTransportSecurityConfigurationChanged( + const ESPressio::Security::TransportSecurityConfig&, + const ESPressio::Security::TransportSecurityConfig& + ) override { Line("ConfigurationChanged"); } + + void OnTransportSecuritySessionReset(uint64_t previousSessionID) override { + if (!_output) return; + _output->print("[ESPressio Security] SessionReset previous="); + _output->println(static_cast(previousSessionID)); + } + + void OnTransportSecuritySessionEstablished(uint64_t sessionID) override { + if (!_output) return; + _output->print("[ESPressio Security] SessionEstablished id="); + _output->println(static_cast(sessionID)); + } + + void OnTransportSecurityReplayProtectionReset() override { + Line("ReplayProtectionReset"); + } + + void OnTransportSecurityFailure(const ESPressio::Security::SecurityResult& result) override { + if (!_output) return; + _output->print("[ESPressio Security] Failure error="); + _output->print(static_cast(result.Error)); + if (!result.Message.empty()) { + _output->print(" message="); + _output->print(result.Message.c_str()); + } + _output->println(); + } +}; + +} // namespace ESPressio::Serial From a127502eb2dc767b8fabd5e140fe9182f0ee6130 Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 19:27:53 +0200 Subject: [PATCH 04/22] feat: expose Security observable monitor --- src/ESPressio_SecurityMonitor.hpp | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 src/ESPressio_SecurityMonitor.hpp diff --git a/src/ESPressio_SecurityMonitor.hpp b/src/ESPressio_SecurityMonitor.hpp new file mode 100644 index 0000000..6857f22 --- /dev/null +++ b/src/ESPressio_SecurityMonitor.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "security/ESPressio_SecurityMonitor.hpp" From 68118cc897023e540d3d36f69b2fc2fd55c79a13 Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 19:28:04 +0200 Subject: [PATCH 05/22] feat: add socket worker observable monitor --- src/sockets/ESPressio_SocketWorkerMonitor.hpp | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 src/sockets/ESPressio_SocketWorkerMonitor.hpp diff --git a/src/sockets/ESPressio_SocketWorkerMonitor.hpp b/src/sockets/ESPressio_SocketWorkerMonitor.hpp new file mode 100644 index 0000000..eb8f91f --- /dev/null +++ b/src/sockets/ESPressio_SocketWorkerMonitor.hpp @@ -0,0 +1,49 @@ +#pragma once + +#if !__has_include() +#error "SocketWorkerMonitor requires ESPressio Sockets >= 0.5.0 < 1.0.0." +#endif + +#include +#include +#include + +namespace ESPressio::Serial { + +class SocketWorkerMonitor final : + public ESPressio::Sockets::ISocketWorkerObserver { +private: + Print* _output = nullptr; + ESPressio::Observable::ObserverHandlePtr _handle; + + void Line(const char* operation, const char* name = nullptr) { + if (!_output) return; + _output->print("[ESPressio Sockets] [Worker] "); + _output->print(operation); + if (name != nullptr) { + _output->print(" name="); + _output->print(name); + } + _output->println(); + } + +public: + bool Initialize(Print& output, ESPressio::Sockets::SocketWorker& worker) { + if (_handle) return true; + _output = &output; + _handle = worker.RegisterObserver(this); + if (!_handle) { _output = nullptr; return false; } + return true; + } + + void Shutdown() { + _handle.reset(); + _output = nullptr; + } + + void OnSocketWorkerStarted(const char* name) override { Line("Started", name); } + void OnSocketWorkerStartFailed(const char* name) override { Line("StartFailed", name); } + void OnSocketWorkerStopped() override { Line("Stopped"); } +}; + +} // namespace ESPressio::Serial From 849da16c14cfbf6101c56740e7c93fd76175ff6d Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 19:28:12 +0200 Subject: [PATCH 06/22] feat: add socket security session monitor --- ...ESPressio_SocketSecuritySessionMonitor.hpp | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 src/sockets/ESPressio_SocketSecuritySessionMonitor.hpp diff --git a/src/sockets/ESPressio_SocketSecuritySessionMonitor.hpp b/src/sockets/ESPressio_SocketSecuritySessionMonitor.hpp new file mode 100644 index 0000000..2d31a24 --- /dev/null +++ b/src/sockets/ESPressio_SocketSecuritySessionMonitor.hpp @@ -0,0 +1,50 @@ +#pragma once + +#if !__has_include() +#error "SocketSecuritySessionMonitor requires ESPressio Sockets >= 0.5.0 < 1.0.0 and ESPressio Security >= 0.2.0 < 1.0.0." +#endif + +#include +#include +#include + +namespace ESPressio::Serial { + +class SocketSecuritySessionMonitor final : + public ESPressio::Sockets::ISocketSecuritySessionObserver { +private: + Print* _output = nullptr; + ESPressio::Observable::ObserverHandlePtr _handle; + +public: + bool Initialize(Print& output, ESPressio::Sockets::SocketSecuritySession& session) { + if (_handle) return true; + _output = &output; + _handle = session.RegisterObserver(this); + if (!_handle) { _output = nullptr; return false; } + return true; + } + + void Shutdown() { + _handle.reset(); + _output = nullptr; + } + + void OnSocketSecuritySessionFaulted(const ESPressio::Security::SecurityResult& result) override { + if (!_output) return; + _output->print("[ESPressio Sockets] [SecuritySession] Faulted error="); + _output->print(static_cast(result.Error)); + if (!result.Message.empty()) { + _output->print(" message="); + _output->print(result.Message.c_str()); + } + _output->println(); + } + + void OnSocketSecuritySessionReset() override { + if (!_output) return; + _output->println("[ESPressio Sockets] [SecuritySession] Reset"); + } +}; + +} // namespace ESPressio::Serial From 6d699134bafc7d7eaf97c2d465a9ff386b9c3c23 Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 19:28:17 +0200 Subject: [PATCH 07/22] feat: expose socket worker monitor --- src/ESPressio_SocketWorkerMonitor.hpp | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 src/ESPressio_SocketWorkerMonitor.hpp diff --git a/src/ESPressio_SocketWorkerMonitor.hpp b/src/ESPressio_SocketWorkerMonitor.hpp new file mode 100644 index 0000000..d32bfa5 --- /dev/null +++ b/src/ESPressio_SocketWorkerMonitor.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "sockets/ESPressio_SocketWorkerMonitor.hpp" From e33e0f2563a947770b08d40b4c8abda617fe3ffb Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 19:28:22 +0200 Subject: [PATCH 08/22] feat: expose socket security session monitor --- src/ESPressio_SocketSecuritySessionMonitor.hpp | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 src/ESPressio_SocketSecuritySessionMonitor.hpp diff --git a/src/ESPressio_SocketSecuritySessionMonitor.hpp b/src/ESPressio_SocketSecuritySessionMonitor.hpp new file mode 100644 index 0000000..3a5caa7 --- /dev/null +++ b/src/ESPressio_SocketSecuritySessionMonitor.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "sockets/ESPressio_SocketSecuritySessionMonitor.hpp" From e18250c142a41540a5b77380df75b3024709f04e Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 19:28:29 +0200 Subject: [PATCH 09/22] feat: add ESP-NOW observable monitor --- .../ESPressio_ESPNowTransportMonitor.hpp | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 src/espnow/ESPressio_ESPNowTransportMonitor.hpp diff --git a/src/espnow/ESPressio_ESPNowTransportMonitor.hpp b/src/espnow/ESPressio_ESPNowTransportMonitor.hpp new file mode 100644 index 0000000..98f3403 --- /dev/null +++ b/src/espnow/ESPressio_ESPNowTransportMonitor.hpp @@ -0,0 +1,51 @@ +#pragma once + +#if !__has_include() +#error "ESPNowTransportMonitor requires ESPressio ESP-Now >= 0.5.0 < 1.0.0." +#endif + +#include +#include +#include + +namespace ESPressio::Serial { + +class ESPNowTransportMonitor final : + public ESPressio::ESPNow::IESPNowTransportObserver { +private: + Print* _output = nullptr; + ESPressio::Observable::ObserverHandlePtr _handle; + + void Line(const char* operation) { + if (!_output) return; + _output->print("[ESPressio ESP-Now] "); + _output->println(operation); + } + +public: + bool Initialize( + Print& output, + ESPressio::ESPNow::ESPNowTransport& transport = ESPressio::ESPNow::ESPNowTransport::GetInstance() + ) { + if (_handle) return true; + _output = &output; + _handle = transport.RegisterObserver(this); + if (!_handle) { _output = nullptr; return false; } + return true; + } + + void Shutdown() { + _handle.reset(); + _output = nullptr; + } + + void OnESPNowTransportInitialized() override { Line("Initialized"); } + void OnESPNowTransportInitializationFailed() override { Line("InitializationFailed"); } + void OnESPNowTransportShutdown() override { Line("Shutdown"); } + void OnESPNowPeerAdded(const ESPressio::ESPNow::MacAddress&) override { Line("PeerAdded"); } + void OnESPNowPeerRemoved(const ESPressio::ESPNow::MacAddress&) override { Line("PeerRemoved"); } + void OnESPNowSendAccepted(const ESPressio::ESPNow::MacAddress&, uint8_t, std::size_t) override { Line("SendAccepted"); } + void OnESPNowSendFailed(const ESPressio::ESPNow::MacAddress&, uint8_t, std::size_t) override { Line("SendFailed"); } +}; + +} // namespace ESPressio::Serial From caa33d54d4cc70ff43b0727233f365bcd63e12e4 Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 19:28:35 +0200 Subject: [PATCH 10/22] feat: expose ESP-NOW observable monitor --- src/ESPressio_ESPNowTransportMonitor.hpp | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 src/ESPressio_ESPNowTransportMonitor.hpp diff --git a/src/ESPressio_ESPNowTransportMonitor.hpp b/src/ESPressio_ESPNowTransportMonitor.hpp new file mode 100644 index 0000000..efacabd --- /dev/null +++ b/src/ESPressio_ESPNowTransportMonitor.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "espnow/ESPressio_ESPNowTransportMonitor.hpp" From 181c31f33823c624a51fab76433667ecaf598b9b Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 19:28:48 +0200 Subject: [PATCH 11/22] feat: extend aggregate diagnostics with observable monitors --- .../ESPressio_DiagnosticMonitor.hpp | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/diagnostics/ESPressio_DiagnosticMonitor.hpp b/src/diagnostics/ESPressio_DiagnosticMonitor.hpp index 223fbe1..eb74a0d 100644 --- a/src/diagnostics/ESPressio_DiagnosticMonitor.hpp +++ b/src/diagnostics/ESPressio_DiagnosticMonitor.hpp @@ -16,12 +16,24 @@ #define ESPRESSIO_SERIAL_HAS_EVENT_MONITOR 1 #endif +#if __has_include() && __has_include() +#include "../command/ESPressio_CommandMonitor.hpp" +#define ESPRESSIO_SERIAL_HAS_COMMAND_MONITOR 1 +#endif + +#if __has_include() && __has_include() +#include "../espnow/ESPressio_ESPNowTransportMonitor.hpp" +#define ESPRESSIO_SERIAL_HAS_ESPNOW_MONITOR 1 +#endif + namespace ESPressio::Serial { struct DiagnosticMonitorConfig { bool SystemClock = true; bool Threads = true; bool Events = true; + bool Commands = false; + bool ESPNow = false; }; class DiagnosticMonitor final { @@ -34,6 +46,12 @@ class DiagnosticMonitor final { #ifdef ESPRESSIO_SERIAL_HAS_EVENT_MONITOR EventMonitor _events; #endif +#ifdef ESPRESSIO_SERIAL_HAS_COMMAND_MONITOR + CommandMonitor _commands; +#endif +#ifdef ESPRESSIO_SERIAL_HAS_ESPNOW_MONITOR + ESPNowTransportMonitor _espNow; +#endif public: bool Initialize(Print& output, const DiagnosticMonitorConfig& config = {}) { bool success = true; @@ -51,11 +69,27 @@ class DiagnosticMonitor final { if (config.Events) success = _events.Initialize(output) && success; #else if (config.Events) success = false; +#endif +#ifdef ESPRESSIO_SERIAL_HAS_COMMAND_MONITOR + if (config.Commands) success = _commands.Initialize(output) && success; +#else + if (config.Commands) success = false; +#endif +#ifdef ESPRESSIO_SERIAL_HAS_ESPNOW_MONITOR + if (config.ESPNow) success = _espNow.Initialize(output) && success; +#else + if (config.ESPNow) success = false; #endif return success; } void Shutdown() { +#ifdef ESPRESSIO_SERIAL_HAS_ESPNOW_MONITOR + _espNow.Shutdown(); +#endif +#ifdef ESPRESSIO_SERIAL_HAS_COMMAND_MONITOR + _commands.Shutdown(); +#endif #ifdef ESPRESSIO_SERIAL_HAS_EVENT_MONITOR _events.Shutdown(); #endif From 0e509a603babc113775d107865fb67e002fa975c Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 19:29:13 +0200 Subject: [PATCH 12/22] chore: bump Serial to 0.5.0 --- library.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library.json b/library.json index 10db741..bea5822 100644 --- a/library.json +++ b/library.json @@ -1,7 +1,7 @@ { "name": "ESPressio-Serial", - "description": "Serial and console-oriented components for ESPressio, including opt-in ESPressio Command and Event integrations.", - "keywords": "esp32,serial,console,monitor,event,transport,diagnostics,espressio", + "description": "Serial and console-oriented components for ESPressio, including opt-in Observable, Command and Event integrations.", + "keywords": "esp32,serial,console,monitor,event,transport,diagnostics,observable,espressio", "authors": { "name": "Flowduino", "maintainer": true, @@ -16,7 +16,7 @@ "type": "git", "url": "https://github.com/Flowduino/ESPressio-Serial.git" }, - "version": "0.4.0", + "version": "0.5.0", "license": "Apache-2.0", "frameworks": "arduino", "platforms": "espressif32" From 68ddba8f3aef65931dbd9e2bfe305bab27ea5775 Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 19:29:19 +0200 Subject: [PATCH 13/22] chore: update Serial Arduino metadata --- library.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library.properties b/library.properties index a531a00..c1af497 100644 --- a/library.properties +++ b/library.properties @@ -1,9 +1,9 @@ name=ESPressio-Serial -version=0.4.0 +version=0.5.0 author=Flowduino maintainer=Flowduino sentence=Serial console, diagnostics, logging and operator tooling for the ESPressio ecosystem. -paragraph=Provides structured logging, diagnostics monitors, an extensible Stream/Print console, opt-in ESPressio Command integration, and opt-in runtime JSON composition and dispatch of registered Serializable ESPressio Events. +paragraph=Provides structured logging, diagnostics monitors, an extensible Stream/Print console, opt-in observable monitors for Command, Security, Sockets and ESP-Now, opt-in ESPressio Command integration, and opt-in runtime JSON composition and dispatch of registered Serializable ESPressio Events. category=Communication url=https://github.com/Flowduino/ESPressio-Serial architectures=esp32 From b71031f39ba0a33aa97393408784f66561d8ea14 Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 19:29:26 +0200 Subject: [PATCH 14/22] chore: update Serial component version and include paths --- component.mk | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/component.mk b/component.mk index 3c836fc..02b1fdc 100644 --- a/component.mk +++ b/component.mk @@ -1,11 +1,15 @@ COMPONENT_ADD_INCLUDEDIRS := \ src \ src/console \ + src/command \ src/command-console \ src/diagnostics \ + src/espnow \ src/event \ src/event-console \ src/logging \ + src/security \ + src/sockets \ src/threads \ src/timing @@ -16,6 +20,6 @@ CXXFLAGS += -std=gnu++17 CPPFLAGS += \ -DESPRESSIO_SERIAL \ -DESPRESSIO_SERIAL_VERSION_MAJOR=0 \ - -DESPRESSIO_SERIAL_VERSION_MINOR=4 \ + -DESPRESSIO_SERIAL_VERSION_MINOR=5 \ -DESPRESSIO_SERIAL_VERSION_PATCH=0 \ - -DESPRESSIO_SERIAL_VERSION_STRING=\"0.4.0\" + -DESPRESSIO_SERIAL_VERSION_STRING=\"0.5.0\" From 02f0427c7adb90d29283ccfda186a33189d5083d Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 19:29:32 +0200 Subject: [PATCH 15/22] docs: expose observable monitor entry points --- src/ESPressio_Serial.hpp | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/ESPressio_Serial.hpp b/src/ESPressio_Serial.hpp index bed8927..72cb2d2 100644 --- a/src/ESPressio_Serial.hpp +++ b/src/ESPressio_Serial.hpp @@ -3,4 +3,25 @@ #include "ESPressio_SerialTypes.hpp" #include "ESPressio_DiagnosticTypes.hpp" -/* Optional facilities are selected explicitly through ESPressio_Logging.hpp, ESPressio_SystemClockMonitor.hpp, ESPressio_ThreadMonitor.hpp, ESPressio_EventMonitor.hpp, or ESPressio_DiagnosticMonitor.hpp, ESPressio_CommandConsole.hpp, or ESPressio_EventConsole.hpp. */ +/* + * Optional facilities are selected explicitly. Core Serial remains free of + * mandatory ESPressio-library dependencies. + * + * Logging / diagnostics: + * ESPressio_Logging.hpp + * ESPressio_SystemClockMonitor.hpp + * ESPressio_ThreadMonitor.hpp + * ESPressio_EventMonitor.hpp + * ESPressio_DiagnosticMonitor.hpp + * + * Observable subsystem monitors: + * ESPressio_CommandMonitor.hpp -> Command >= 0.3.0 < 1.0.0 + * ESPressio_SecurityMonitor.hpp -> Security >= 0.2.0 < 1.0.0 + * ESPressio_SocketWorkerMonitor.hpp -> Sockets >= 0.5.0 < 1.0.0 + * ESPressio_SocketSecuritySessionMonitor.hpp + * ESPressio_ESPNowTransportMonitor.hpp -> ESP-Now >= 0.5.0 < 1.0.0 + * + * Interactive integrations: + * ESPressio_CommandConsole.hpp + * ESPressio_EventConsole.hpp + */ From 831fe56db93166b37e08f0ecc02c1da35002354a Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 19:29:52 +0200 Subject: [PATCH 16/22] docs: add Serial 0.5.0 changelog --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d8b563..f0aae0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +## 0.5.0 + +- Added opt-in `CommandMonitor` for ESPressio Command 0.3.x registry lifecycle observation. +- Added opt-in `SecurityMonitor` for ESPressio Security 0.2.x configuration, session, replay and failure observation. +- Added opt-in `SocketWorkerMonitor` and `SocketSecuritySessionMonitor` for ESPressio Sockets 0.5.x lifecycle observation. +- Added opt-in `ESPNowTransportMonitor` for ESPressio ESP-Now 0.5.x transport, peer and send lifecycle observation. +- Extended `DiagnosticMonitor` with optional Command and ESP-Now monitoring while preserving its existing default behavior. +- Updated the validated optional ESPressio Event integration baseline to Event 5.8.0 within the 5.x line. +- Preserved Serial's dependency-free core: all new monitors are selected explicitly and observe the originating subsystem rather than duplicating its lifecycle semantics. + ## 0.4.0 - Added optional ESPressio Command 0.2.x integration through `CommandConsole`. From 210448fd1ef6cb2f36429578e7015ebb30b3a329 Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 19:37:58 +0200 Subject: [PATCH 17/22] docs: document Serial 0.5.0 observable monitors --- README.md | 1114 +++++------------------------------------------------ 1 file changed, 86 insertions(+), 1028 deletions(-) diff --git a/README.md b/README.md index baf374e..019e7b0 100644 --- a/README.md +++ b/README.md @@ -1,1112 +1,170 @@ # ESPressio Serial -Serial and console-oriented components for the Flowduino ESPressio Development Platform. +Serial and console-oriented diagnostics, logging and operator tooling for the Flowduino ESPressio Development Platform. -Version 0.3.0 adds a reusable Stream/Print command console and an opt-in operator-facing Event Console capable of discovering, describing, composing as JSON, validating, and dispatching runtime-registered Serializable Events through ESPressio Event 5.6.1. +## Current Development Version -## Latest Stable Version +This branch targets **ESPressio Serial 0.5.0**. -The latest stable version is **0.4.0**. +0.5.0 extends Serial's diagnostics role with opt-in monitors for the new Observable lifecycle surfaces in ESPressio Command, Security, Sockets and ESP-Now. The originating library remains the source of truth; Serial only subscribes and renders those observations to an Arduino `Print` destination. -## ESPressio Development Platform +See [CHANGELOG.md](CHANGELOG.md) for release history. -ESPressio is a collection of discrete, composable component libraries designed around a common development ethos: +## Dependency philosophy -- **Light-weight** -- **Ease of use** -- **Object-oriented design** -- **SOLID design principles** -- **Pay only for the functionality an application selects** +The **core ESPressio Serial library remains dependency-free within the ESPressio ecosystem**. Optional facilities are selected explicitly by including their corresponding headers. -## License - -Licensed under the **Apache License 2.0**. See [LICENSE](LICENSE). - -## Namespace - -The public API resides beneath: - -```cpp -ESPressio::Serial -``` - -Because Arduino exposes a global object named `Serial`, fully qualified ESPressio Serial names are recommended: - -```cpp -ESPressio::Serial::EventMonitor monitor; -``` - -while the Arduino serial port remains: - -```cpp -::Serial -``` - -## ESPressio Library Dependencies - -The **core ESPressio Serial library has no required ESPressio library dependencies**. - -The Event Monitor is deliberately opt-in and requires: - -```text -ESPressio Event >= 5.7.1 < 6.0.0 -ESPressio Serializable >= 0.10.0 < 1.0.0 -``` - -For the complete ecosystem hierarchy, see: - -**[ESPressio Library Dependency Chart](ESPRESSIO_DEPENDENCY_CHART.md)** - -In the dependency chart: - -- **Solid relationships** represent required dependencies. -- **Dashed relationships** represent opt-in dependencies introduced only when the associated feature/header is used. - ---- - - - - -## Version 0.3.1 — Event 5.6.1 compatibility - -Version 0.3.1 updates the optional `EventConsole` integration baseline to **ESPressio Event 5.6.1**. - -Event 5.6.1 corrects `EventDispatchContext` equality semantics required by ESPressio Threads 3.1 `ReadWriteMutex` change detection. No ESPressio Serial console, monitoring, logging, or EventConsole public API changes are required. - -Applications using `EventConsole` should therefore target: - -```ini -flowduino/ESPressio-Event@^5.7.1 -``` - -The core Serial library and generic `Console` remain independent of ESPressio Event. - ---- - -# Version 0.3.0 — Interactive Runtime Serializable Event Console - -Version 0.3.0 adds the interactive operator/service-console layer. - -The architecture deliberately preserves library ownership: - -```text -operator - | - v -ESPressio Serial Console - | - | JSON - v -ESPressio Serializable JsonArchive - | - | SerializationNode - v -ESPressio Event 5.6 runtime registry/factory - | - v -concrete Serializable Event - | - v -normal Queue / Stack dispatch - | - +--> local listeners - | - +--> EventTransportManager - | - +--> any configured outbound transport -``` - -Serial does not create a second Event registry or remote-dispatch mechanism. - -## Generic `Console` - -The generic console is available independently of Event: - -```cpp -#include - -ESPressio::Serial::Console console; - -void setup() { - ::Serial.begin(115200); - - ESPressio::Serial::ConsoleConfig config; - config.Prompt = "espressio> "; - - console.Initialize( - ::Serial, - ::Serial, - config - ); - - console.RegisterCommand( - "hello", - "Print a greeting", - [](const auto& context) { - // Handle context.Arguments. - } - ); -} - -void loop() { - console.Poll(); -} -``` - -Input uses Arduino `Stream`; output uses Arduino `Print`. - -The console therefore works with Hardware Serial, USB CDC, or another compatible implementation. - -The line buffer is bounded through: - -```cpp -ConsoleConfig::MaximumLineLength -``` - -and the console supports: - -```text -command registration -command unregistration -help -arguments -prompt configuration -optional input echo -multiple interactive line interceptors -backspace/delete handling -CR/LF handling -``` - -Multiple line interceptors are intentional: future console extensions can maintain independent interactive states without replacing one global input handler. - -## `EventConsole` - -The Event Console is opt-in: - -```cpp -#include -``` - -and requires: - -```text -ESPressio Event >= 5.7.1 -ESPressio Serializable >= 0.10.0 < 1.0.0 -ArduinoJson (through the optional Serializable JsonArchive) -``` - -Initialize it over an existing `Console`: - -```cpp -ESPressio::Serial::Console console; -ESPressio::Serial::EventConsole eventConsole; - -console.Initialize( - ::Serial, - ::Serial -); - -eventConsole.Initialize( - console -); -``` - -## Safe-by-default Event authorization - -Runtime Event discovery does **not** imply permission to dispatch an Event. - -The default access policy is: - -```cpp -EventConsoleAccessPolicy::AllowListedOnly -``` - -Allow specific Event types: - -```cpp -eventConsole.AllowEvent< - CameraShutterEvent ->(); - -eventConsole.AllowEvent( - "flowduino.motor.move.v1" -); -``` - -For a controlled development environment, explicitly enable all registered types: - -```cpp -eventConsole.SetAccessPolicy( - ESPressio::Serial:: - EventConsoleAccessPolicy:: - AllRegistered -); -``` - -Deny-list entries override allow-all: - -```cpp -eventConsole.DenyEvent< - FactoryResetEvent ->(); -``` - -This prevents a registered administrative/destructive Event from becoming operator-dispatchable merely because a console is enabled. - -## Event discovery - -List runtime-registered Serializable Events: - -```text -espressio> events - -Registered Serializable Events: - flowduino.camera.shutter.v1 [constructible] [allowed] schema=1 defaultRouting=Outbound - flowduino.motor.move.v1 [constructible] [allowed] schema=2 defaultRouting=Bidirectional - flowduino.system.factory-reset.v1 [constructible] [denied] schema=1 defaultRouting=None -``` - -The equivalent command is: - -```text -event list -``` - -## Event schema description - -```text -espressio> event describe flowduino.motor.move.v1 -``` - -uses Event 5.6's runtime descriptor and Serializable schema metadata to report: - -```text -stable Event type name -stable Event type ID -schema version -runtime constructibility -operator access -default Event Transport direction -property names -property types -required state -read-only state -sensitive metadata -default-value availability -aliases -``` - -Per-transport route names are not fabricated: Event 5.6 currently exposes the default routing direction through the public runtime descriptor. - -## One-line JSON dispatch - -Queue: - -```text -event queue flowduino.motor.move.v1 {"axis":"pan","position":45,"speed":20} -``` - -Stack: - -```text -event stack flowduino.motor.move.v1 {"axis":"pan","position":45,"speed":20} -``` - -`event dispatch` is a Queue alias. - -JSON is parsed through ESPressio Serializable's `JsonArchive`, converted to a representation-neutral `SerializationNode`, and passed to Event 5.6's runtime factory. - -## Interactive composition - -```text -event compose flowduino.motor.move.v1 -``` - -or: - -```text -event compose flowduino.motor.move.v1 stack -``` - -prompts for a one-line JSON object: - -```text -Enter one-line JSON object for flowduino.motor.move.v1 (or 'cancel'): -{"axis":"pan","position":45,"speed":20} -``` - -## Serializable validation diagnostics - -Runtime-created Events use the normal ESPressio Serializable validation path. - -Validation errors are presented to the operator with: - -```text -property path -serialization error code -diagnostic message -``` - -For example: - -```text -Event payload validation failed with 2 issue(s): - speed: NumericOutOfRange - Property failed its numeric range constraint - axis: UnknownEnumValue - Value is not a registered enum mapping -``` - -No separate Serial-specific Event validation system exists. - -## Confirmation - -Confirmation is enabled by default: - -```text -Dispatch Event 'flowduino.motor.move.v1' via Queue priority=Normal? [y/N] -``` - -Only `y` or `yes` proceeds; any other response cancels the dispatch. - -It can be disabled explicitly: - -```cpp -EventConsoleConfig config; -config.RequireConfirmation = false; -``` - -## Dispatch semantics - -Event Console uses Event 5.6's ownership-safe runtime dispatch API. - -Once dispatched, the Event follows the normal Event system: - -```text -runtime-created Event - | - v -Queue / Stack - | - v -local Event dispatch - | - v -EventTransportManager - | - v -existing per-transport outbound routing -``` - -Event Console therefore knows nothing about ESP-NOW, UDP, TCP, WebSocket, MQTT, or another concrete Event transport. - -## Audit logging - -`EventConsole` can optionally send security/operation audit records to any existing: - -```cpp -ILoggerSink -``` - -using: - -```cpp -eventConsole.SetAuditSink( - &history -); -``` - -Useful audit conditions include: - -```text -successful operator dispatch -denied dispatch -unregistered type -malformed JSON -oversized JSON -construction/validation failure -dispatch failure -``` - -The Event payload itself is deliberately not copied into the audit message by default, avoiding accidental logging of sensitive properties. - -## Event Monitor integration - -Console-created Events naturally flow through the ordinary Event Transport pipeline. - -If `EventMonitor` is enabled, the same operator-created Event appears in its normal outbound/inbound transaction diagnostics without any special integration code. - -## Limits - -Operator JSON is bounded by: - -```cpp -EventConsoleConfig::MaximumJsonLength -``` - -and the enclosing generic Console independently bounds total input line length. - -Queue and Stack dispatch can be independently disabled: - -```cpp -config.AllowQueue = true; -config.AllowStack = false; -``` - -## Examples - -Version 0.3.0 adds: - -```text -examples/ -├── Console/ -│ └── Console.ino -│ -├── EventConsole/ -│ └── EventConsole.ino -│ -└── EventConsoleLoopback/ - └── EventConsoleLoopback.ino -``` - -`EventConsoleLoopback` combines the operator console, Event Console, Event Monitor, Serializable Event, and a local loopback `IEventTransport` to demonstrate the complete: - -```text -Serial JSON - -> runtime Event - -> local dispatch - -> Event Transport - -> inbound reconstruction - -> Serial Event Monitor -``` - -pipeline on one ESP32. - -## Tests - -The repository includes host-side tests for: - -```text -generic Console command dispatch -argument preservation -multiple interactive line interceptors -interceptor removal -Stream polling -runtime Event listing -Event schema description -allow-list enforcement -JSON command processing -pre-dispatch confirmation -type-erased dispatch -``` - -The Event Console contract test uses narrow test doubles for Event 5.6 and the Serializable JSON adapter, while release preparation verifies compatibility with the real public API surface. - ---- - -# Version 0.2.0 — Diagnostics & Logging - -Version 0.2.0 adds a general diagnostics foundation alongside the existing Event Monitor. - -## Logging - -```cpp -#include - -ESPressio::Serial::Logger<> logger; -ESPressio::Serial::SerialLogSink serialSink(::Serial); -ESPressio::Serial::DiagnosticRingBuffer<64> history; - -void setup() { - ::Serial.begin(115200); - - logger.AddSink(serialSink); - logger.AddSink(history); - - logger.SetMinimumLevel( - ESPressio::Serial::LogLevel::Debug - ); - - logger.Info("Application", "Boot complete"); -} -``` - -Supported levels are: - -```text -Trace -Debug -Info -Warning -Error -Critical -Off -``` - -`Logger` supports multiple simultaneous `ILoggerSink` implementations. Logging data is therefore separated from its output destination: Serial is one sink, not the logging architecture itself. - -`ESPRESSIO_SERIAL_COMPILETIME_LOG_LEVEL` may be defined to remove lower-severity calls from runtime delivery, while `SetMinimumLevel()` provides runtime filtering. - -## Diagnostic flight recorder - -`DiagnosticRingBuffer` is both an `ILoggerSink` and a bounded in-memory history. - -```cpp -ESPressio::Serial::DiagnosticRingBuffer<64> history; - -logger.AddSink(history); - -// Later, after a fault: -history.Dump(::Serial); -``` - -Entries are copied into fixed-size storage; the oldest entry is overwritten when capacity is exhausted. This makes it suitable for retaining the diagnostic events immediately preceding a failure without unbounded heap growth. - -## System Clock Monitor - -```cpp -#include - -ESPressio::Serial::SystemClockMonitor<> clockMonitor; - -clockMonitor.Initialize(::Serial); -``` - -This integration directly consumes ESPressio Timing 2.2.2's `ISystemClockObserver` notifications. It reports time-setting, synchronization acceptance/rejection, synchronization state changes, resets/configuration changes, and callback scheduling/execution. - -Synchronization output includes the clock value before correction, the value after correction, and the immediate nanosecond difference. - -This is an opt-in Timing dependency; ESPressio Event is not involved. - -## Thread Monitor - -```cpp -#include - -ESPressio::Serial::ThreadMonitor threadMonitor; - -threadMonitor.Initialize(::Serial); -``` - -`ThreadMonitor` directly observes the process-wide ESPressio Threads 3.1.2 infrastructure: - -```text -ThreadManager -ThreadGarbageCollector -ThreadTerminationDispatcher -``` - -It reports registration, cleanup, garbage collection, termination dispatch, initialization, and failure lifecycle notifications. - -This is an opt-in Threads dependency; Event bridges are not required merely to display Thread diagnostics. - -## Aggregate Diagnostic Monitor - -When the corresponding dependency headers are available, the convenience monitor can compose all supported subsystem monitors: - -```cpp -#include - -ESPressio::Serial::DiagnosticMonitor diagnostics; - -void setup() { - ::Serial.begin(115200); - - ESPressio::Serial::DiagnosticMonitorConfig config; - - config.SystemClock = true; - config.Threads = true; - config.Events = true; - - diagnostics.Initialize( - ::Serial, - config - ); -} -``` +Current optional integration baselines are: -The aggregate uses compile-time feature detection. It does not itself make Timing, Threads, Event, or Serializable mandatory package dependencies. +- **ESPressio Timing >= 2.2.2 and < 3.0.0** — System Clock monitoring. +- **ESPressio Threads >= 3.1.2 and < 4.0.0** — Thread Manager/GC/termination monitoring. +- **ESPressio Event >= 5.8.0 and < 6.0.0** — Event Monitor and EventConsole integrations. +- **ESPressio Serializable >= 0.10.0 and < 1.0.0** — runtime Serializable Event tooling where selected. +- **ESPressio Command >= 0.3.0 and < 1.0.0** — CommandConsole and `CommandMonitor`. +- **ESPressio Security >= 0.2.0 and < 1.0.0** — `SecurityMonitor`. +- **ESPressio Sockets >= 0.5.0 and < 1.0.0** — socket worker/security-session monitors. +- **ESPressio ESP-Now >= 0.5.0 and < 1.0.0** — `ESPNowTransportMonitor`. -## Dependency model +No one of these is introduced as a mandatory dependency of `ESPressio_Serial.hpp`. ```text -ESPressio Serial core - -> no mandatory ESPressio dependency - -Logging - -> no additional ESPressio dependency - -SystemClockMonitor - - - -> ESPressio Timing >= 2.2.2 < 3.0.0 - -ThreadMonitor - - - -> ESPressio Threads >= 3.1.2 < 4.0.0 + +--> Timing monitor + +--> Threads monitor +ESPressio Serial core ---+--> Event monitor / EventConsole + +--> Command console / monitor + +--> Security monitor + +--> Sockets monitors + +--> ESP-Now monitor -EventMonitor - - - -> ESPressio Event >= 5.7.1 < 6.0.0 - - - -> ESPressio Serializable >= 0.10.0 < 1.0.0 +(all relationships above are opt-in) ``` -All ESPressio relationships remain opt-in. +See [ESPRESSIO_DEPENDENCY_CHART.md](ESPRESSIO_DEPENDENCY_CHART.md) for the broader ecosystem relationship view. ---- - -# Core include +## Core umbrella ```cpp #include ``` -The core header contains common ESPressio Serial types only. - -It does **not** include ESPressio Event or ESPressio Serializable. - -Event monitoring is selected explicitly: - -```cpp -#include -``` - -or through the feature batch header: - -```cpp -#include -``` +The core umbrella exposes common Serial/diagnostic types and documents optional entry points without batch-including their dependencies. ---- +## Logging -# Event Transport Monitor +The existing logging layer remains available through `ESPressio_Logging.hpp`, including log levels, pluggable sinks, `SerialLogSink`, filtering and retained diagnostic history. -`EventMonitor` consumes the **Event Transport Transaction Observation** API introduced by ESPressio Event 5.5.0. +## Existing monitors -It does not implement an Event Transport and does not alter Event routing. +Serial continues to provide: -Conceptually: +- `SystemClockMonitor` — Timing System Clock observer output; +- `ThreadMonitor` — Thread Manager, Garbage Collector and Termination Dispatcher observations; +- `EventMonitor` — Event Transport transaction/event diagnostics; and +- `DiagnosticMonitor` — convenience aggregation of available monitors. -```text -Serializable Event - | - v -EventTransportManager - | - +-----------------------> concrete transport - | - +--> transaction Observer - | - v - EventMonitor - | - v - Arduino Print - | - +--------+--------+ - | | - v v - Serial USB CDC -``` +## Observable subsystem monitors -Any `Print` implementation may be used. The monitor is therefore not tied specifically to `HardwareSerial`. +0.5.0 adds four new opt-in monitoring areas. -## Initialization +### Command ```cpp -#include - -ESPressio::Serial::EventMonitor - monitor; - -void setup() { - ::Serial.begin(115200); - - ESPressio::Serial:: - EventMonitorConfig - config; +#include - monitor.Initialize( - ::Serial, - config - ); -} -``` - -`Initialize()` registers the monitor with the selected `EventTransportManager`. - -It does **not** initialize the Event Transport Manager itself. The application remains responsible for its normal Event Transport setup and initialization. - -The monitor unregisters automatically when destroyed or when: - -```cpp -monitor.Shutdown(); +ESPressio::Serial::CommandMonitor monitor; +monitor.Initialize(Serial); ``` -is called. +`CommandMonitor` consumes `ICommandRegistryObserver` and prints command-root registration/unregistration lifecycle changes. It does not observe or intercept command execution itself. ---- - -# Default monitoring behaviour - -The default mode is: +### Security ```cpp -EventMonitorMode::Events -``` - -This is intended to provide one useful record per logical transported Event rather than printing every internal lifecycle transition. +#include -It reports: - -```text -outbound Event after concrete transport handoff -inbound Event after successful deserialization -inbound rejection -transport processing failure +ESPressio::Serial::SecurityMonitor monitor; +monitor.Initialize(Serial, security); ``` -For example: - -```text -[ESPressio Event] [OUT] [OutboundHandedToTransport] type=flowduino.example.serial.monitored-counter.v1 typeId=0x... schema=1 message=3 transport=0x... dispatch=Queue priority=Normal origin=Local hops=0 accepted=true payloadBytes=... - payload: { - "__schemaVersion": 1, - "counter": 3, - "source": "local" - } -``` - -and the looped-back inbound Event may then appear as: - -```text -[ESPressio Event] [IN] [InboundDeserialized] type=flowduino.example.serial.monitored-counter.v1 typeId=0x... schema=1 message=3 transport=0x... dispatch=Queue priority=Normal origin=Remote hops=0 payloadBytes=... - payload: { - "__schemaVersion": 1, - "counter": 3, - "source": "local" - } -``` +`SecurityMonitor` subscribes to a specific `TransportSecurity` instance and reports configuration changes, session reset/establishment, replay-protection reset and security failures. Key material is never rendered. ---- - -# Lifecycle mode - -For deeper diagnostics: +### Sockets ```cpp -config.Mode = - ESPressio::Serial:: - EventMonitorMode::Lifecycle; +#include +#include ``` -prints every Event 5.5 transaction stage exposed by `EventTransportManager`: - -```text -OutboundAccepted -OutboundSerialized -OutboundHandedToTransport - -InboundAccepted -InboundRejected -InboundDeserialized -InboundDispatched - -Failed -``` +`SocketWorkerMonitor` subscribes to a specific `SocketWorker` and reports start/start-failure/stop transitions. -Lifecycle mode is intentionally verbose and is most useful while debugging the transport pipeline itself. +`SocketSecuritySessionMonitor` subscribes to a specific `SocketSecuritySession` and reports secure-session faults and explicit resets. ---- +The instance-specific API is deliberate: Serial does not invent a global socket/session registry where the Sockets library does not own one. -# Payload formatting - -The Event Monitor supports: +### ESP-Now ```cpp -EventMonitorPayloadFormat::None -EventMonitorPayloadFormat::Summary -EventMonitorPayloadFormat::Hex -EventMonitorPayloadFormat::Structured -``` - -## `None` - -Only transaction metadata is printed. - -## `Summary` - -Reports payload size without printing payload contents. +#include -## `Hex` - -Prints the Serializable Binary Archive bytes in hexadecimal. - -The maximum number of bytes is controlled by: - -```cpp -config.MaximumHexPayloadBytes +ESPressio::Serial::ESPNowTransportMonitor monitor; +monitor.Initialize(Serial); ``` -## `Structured` - -`Structured` is the default. - -ESPressio Event Transport serializes Event payloads using ESPressio Serializable's `BinaryArchive`. - -The monitor decodes that Binary Archive into Serializable's generic `SerializationNode` tree and renders it directly as JSON-like structured text. +`ESPNowTransportMonitor` consumes the shared `ESPNowTransport` observer surface and reports initialization, shutdown, peer lifecycle, and send acceptance/failure observations. -This has two important advantages: +## Aggregate DiagnosticMonitor -1. the monitor does not need to know the concrete C++ Event type; -2. it does not require ArduinoJson merely to present human-readable diagnostics. +`DiagnosticMonitor` continues to auto-compose integrations that can be located at compile time. -The monitor is therefore able to inspect arbitrary transported Serializable Event payloads using the schema already encoded in the Binary Archive. - ---- - -# Structured-output limits - -Diagnostic output should not be allowed to grow without bound. - -Configuration includes: +The existing `SystemClock`, `Threads` and `Events` defaults are preserved. 0.5.0 adds: ```cpp -MaximumCollectionItems -MaximumStringLength -MaximumStructuredDepth -IndentSpaces -PrettyStructuredPayload -``` - -These provide deterministic limits when monitoring large or deeply nested Event payloads. - ---- - -# Transaction metadata - -The monitor can independently enable or disable: - -```text -stable Event type name -stable Event type ID -schema version -message ID -transport address -dispatch method -priority -origin -hop count -transport acceptance result +ESPressio::Serial::DiagnosticMonitorConfig config; +config.Commands = true; +config.ESPNow = true; ``` -using `EventMonitorConfig`. - -Inbound and outbound monitoring can also be enabled independently. - ---- - -# Borrowed Event Transport data - -ESPressio Event 5.5 transaction snapshots expose borrowed Event/payload references valid only during the Observer callback. - -`EventMonitor` consumes those values synchronously and does not retain borrowed transaction pointers after the callback returns. - -Structured decoding is therefore performed while the payload is valid. - ---- - -# Performance considerations +`Commands` and `ESPNow` default to `false` so upgrading Serial does not silently enable additional output even when those optional libraries happen to be present. -Event Transport transaction observation is synchronous. +Security and Sockets are intentionally not auto-added to the aggregate because they require an explicit runtime instance to observe. -Serial/USB output can be comparatively slow. +## Command console -Enabling Event Monitor—particularly `Lifecycle` mode or large structured payload output—can therefore add diagnostic latency to the Event Transport execution path. +`ESPressio_CommandConsole.hpp` remains the transport-neutral Command-backed console integration. Serial 0.5.0 targets the Command 0.3.x generation but does not change the command execution contract. -This is intentional for a developer-facing monitor, but applications with tight real-time requirements should: +## Event console -- disable monitoring in production; -- use `Summary` or `None` payload modes; -- use an appropriately fast `Print` destination; -- avoid Lifecycle mode except during diagnosis. +`ESPressio_EventConsole.hpp` remains the opt-in operator-facing Event console for runtime discovery, schema description, JSON composition, validation and dispatch of registered Serializable Events. -The Event Monitor changes observation only; it does not change Event routing or transport semantics. +The validated Event baseline for 0.5.0 is **Event 5.8.0+ within the 5.x line**. Serializable/ArduinoJson dependencies remain specific to the EventConsole path. ---- +## Event bridges versus Serial monitors -# Example - -The repository includes: +ESPressio Event 5.8.0 can independently convert the same upstream observations into asynchronous Events. Serial monitors and Event bridges are complementary consumers: ```text -examples/ -└── EventMonitor/ - └── EventMonitor.ino + +--> Serial monitor --> Print +Observer -----+ + +--> Event bridge ---> EventManager ``` -The example uses a small local `LoopbackEventTransport` so both outbound and inbound transactions can be demonstrated on a single ESP32 without networking or additional hardware. - -It defines a Serializable counter Event, transports it through Event 5.5, and renders the Binary payload as structured text. +Serial does not require Event in order to use its Command, Security, Sockets or ESP-Now monitors. ---- +## PlatformIO -# PlatformIO - -A project using only the core Serial library: +Core Serial can still be consumed alone: ```ini lib_deps = - flowduino/ESPressio-Serial@^0.4.0 + flowduino/ESPressio-Serial@^0.5.0 ``` -An application using Event Monitor requires: - -```ini -lib_deps = - flowduino/ESPressio-Serial@^0.4.0 - flowduino/ESPressio-Event@^5.7.1 - flowduino/ESPressio-Serializable@^0.10.0 -``` +Add the ESPressio libraries required by the monitor or console headers selected by the application. -The Event/Serializable dependencies are intentionally not declared as mandatory package dependencies of ESPressio Serial because they are required only by the opt-in Event Monitor feature. +## Compatibility ---- +0.5.0 preserves the existing core Serial, logging, Console, Event Monitor and EventConsole APIs. New monitoring integrations are opt-in. The package metadata intentionally does not make their upstream libraries mandatory. +## License -## PlatformIO: Event Console - -The generic console requires only ESPressio Serial: - -```ini -lib_deps = - flowduino/ESPressio-Serial@^0.4.0 -``` - -The Event Console additionally requires the runtime Event and JSON stacks: - -```ini -lib_deps = - flowduino/ESPressio-Serial@^0.4.0 - flowduino/ESPressio-Event@^5.7.1 - flowduino/ESPressio-Serializable@^0.10.0 - bblanchon/ArduinoJson -``` - -ArduinoJson is required only because `EventConsole` selects ESPressio Serializable's optional `JsonArchive`; it remains unnecessary for core Serial, logging, diagnostics, and the generic Console. - -# Future direction - -ESPressio Serial is intended to contain Serial/console-oriented ESPressio integrations rather than becoming a general communications catch-all. - -Potential future components include: - -```text -Serial Event Transport -structured Event-based remote log sinks -persistent diagnostic sinks -additional subsystem console commands -serial configuration interfaces -serial protocol adapters -operator authentication/session policy where appropriate -``` - -Network/socket implementations belong in **ESPressio Sockets**. - -ESP-NOW implementations belong in **ESPressio ESP-Now**. - -Hardware-radio implementations belong in the planned **ESPressio Radio** library. - ---- - -# Summary - -ESPressio Serial 0.3.0 provides three complementary layers: - -```text -CORE - ESPressio_Serial.hpp - diagnostic types - no mandatory ESPressio dependency - -DIAGNOSTICS / LOGGING - Logger - SerialLogSink - DiagnosticRingBuffer - SystemClockMonitor [opt-in Timing] - ThreadMonitor [opt-in Threads] - EventMonitor [opt-in Event + Serializable] - DiagnosticMonitor - -OPERATOR CONSOLE - Console - Stream input - Print output - extensible commands - - EventConsole [opt-in Event 5.6 + Serializable JSON] - runtime Event discovery - schema description - JSON composition - validation diagnostics - allow/deny policy - confirmation - Queue / Stack dispatch -``` - -The central rule remains unchanged: - -**ESPressio Serial owns human/operator interaction and presentation; the upstream ESPressio libraries continue to own their underlying runtime semantics.** - - -## ESPressio Command Integration (0.4.0) - -Serial 0.4.0 adds an opt-in bridge to **ESPressio Command >= 0.2.0 < 1.0.0**. Core Serial remains usable without Command. Include `ESPressio_CommandConsole.hpp` only when the integration is required. - -```ini -lib_deps = - flowduino/ESPressio-Serial@^0.4.0 - flowduino/ESPressio-Command@^0.2.0 -``` - -```cpp -#include -#include -#include - -ESPressio::Serial::Console console; -ESPressio::Serial::CommandConsole commandConsole; - -void setup() { - console.Initialize(Serial, Serial); - commandConsole.Initialize(console); - - auto& commands = ESPressio::Command::CommandRegistry::GetInstance(); - commands.Command("system").Command("status") - .OnExecute([](const ESPressio::Command::CommandContext&) { - return ESPressio::Command::CommandResult::Ok("System OK"); - }); -} - -void loop() { console.Poll(); } -``` - -`CommandConsole` reuses Serial's existing input/prompt handling and forwards resolvable lines into the shared transport-neutral Command registry. Unknown roots fall through so other Console interceptors and legacy commands can continue to coexist. - -### EventConsole on the shared Command tree - -When Command integration is selected, initialize EventConsole with `CommandConsole`: - -```cpp -ESPressio::Serial::EventConsole eventConsole; -eventConsole.Initialize(commandConsole); -``` - -EventConsole then registers the following shared Command tree with ownership-safe registration handles: - -```text -event list -event describe -event compose [queue|stack] -event queue -event stack -event dispatch -event cancel -events -``` - -Shutdown removes the registered subtrees, preventing callbacks from outliving the EventConsole instance. The previous `Initialize(Console&, ...)` overload remains available for compatibility with existing applications. +Apache License 2.0. See [LICENSE](LICENSE). From a78bbbcf9f4970c73d3131083436369fa957b7e6 Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 19:50:26 +0200 Subject: [PATCH 18/22] docs: restore full README and document observable monitors --- README.md | 1148 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 1062 insertions(+), 86 deletions(-) diff --git a/README.md b/README.md index 019e7b0..f848349 100644 --- a/README.md +++ b/README.md @@ -1,170 +1,1146 @@ # ESPressio Serial -Serial and console-oriented diagnostics, logging and operator tooling for the Flowduino ESPressio Development Platform. +Serial and console-oriented components for the Flowduino ESPressio Development Platform. -## Current Development Version +Version 0.3.0 adds a reusable Stream/Print command console and an opt-in operator-facing Event Console capable of discovering, describing, composing as JSON, validating, and dispatching runtime-registered Serializable Events through ESPressio Event 5.6.1. -This branch targets **ESPressio Serial 0.5.0**. +## Latest Stable Version -0.5.0 extends Serial's diagnostics role with opt-in monitors for the new Observable lifecycle surfaces in ESPressio Command, Security, Sockets and ESP-Now. The originating library remains the source of truth; Serial only subscribes and renders those observations to an Arduino `Print` destination. +The latest stable version is **0.4.0**. -See [CHANGELOG.md](CHANGELOG.md) for release history. +## Current Development Version — 0.5.0 -## Dependency philosophy +The `feature/observable-callback-coverage` branch targets **0.5.0** and extends Serial's diagnostics layer to consume the new Observable lifecycle contracts provided by ESPressio Command, Security, Sockets, and ESP-Now. -The **core ESPressio Serial library remains dependency-free within the ESPressio ecosystem**. Optional facilities are selected explicitly by including their corresponding headers. +Core ESPressio Serial remains free of mandatory ESPressio-library dependencies. The new monitors are selected only when their corresponding upstream headers are available: -Current optional integration baselines are: +```text +CommandMonitor + - - -> ESPressio Command >= 0.3.0 < 1.0.0 + +SecurityMonitor + - - -> ESPressio Security >= 0.2.0 < 1.0.0 + +SocketWorkerMonitor + - - -> ESPressio Sockets >= 0.5.0 < 1.0.0 + +SocketSecuritySessionMonitor + - - -> ESPressio Sockets >= 0.5.0 < 1.0.0 + - - -> ESPressio Security >= 0.2.0 < 1.0.0 + +ESPNowTransportMonitor + - - -> ESPressio ESP-Now >= 0.5.0 < 1.0.0 +``` + +`DiagnosticMonitor` can additionally compose `CommandMonitor` and `ESPNowTransportMonitor` when those dependencies are present. Security and Socket monitors remain instance-oriented because the application must choose the specific `TransportSecurity`, `SocketWorker`, or `SocketSecuritySession` object to observe. + +These monitors subscribe directly to the originating library's Observable contract. They do not invent parallel Serial lifecycle semantics and do not require ESPressio Event. Event-backed observation remains a separate opt-in integration in ESPressio Event 5.8.0. + +The complete historical/stable documentation below remains intact. + +## ESPressio Development Platform + +ESPressio is a collection of discrete, composable component libraries designed around a common development ethos: + +- **Light-weight** +- **Ease of use** +- **Object-oriented design** +- **SOLID design principles** +- **Pay only for the functionality an application selects** + +## License + +Licensed under the **Apache License 2.0**. See [LICENSE](LICENSE). + +## Namespace + +The public API resides beneath: + +```cpp +ESPressio::Serial +``` + +Because Arduino exposes a global object named `Serial`, fully qualified ESPressio Serial names are recommended: + +```cpp +ESPressio::Serial::EventMonitor monitor; +``` + +while the Arduino serial port remains: + +```cpp +::Serial +``` + +## ESPressio Library Dependencies -- **ESPressio Timing >= 2.2.2 and < 3.0.0** — System Clock monitoring. -- **ESPressio Threads >= 3.1.2 and < 4.0.0** — Thread Manager/GC/termination monitoring. -- **ESPressio Event >= 5.8.0 and < 6.0.0** — Event Monitor and EventConsole integrations. -- **ESPressio Serializable >= 0.10.0 and < 1.0.0** — runtime Serializable Event tooling where selected. -- **ESPressio Command >= 0.3.0 and < 1.0.0** — CommandConsole and `CommandMonitor`. -- **ESPressio Security >= 0.2.0 and < 1.0.0** — `SecurityMonitor`. -- **ESPressio Sockets >= 0.5.0 and < 1.0.0** — socket worker/security-session monitors. -- **ESPressio ESP-Now >= 0.5.0 and < 1.0.0** — `ESPNowTransportMonitor`. +The **core ESPressio Serial library has no required ESPressio library dependencies**. -No one of these is introduced as a mandatory dependency of `ESPressio_Serial.hpp`. +The Event Monitor is deliberately opt-in and requires: ```text - +--> Timing monitor - +--> Threads monitor -ESPressio Serial core ---+--> Event monitor / EventConsole - +--> Command console / monitor - +--> Security monitor - +--> Sockets monitors - +--> ESP-Now monitor +ESPressio Event >= 5.7.1 < 6.0.0 +ESPressio Serializable >= 0.10.0 < 1.0.0 +``` + +For the 0.5.0 development branch, the additional opt-in monitoring dependencies are listed in the development-version section above. Existing Event Monitor/EventConsole guidance below remains the stable 0.4.0 baseline unless explicitly identified otherwise. + +For the complete ecosystem hierarchy, see: + +**[ESPressio Library Dependency Chart](ESPRESSIO_DEPENDENCY_CHART.md)** + +In the dependency chart: + +- **Solid relationships** represent required dependencies. +- **Dashed relationships** represent opt-in dependencies introduced only when the associated feature/header is used. + +--- + + + + +## Version 0.3.1 — Event 5.6.1 compatibility + +Version 0.3.1 updates the optional `EventConsole` integration baseline to **ESPressio Event 5.6.1**. -(all relationships above are opt-in) +Event 5.6.1 corrects `EventDispatchContext` equality semantics required by ESPressio Threads 3.1 `ReadWriteMutex` change detection. No ESPressio Serial console, monitoring, logging, or EventConsole public API changes are required. + +Applications using `EventConsole` should therefore target: + +```ini +flowduino/ESPressio-Event@^5.7.1 ``` -See [ESPRESSIO_DEPENDENCY_CHART.md](ESPRESSIO_DEPENDENCY_CHART.md) for the broader ecosystem relationship view. +The core Serial library and generic `Console` remain independent of ESPressio Event. + +--- -## Core umbrella +# Version 0.3.0 — Interactive Runtime Serializable Event Console + +Version 0.3.0 adds the interactive operator/service-console layer. + +The architecture deliberately preserves library ownership: + +```text +operator + | + v +ESPressio Serial Console + | + | JSON + v +ESPressio Serializable JsonArchive + | + | SerializationNode + v +ESPressio Event 5.6 runtime registry/factory + | + v +concrete Serializable Event + | + v +normal Queue / Stack dispatch + | + +--> local listeners + | + +--> EventTransportManager + | + +--> any configured outbound transport +``` + +Serial does not create a second Event registry or remote-dispatch mechanism. + +## Generic `Console` + +The generic console is available independently of Event: ```cpp -#include +#include + +ESPressio::Serial::Console console; + +void setup() { + ::Serial.begin(115200); + + ESPressio::Serial::ConsoleConfig config; + config.Prompt = "espressio> "; + + console.Initialize( + ::Serial, + ::Serial, + config + ); + + console.RegisterCommand( + "hello", + "Print a greeting", + [](const auto& context) { + // Handle context.Arguments. + } + ); +} + +void loop() { + console.Poll(); +} +``` + +Input uses Arduino `Stream`; output uses Arduino `Print`. + +The console therefore works with Hardware Serial, USB CDC, or another compatible implementation. + +The line buffer is bounded through: + +```cpp +ConsoleConfig::MaximumLineLength +``` + +and the console supports: + +```text +command registration +command unregistration +help +arguments +prompt configuration +optional input echo +multiple interactive line interceptors +backspace/delete handling +CR/LF handling +``` + +Multiple line interceptors are intentional: future console extensions can maintain independent interactive states without replacing one global input handler. + +## `EventConsole` + +The Event Console is opt-in: + +```cpp +#include +``` + +and requires: + +```text +ESPressio Event >= 5.7.1 +ESPressio Serializable >= 0.10.0 < 1.0.0 +ArduinoJson (through the optional Serializable JsonArchive) +``` + +Initialize it over an existing `Console`: + +```cpp +ESPressio::Serial::Console console; +ESPressio::Serial::EventConsole eventConsole; + +console.Initialize( + ::Serial, + ::Serial +); + +eventConsole.Initialize( + console +); +``` + +## Safe-by-default Event authorization + +Runtime Event discovery does **not** imply permission to dispatch an Event. + +The default access policy is: + +```cpp +EventConsoleAccessPolicy::AllowListedOnly ``` -The core umbrella exposes common Serial/diagnostic types and documents optional entry points without batch-including their dependencies. +Allow specific Event types: + +```cpp +eventConsole.AllowEvent< + CameraShutterEvent +>(); + +eventConsole.AllowEvent( + "flowduino.motor.move.v1" +); +``` + +For a controlled development environment, explicitly enable all registered types: + +```cpp +eventConsole.SetAccessPolicy( + ESPressio::Serial:: + EventConsoleAccessPolicy:: + AllRegistered +); +``` + +Deny-list entries override allow-all: + +```cpp +eventConsole.DenyEvent< + FactoryResetEvent +>(); +``` + +This prevents a registered administrative/destructive Event from becoming operator-dispatchable merely because a console is enabled. + +## Event discovery + +List runtime-registered Serializable Events: + +```text +espressio> events + +Registered Serializable Events: + flowduino.camera.shutter.v1 [constructible] [allowed] schema=1 defaultRouting=Outbound + flowduino.motor.move.v1 [constructible] [allowed] schema=2 defaultRouting=Bidirectional + flowduino.system.factory-reset.v1 [constructible] [denied] schema=1 defaultRouting=None +``` + +The equivalent command is: + +```text +event list +``` + +## Event schema description + +```text +espressio> event describe flowduino.motor.move.v1 +``` + +uses Event 5.6's runtime descriptor and Serializable schema metadata to report: + +```text +stable Event type name +stable Event type ID +schema version +runtime constructibility +operator access +default Event Transport direction +property names +property types +required state +read-only state +sensitive metadata +default-value availability +aliases +``` + +Per-transport route names are not fabricated: Event 5.6 currently exposes the default routing direction through the public runtime descriptor. + +## One-line JSON dispatch + +Queue: + +```text +event queue flowduino.motor.move.v1 {"axis":"pan","position":45,"speed":20} +``` + +Stack: + +```text +event stack flowduino.motor.move.v1 {"axis":"pan","position":45,"speed":20} +``` + +`event dispatch` is a Queue alias. + +JSON is parsed through ESPressio Serializable's `JsonArchive`, converted to a representation-neutral `SerializationNode`, and passed to Event 5.6's runtime factory. + +## Interactive composition + +```text +event compose flowduino.motor.move.v1 +``` + +or: + +```text +event compose flowduino.motor.move.v1 stack +``` + +prompts for a one-line JSON object: + +```text +Enter one-line JSON object for flowduino.motor.move.v1 (or 'cancel'): +{"axis":"pan","position":45,"speed":20} +``` + +## Serializable validation diagnostics + +Runtime-created Events use the normal ESPressio Serializable validation path. + +Validation errors are presented to the operator with: + +```text +property path +serialization error code +diagnostic message +``` + +For example: + +```text +Event payload validation failed with 2 issue(s): + speed: NumericOutOfRange - Property failed its numeric range constraint + axis: UnknownEnumValue - Value is not a registered enum mapping +``` + +No separate Serial-specific Event validation system exists. + +## Confirmation + +Confirmation is enabled by default: + +```text +Dispatch Event 'flowduino.motor.move.v1' via Queue priority=Normal? [y/N] +``` + +Only `y` or `yes` proceeds; any other response cancels the dispatch. + +It can be disabled explicitly: + +```cpp +EventConsoleConfig config; +config.RequireConfirmation = false; +``` + +## Dispatch semantics + +Event Console uses Event 5.6's ownership-safe runtime dispatch API. + +Once dispatched, the Event follows the normal Event system: + +```text +runtime-created Event + | + v +Queue / Stack + | + v +local Event dispatch + | + v +EventTransportManager + | + v +existing per-transport outbound routing +``` + +Event Console therefore knows nothing about ESP-NOW, UDP, TCP, WebSocket, MQTT, or another concrete Event transport. + +## Audit logging + +`EventConsole` can optionally send security/operation audit records to any existing: + +```cpp +ILoggerSink +``` + +using: + +```cpp +eventConsole.SetAuditSink( + &history +); +``` + +Useful audit conditions include: + +```text +successful operator dispatch +denied dispatch +unregistered type +malformed JSON +oversized JSON +construction/validation failure +dispatch failure +``` + +The Event payload itself is deliberately not copied into the audit message by default, avoiding accidental logging of sensitive properties. + +## Event Monitor integration + +Console-created Events naturally flow through the ordinary Event Transport pipeline. + +If `EventMonitor` is enabled, the same operator-created Event appears in its normal outbound/inbound transaction diagnostics without any special integration code. + +## Limits + +Operator JSON is bounded by: + +```cpp +EventConsoleConfig::MaximumJsonLength +``` + +and the enclosing generic Console independently bounds total input line length. + +Queue and Stack dispatch can be independently disabled: + +```cpp +config.AllowQueue = true; +config.AllowStack = false; +``` + +## Examples + +Version 0.3.0 adds: + +```text +examples/ +├── Console/ +│ └── Console.ino +│ +├── EventConsole/ +│ └── EventConsole.ino +│ +└── EventConsoleLoopback/ + └── EventConsoleLoopback.ino +``` + +`EventConsoleLoopback` combines the operator console, Event Console, Event Monitor, Serializable Event, and a local loopback `IEventTransport` to demonstrate the complete: + +```text +Serial JSON + -> runtime Event + -> local dispatch + -> Event Transport + -> inbound reconstruction + -> Serial Event Monitor +``` + +pipeline on one ESP32. + +## Tests + +The repository includes host-side tests for: + +```text +generic Console command dispatch +argument preservation +multiple interactive line interceptors +interceptor removal +Stream polling +runtime Event listing +Event schema description +allow-list enforcement +JSON command processing +pre-dispatch confirmation +type-erased dispatch +``` + +The Event Console contract test uses narrow test doubles for Event 5.6 and the Serializable JSON adapter, while release preparation verifies compatibility with the real public API surface. + +--- + +# Version 0.2.0 — Diagnostics & Logging + +Version 0.2.0 adds a general diagnostics foundation alongside the existing Event Monitor. ## Logging -The existing logging layer remains available through `ESPressio_Logging.hpp`, including log levels, pluggable sinks, `SerialLogSink`, filtering and retained diagnostic history. +```cpp +#include + +ESPressio::Serial::Logger<> logger; +ESPressio::Serial::SerialLogSink serialSink(::Serial); +ESPressio::Serial::DiagnosticRingBuffer<64> history; + +void setup() { + ::Serial.begin(115200); + + logger.AddSink(serialSink); + logger.AddSink(history); + + logger.SetMinimumLevel( + ESPressio::Serial::LogLevel::Debug + ); + + logger.Info("Application", "Boot complete"); +} +``` + +Supported levels are: + +```text +Trace +Debug +Info +Warning +Error +Critical +Off +``` + +`Logger` supports multiple simultaneous `ILoggerSink` implementations. Logging data is therefore separated from its output destination: Serial is one sink, not the logging architecture itself. + +`ESPRESSIO_SERIAL_COMPILETIME_LOG_LEVEL` may be defined to remove lower-severity calls from runtime delivery, while `SetMinimumLevel()` provides runtime filtering. + +## Diagnostic flight recorder + +`DiagnosticRingBuffer` is both an `ILoggerSink` and a bounded in-memory history. + +```cpp +ESPressio::Serial::DiagnosticRingBuffer<64> history; + +logger.AddSink(history); + +// Later, after a fault: +history.Dump(::Serial); +``` + +Entries are copied into fixed-size storage; the oldest entry is overwritten when capacity is exhausted. This makes it suitable for retaining the diagnostic events immediately preceding a failure without unbounded heap growth. -## Existing monitors +## System Clock Monitor -Serial continues to provide: +```cpp +#include + +ESPressio::Serial::SystemClockMonitor<> clockMonitor; + +clockMonitor.Initialize(::Serial); +``` -- `SystemClockMonitor` — Timing System Clock observer output; -- `ThreadMonitor` — Thread Manager, Garbage Collector and Termination Dispatcher observations; -- `EventMonitor` — Event Transport transaction/event diagnostics; and -- `DiagnosticMonitor` — convenience aggregation of available monitors. +This integration directly consumes ESPressio Timing 2.2.2's `ISystemClockObserver` notifications. It reports time-setting, synchronization acceptance/rejection, synchronization state changes, resets/configuration changes, and callback scheduling/execution. -## Observable subsystem monitors +Synchronization output includes the clock value before correction, the value after correction, and the immediate nanosecond difference. -0.5.0 adds four new opt-in monitoring areas. +This is an opt-in Timing dependency; ESPressio Event is not involved. -### Command +## Thread Monitor ```cpp -#include +#include + +ESPressio::Serial::ThreadMonitor threadMonitor; + +threadMonitor.Initialize(::Serial); +``` -ESPressio::Serial::CommandMonitor monitor; -monitor.Initialize(Serial); +`ThreadMonitor` directly observes the process-wide ESPressio Threads 3.1.2 infrastructure: + +```text +ThreadManager +ThreadGarbageCollector +ThreadTerminationDispatcher ``` -`CommandMonitor` consumes `ICommandRegistryObserver` and prints command-root registration/unregistration lifecycle changes. It does not observe or intercept command execution itself. +It reports registration, cleanup, garbage collection, termination dispatch, initialization, and failure lifecycle notifications. + +This is an opt-in Threads dependency; Event bridges are not required merely to display Thread diagnostics. + +## Aggregate Diagnostic Monitor -### Security +When the corresponding dependency headers are available, the convenience monitor can compose all supported subsystem monitors: ```cpp -#include +#include + +ESPressio::Serial::DiagnosticMonitor diagnostics; + +void setup() { + ::Serial.begin(115200); + + ESPressio::Serial::DiagnosticMonitorConfig config; + + config.SystemClock = true; + config.Threads = true; + config.Events = true; + + diagnostics.Initialize( + ::Serial, + config + ); +} +``` + +The aggregate uses compile-time feature detection. It does not itself make Timing, Threads, Event, or Serializable mandatory package dependencies. + +In the 0.5.0 development branch, `DiagnosticMonitorConfig` additionally supports `Commands` and `ESPNow`. These remain disabled by default and are available only when the corresponding optional upstream headers are present. + +## Dependency model + +```text +ESPressio Serial core + -> no mandatory ESPressio dependency + +Logging + -> no additional ESPressio dependency + +SystemClockMonitor + - - -> ESPressio Timing >= 2.2.2 < 3.0.0 + +ThreadMonitor + - - -> ESPressio Threads >= 3.1.2 < 4.0.0 + +EventMonitor + - - -> ESPressio Event >= 5.7.1 < 6.0.0 + - - -> ESPressio Serializable >= 0.10.0 < 1.0.0 +``` + +All ESPressio relationships remain opt-in. The 0.5.0 development observer monitors add the additional optional relationships documented near the top of this README. + +--- + +# Core include + +```cpp +#include +``` + +The core header contains common ESPressio Serial types only. + +It does **not** include ESPressio Event or ESPressio Serializable. + +Event monitoring is selected explicitly: + +```cpp +#include +``` + +or through the feature batch header: + +```cpp +#include +``` + +--- + +# Event Transport Monitor + +`EventMonitor` consumes the **Event Transport Transaction Observation** API introduced by ESPressio Event 5.5.0. + +It does not implement an Event Transport and does not alter Event routing. + +Conceptually: + +```text +Serializable Event + | + v +EventTransportManager + | + +-----------------------> concrete transport + | + +--> transaction Observer + | + v + EventMonitor + | + v + Arduino Print + | + +--------+--------+ + | | + v v + Serial USB CDC +``` + +Any `Print` implementation may be used. The monitor is therefore not tied specifically to `HardwareSerial`. + +## Initialization + +```cpp +#include + +ESPressio::Serial::EventMonitor + monitor; + +void setup() { + ::Serial.begin(115200); + + ESPressio::Serial:: + EventMonitorConfig + config; + + monitor.Initialize( + ::Serial, + config + ); +} +``` + +`Initialize()` registers the monitor with the selected `EventTransportManager`. + +It does **not** initialize the Event Transport Manager itself. The application remains responsible for its normal Event Transport setup and initialization. + +The monitor unregisters automatically when destroyed or when: + +```cpp +monitor.Shutdown(); +``` + +is called. + +--- + +# Default monitoring behaviour + +The default mode is: + +```cpp +EventMonitorMode::Events +``` + +This is intended to provide one useful record per logical transported Event rather than printing every internal lifecycle transition. + +It reports: + +```text +outbound Event after concrete transport handoff +inbound Event after successful deserialization +inbound rejection +transport processing failure +``` + +For example: -ESPressio::Serial::SecurityMonitor monitor; -monitor.Initialize(Serial, security); +```text +[ESPressio Event] [OUT] [OutboundHandedToTransport] type=flowduino.example.serial.monitored-counter.v1 typeId=0x... schema=1 message=3 transport=0x... dispatch=Queue priority=Normal origin=Local hops=0 accepted=true payloadBytes=... + payload: { + "__schemaVersion": 1, + "counter": 3, + "source": "local" + } ``` -`SecurityMonitor` subscribes to a specific `TransportSecurity` instance and reports configuration changes, session reset/establishment, replay-protection reset and security failures. Key material is never rendered. +and the looped-back inbound Event may then appear as: + +```text +[ESPressio Event] [IN] [InboundDeserialized] type=flowduino.example.serial.monitored-counter.v1 typeId=0x... schema=1 message=3 transport=0x... dispatch=Queue priority=Normal origin=Remote hops=0 payloadBytes=... + payload: { + "__schemaVersion": 1, + "counter": 3, + "source": "local" + } +``` -### Sockets +--- + +# Lifecycle mode + +For deeper diagnostics: ```cpp -#include -#include +config.Mode = + ESPressio::Serial:: + EventMonitorMode::Lifecycle; +``` + +prints every Event 5.5 transaction stage exposed by `EventTransportManager`: + +```text +OutboundAccepted +OutboundSerialized +OutboundHandedToTransport + +InboundAccepted +InboundRejected +InboundDeserialized +InboundDispatched + +Failed ``` -`SocketWorkerMonitor` subscribes to a specific `SocketWorker` and reports start/start-failure/stop transitions. +Lifecycle mode is intentionally verbose and is most useful while debugging the transport pipeline itself. -`SocketSecuritySessionMonitor` subscribes to a specific `SocketSecuritySession` and reports secure-session faults and explicit resets. +--- -The instance-specific API is deliberate: Serial does not invent a global socket/session registry where the Sockets library does not own one. +# Payload formatting -### ESP-Now +The Event Monitor supports: ```cpp -#include +EventMonitorPayloadFormat::None +EventMonitorPayloadFormat::Summary +EventMonitorPayloadFormat::Hex +EventMonitorPayloadFormat::Structured +``` + +## `None` -ESPressio::Serial::ESPNowTransportMonitor monitor; -monitor.Initialize(Serial); +Only transaction metadata is printed. + +## `Summary` + +Reports payload size without printing payload contents. + +## `Hex` + +Prints the Serializable Binary Archive bytes in hexadecimal. + +The maximum number of bytes is controlled by: + +```cpp +config.MaximumHexPayloadBytes ``` -`ESPNowTransportMonitor` consumes the shared `ESPNowTransport` observer surface and reports initialization, shutdown, peer lifecycle, and send acceptance/failure observations. +## `Structured` + +`Structured` is the default. + +ESPressio Event Transport serializes Event payloads using ESPressio Serializable's `BinaryArchive`. + +The monitor decodes that Binary Archive into Serializable's generic `SerializationNode` tree and renders it directly as JSON-like structured text. + +This has two important advantages: + +1. the monitor does not need to know the concrete C++ Event type; +2. it does not require ArduinoJson merely to present human-readable diagnostics. + +The monitor is therefore able to inspect arbitrary transported Serializable Event payloads using the schema already encoded in the Binary Archive. -## Aggregate DiagnosticMonitor +--- -`DiagnosticMonitor` continues to auto-compose integrations that can be located at compile time. +# Structured-output limits -The existing `SystemClock`, `Threads` and `Events` defaults are preserved. 0.5.0 adds: +Diagnostic output should not be allowed to grow without bound. + +Configuration includes: ```cpp -ESPressio::Serial::DiagnosticMonitorConfig config; -config.Commands = true; -config.ESPNow = true; +MaximumCollectionItems +MaximumStringLength +MaximumStructuredDepth +IndentSpaces +PrettyStructuredPayload +``` + +These provide deterministic limits when monitoring large or deeply nested Event payloads. + +--- + +# Transaction metadata + +The monitor can independently enable or disable: + +```text +stable Event type name +stable Event type ID +schema version +message ID +transport address +dispatch method +priority +origin +hop count +transport acceptance result ``` -`Commands` and `ESPNow` default to `false` so upgrading Serial does not silently enable additional output even when those optional libraries happen to be present. +using `EventMonitorConfig`. + +Inbound and outbound monitoring can also be enabled independently. + +--- + +# Borrowed Event Transport data + +ESPressio Event 5.5 transaction snapshots expose borrowed Event/payload references valid only during the Observer callback. + +`EventMonitor` consumes those values synchronously and does not retain borrowed transaction pointers after the callback returns. + +Structured decoding is therefore performed while the payload is valid. -Security and Sockets are intentionally not auto-added to the aggregate because they require an explicit runtime instance to observe. +--- -## Command console +# Performance considerations -`ESPressio_CommandConsole.hpp` remains the transport-neutral Command-backed console integration. Serial 0.5.0 targets the Command 0.3.x generation but does not change the command execution contract. +Event Transport transaction observation is synchronous. -## Event console +Serial/USB output can be comparatively slow. -`ESPressio_EventConsole.hpp` remains the opt-in operator-facing Event console for runtime discovery, schema description, JSON composition, validation and dispatch of registered Serializable Events. +Enabling Event Monitor—particularly `Lifecycle` mode or large structured payload output—can therefore add diagnostic latency to the Event Transport execution path. -The validated Event baseline for 0.5.0 is **Event 5.8.0+ within the 5.x line**. Serializable/ArduinoJson dependencies remain specific to the EventConsole path. +This is intentional for a developer-facing monitor, but applications with tight real-time requirements should: -## Event bridges versus Serial monitors +- disable monitoring in production; +- use `Summary` or `None` payload modes; +- use an appropriately fast `Print` destination; +- avoid Lifecycle mode except during diagnosis. -ESPressio Event 5.8.0 can independently convert the same upstream observations into asynchronous Events. Serial monitors and Event bridges are complementary consumers: +The Event Monitor changes observation only; it does not change Event routing or transport semantics. + +--- + +# Example + +The repository includes: ```text - +--> Serial monitor --> Print -Observer -----+ - +--> Event bridge ---> EventManager +examples/ +└── EventMonitor/ + └── EventMonitor.ino ``` -Serial does not require Event in order to use its Command, Security, Sockets or ESP-Now monitors. +The example uses a small local `LoopbackEventTransport` so both outbound and inbound transactions can be demonstrated on a single ESP32 without networking or additional hardware. + +It defines a Serializable counter Event, transports it through Event 5.5, and renders the Binary payload as structured text. -## PlatformIO +--- -Core Serial can still be consumed alone: +# PlatformIO + +A project using only the core Serial library: ```ini lib_deps = - flowduino/ESPressio-Serial@^0.5.0 + flowduino/ESPressio-Serial@^0.4.0 ``` -Add the ESPressio libraries required by the monitor or console headers selected by the application. +An application using Event Monitor requires: -## Compatibility +```ini +lib_deps = + flowduino/ESPressio-Serial@^0.4.0 + flowduino/ESPressio-Event@^5.7.1 + flowduino/ESPressio-Serializable@^0.10.0 +``` -0.5.0 preserves the existing core Serial, logging, Console, Event Monitor and EventConsole APIs. New monitoring integrations are opt-in. The package metadata intentionally does not make their upstream libraries mandatory. +The Event/Serializable dependencies are intentionally not declared as mandatory package dependencies of ESPressio Serial because they are required only by the opt-in Event Monitor feature. -## License +--- + + +## PlatformIO: Event Console + +The generic console requires only ESPressio Serial: + +```ini +lib_deps = + flowduino/ESPressio-Serial@^0.4.0 +``` + +The Event Console additionally requires the runtime Event and JSON stacks: + +```ini +lib_deps = + flowduino/ESPressio-Serial@^0.4.0 + flowduino/ESPressio-Event@^5.7.1 + flowduino/ESPressio-Serializable@^0.10.0 + bblanchon/ArduinoJson +``` + +ArduinoJson is required only because `EventConsole` selects ESPressio Serializable's optional `JsonArchive`; it remains unnecessary for core Serial, logging, diagnostics, and the generic Console. + +# Future direction + +ESPressio Serial is intended to contain Serial/console-oriented ESPressio integrations rather than becoming a general communications catch-all. + +Potential future components include: + +```text +Serial Event Transport +structured Event-based remote log sinks +persistent diagnostic sinks +additional subsystem console commands +serial configuration interfaces +serial protocol adapters +operator authentication/session policy where appropriate +``` + +Network/socket implementations belong in **ESPressio Sockets**. + +ESP-NOW implementations belong in **ESPressio ESP-Now**. + +Hardware-radio implementations belong in the planned **ESPressio Radio** library. + +--- + +# Summary + +ESPressio Serial 0.3.0 provides three complementary layers: + +```text +CORE + ESPressio_Serial.hpp + diagnostic types + no mandatory ESPressio dependency + +DIAGNOSTICS / LOGGING + Logger + SerialLogSink + DiagnosticRingBuffer + SystemClockMonitor [opt-in Timing] + ThreadMonitor [opt-in Threads] + EventMonitor [opt-in Event + Serializable] + DiagnosticMonitor + +OPERATOR CONSOLE + Console + Stream input + Print output + extensible commands + + EventConsole [opt-in Event 5.6 + Serializable JSON] + runtime Event discovery + schema description + JSON composition + validation diagnostics + allow/deny policy + confirmation + Queue / Stack dispatch +``` + +The central rule remains unchanged: + +**ESPressio Serial owns human/operator interaction and presentation; the upstream ESPressio libraries continue to own their underlying runtime semantics.** + + +## ESPressio Command Integration (0.4.0) + +Serial 0.4.0 adds an opt-in bridge to **ESPressio Command >= 0.2.0 < 1.0.0**. Core Serial remains usable without Command. Include `ESPressio_CommandConsole.hpp` only when the integration is required. + +```ini +lib_deps = + flowduino/ESPressio-Serial@^0.4.0 + flowduino/ESPressio-Command@^0.2.0 +``` + +```cpp +#include +#include +#include + +ESPressio::Serial::Console console; +ESPressio::Serial::CommandConsole commandConsole; + +void setup() { + console.Initialize(Serial, Serial); + commandConsole.Initialize(console); + + auto& commands = ESPressio::Command::CommandRegistry::GetInstance(); + commands.Command("system").Command("status") + .OnExecute([](const ESPressio::Command::CommandContext&) { + return ESPressio::Command::CommandResult::Ok("System OK"); + }); +} + +void loop() { console.Poll(); } +``` + +`CommandConsole` reuses Serial's existing input/prompt handling and forwards resolvable lines into the shared transport-neutral Command registry. Unknown roots fall through so other Console interceptors and legacy commands can continue to coexist. + +### EventConsole on the shared Command tree + +When Command integration is selected, initialize EventConsole with `CommandConsole`: + +```cpp +ESPressio::Serial::EventConsole eventConsole; +eventConsole.Initialize(commandConsole); +``` + +EventConsole then registers the following shared Command tree with ownership-safe registration handles: + +```text +event list +event describe +event compose [queue|stack] +event queue +event stack +event dispatch +event cancel +events +``` -Apache License 2.0. See [LICENSE](LICENSE). +Shutdown removes the registered subtrees, preventing callbacks from outliving the EventConsole instance. The previous `Initialize(Console&, ...)` overload remains available for compatibility with existing applications. From 33b78fdba489e37930cee4aad6642b9a4688ba32 Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 21:10:51 +0200 Subject: [PATCH 19/22] ci: validate Serial 0.5.0 against released observer dependencies --- .github/workflows/host-tests.yml | 102 ++++++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 3 deletions(-) diff --git a/.github/workflows/host-tests.yml b/.github/workflows/host-tests.yml index 533a8cb..6c7345b 100644 --- a/.github/workflows/host-tests.yml +++ b/.github/workflows/host-tests.yml @@ -2,7 +2,7 @@ name: Host Tests on: push: - branches: [main] + branches: [main, feature/observable-callback-coverage] pull_request: jobs: @@ -11,11 +11,11 @@ jobs: steps: - name: Checkout Serial uses: actions/checkout@v4 - - name: Checkout ESPressio Command 0.2.0 + - name: Checkout ESPressio Command 0.3.0 uses: actions/checkout@v4 with: repository: Flowduino/ESPressio-Command - ref: 0.2.0 + ref: 0.3.0 path: deps/ESPressio-Command - name: Configure run: cmake -S tests -B build -DESPRESSIO_COMMAND_INCLUDE_DIR="$GITHUB_WORKSPACE/deps/ESPressio-Command/src" @@ -23,3 +23,99 @@ jobs: run: cmake --build build --parallel - name: Test run: ctest --test-dir build --output-on-failure + + esp32-observable-monitors: + runs-on: ubuntu-latest + steps: + - name: Checkout Serial + uses: actions/checkout@v4 + with: + path: project/ESPressio-Serial + - name: Checkout ESPressio Observable 3.0.1 + uses: actions/checkout@v4 + with: + repository: Flowduino/ESPressio-Observable + ref: 3.0.1 + path: project/dependencies/ESPressio-Observable + - name: Checkout ESPressio Units 0.2.1 + uses: actions/checkout@v4 + with: + repository: Flowduino/ESPressio-Units + ref: 0.2.1 + path: project/dependencies/ESPressio-Units + - name: Checkout ESPressio Timing 2.2.2 + uses: actions/checkout@v4 + with: + repository: Flowduino/ESPressio-Timing + ref: 2.2.2 + path: project/dependencies/ESPressio-Timing + - name: Checkout ESPressio Command 0.3.0 + uses: actions/checkout@v4 + with: + repository: Flowduino/ESPressio-Command + ref: 0.3.0 + path: project/dependencies/ESPressio-Command + - name: Checkout ESPressio Security 0.2.0 + uses: actions/checkout@v4 + with: + repository: Flowduino/ESPressio-Security + ref: 0.2.0 + path: project/dependencies/ESPressio-Security + - name: Checkout ESPressio Sockets 0.5.0 + uses: actions/checkout@v4 + with: + repository: Flowduino/ESPressio-Sockets + ref: 0.5.0 + path: project/dependencies/ESPressio-Sockets + - name: Checkout ESPressio ESP-Now 0.5.0 + uses: actions/checkout@v4 + with: + repository: Flowduino/ESPressio-ESP-Now + ref: 0.5.0 + path: project/dependencies/ESPressio-ESP-Now + - uses: actions/setup-python@v5 + with: + python-version: '3.x' + - name: Install PlatformIO + run: pip install platformio + - name: Create monitor compile project + shell: bash + run: | + mkdir -p project/compile/src + cat > project/compile/platformio.ini <<'EOF' + [env:esp32] + platform = espressif32 + board = esp32dev + framework = arduino + build_flags = + -std=gnu++17 + -frtti + -I../dependencies/ESPressio-Command/src + -I../dependencies/ESPressio-Security/src + -I../dependencies/ESPressio-Sockets/src + -I../dependencies/ESPressio-ESP-Now/src + build_unflags = + -std=gnu++11 + -fno-rtti + lib_ldf_mode = deep+ + lib_deps = + WiFi + ../dependencies/ESPressio-Observable + ../dependencies/ESPressio-Units + ../dependencies/ESPressio-Timing + ../ESPressio-Serial + EOF + cat > project/compile/src/main.cpp <<'EOF' + #include + #include + #include + #include + #include + #include + #include + + void setup() {} + void loop() {} + EOF + - name: Compile ESP32 Observable monitors + run: pio run -d project/compile From 511e288f68eab5d75bb72d15fb3f495817c5fbfd Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 21:11:10 +0200 Subject: [PATCH 20/22] docs: refresh Serial 0.5.0 dependency chart --- ESPRESSIO_DEPENDENCY_CHART.md | 98 +++++++++++++++++++++++------------ 1 file changed, 66 insertions(+), 32 deletions(-) diff --git a/ESPRESSIO_DEPENDENCY_CHART.md b/ESPRESSIO_DEPENDENCY_CHART.md index c9181e7..df06c04 100644 --- a/ESPRESSIO_DEPENDENCY_CHART.md +++ b/ESPRESSIO_DEPENDENCY_CHART.md @@ -4,7 +4,7 @@ ## Purpose -This document describes the current dependency relationships between ESPressio libraries. +This document describes the current dependency relationships between ESPressio libraries relevant to ESPressio Serial 0.5.0. The chart is hierarchical: libraries with no **required** ESPressio dependencies appear at the top, while libraries that build on progressively more of the ecosystem appear lower. @@ -12,80 +12,114 @@ The chart is hierarchical: libraries with no **required** ESPressio dependencies - **Dashed arrow** — opt-in dependency activated only by the associated feature/header. - Arrows point from the dependent library to the library it consumes. -## ESPressio Serial 0.4.0 +## ESPressio Serial 0.5.0 The ESPressio Serial core and generic `Console` have no required ESPressio dependency. All integrations remain opt-in. -### CommandConsole +### CommandConsole and CommandMonitor -`CommandConsole` consumes: +`CommandConsole` and `CommandMonitor` consume: ```text -ESPressio Command >= 0.2.0 < 1.0.0 +ESPressio Command >= 0.3.0 < 1.0.0 ``` -Command supplies the transport-neutral typed Command registry, parsing, validation, invocation, help/completion metadata, and ownership-safe scoped command registration used by dynamic Serial integrations. +Command supplies the transport-neutral typed Command registry, parsing, validation, invocation, help/completion metadata, scoped command registration, and Observable registry lifecycle used by Serial's Command integrations. -### EventMonitor +### SecurityMonitor -`EventMonitor` consumes: +`SecurityMonitor` consumes: ```text -ESPressio Event >= 5.7.1 < 6.0.0 -ESPressio Serializable >= 0.10.0 < 1.0.0 +ESPressio Security >= 0.2.0 < 1.0.0 ``` -Event supplies the Event Transport Transaction Observation stream. +Security supplies the Observable configuration, secure-session, replay-protection, and failure lifecycle observed directly by the monitor. -Serializable supplies structured payload decoding used for human-readable diagnostic output. +### Socket monitors -### Timing and Threads monitors +`SocketWorkerMonitor` consumes: -`SystemClockMonitor` optionally consumes: +```text +ESPressio Sockets >= 0.5.0 < 1.0.0 +``` + +`SocketSecuritySessionMonitor` consumes: ```text -ESPressio Timing >= 2.2.2 < 3.0.0 +ESPressio Sockets >= 0.5.0 < 1.0.0 +ESPressio Security >= 0.2.0 < 1.0.0 ``` -`ThreadMonitor` optionally consumes: +Sockets supplies the Observable socket worker and secure-session lifecycle contracts. Security is only relevant to the secure-session integration. + +### ESPNowTransportMonitor + +`ESPNowTransportMonitor` consumes: ```text -ESPressio Threads >= 3.1.2 < 4.0.0 +ESPressio ESP-Now >= 0.5.0 < 1.0.0 ``` -## ESPressio Serial Event Console +ESP-Now supplies the Observable transport, peer, and send lifecycle contract. -The legacy EventConsole initialization path remains supported for compatibility. +### EventMonitor and EventConsole -The recommended Serial 0.4.0 Command-backed EventConsole integration consumes: +`EventMonitor` consumes: ```text -ESPressio Command >= 0.2.0 < 1.0.0 -ESPressio Event >= 5.7.1 < 6.0.0 +ESPressio Event >= 5.8.0 < 6.0.0 ESPressio Serializable >= 0.10.0 < 1.0.0 ``` -Command supplies the shared `event`/`events` command tree and scoped registration lifetime. +Event supplies the Event Transport Transaction Observation stream. Serializable supplies structured payload decoding used for human-readable diagnostic output. -Event supplies runtime Serializable Event discovery, descriptors, construction and dispatch. +The legacy EventConsole initialization path remains supported for compatibility. The recommended Command-backed EventConsole integration consumes: -Serializable supplies `JsonArchive` and validation diagnostics. +```text +ESPressio Command >= 0.3.0 < 1.0.0 +ESPressio Event >= 5.8.0 < 6.0.0 +ESPressio Serializable >= 0.10.0 < 1.0.0 +``` + +Command supplies the shared `event`/`events` command tree and scoped registration lifetime. Event supplies runtime Serializable Event discovery, descriptors, construction and dispatch. Serializable supplies `JsonArchive` and validation diagnostics. The external ArduinoJson dependency is required only by the optional Serializable `JsonArchive`; it is outside this ESPressio-to-ESPressio dependency chart. -Applications using only the core ESPressio Serial layer acquire none of these optional ESPressio dependencies. +### Timing and Threads monitors + +`SystemClockMonitor` optionally consumes: + +```text +ESPressio Timing >= 2.2.2 < 3.0.0 +``` + +`ThreadMonitor` optionally consumes: -## Other current relationships +```text +ESPressio Threads >= 3.1.2 < 4.0.0 +``` + +### Event bridges versus Serial monitors + +The 0.5.0 Observable monitors subscribe directly to the originating subsystem. They do not require ESPressio Event. + +ESPressio Event 5.8.0 separately supplies optional Event bridges for Command, Security, Sockets, and ESP-Now when asynchronous Event conversion is desired. Serial diagnostics therefore remain usable without introducing Event as an intermediary. + +## Current ecosystem relationships - Observable 3.0.1 has no mandatory ESPressio dependencies. - Serializable 0.10.0 has no mandatory ESPressio dependencies. - Units 0.2.1 optionally consumes Serializable for Serializable Unit counterparts. - Timing 2.2.2 requires Units and Observable. - Threads 3.1.2 requires Timing and Observable. -- Event 5.7.1 requires Threads, Timing, and Observable; Serializable functionality remains opt-in. -- ESP-Now 0.2.3 requires Timing and optionally Event for ESP-NOW Event Transport. -- Sockets 0.2.3 has no mandatory ESPressio dependency but optionally consumes Event and Timing. -- Command 0.2.0 has no mandatory ESPressio dependencies. -- Serial 0.4.0 has no mandatory ESPressio dependencies; Command/Event/Serializable/Timing/Threads integrations are opt-in. +- Security 0.2.0 requires Observable; Event conversion is opt-in downstream through Event 5.8.0. +- Command 0.3.0 requires Observable; Event conversion is opt-in downstream through Event 5.8.0. +- Sockets 0.5.0 consumes Observable for lifecycle observation and optionally integrates Command and Security. +- ESP-Now 0.5.0 requires Timing and Observable and optionally integrates Command, Security, and Event transport functionality. +- Event 5.8.0 requires Threads, Timing, and Observable and optionally bridges Security, Command, Sockets, and ESP-Now observer contracts. +- Serial 0.5.0 has no mandatory ESPressio dependencies; Command, Security, Sockets, ESP-Now, Event, Serializable, Timing, and Threads integrations are all opt-in. + +Applications using only the core ESPressio Serial layer acquire none of these optional ESPressio dependencies. From 8eb21075df369bad7a003a5b079f6eab493adfcc Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 21:12:40 +0200 Subject: [PATCH 21/22] test: include Observable for Command 0.3.0 host contracts --- tests/CMakeLists.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index fb5ec3f..29beb05 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -4,6 +4,7 @@ project(ESPressioSerialTests LANGUAGES CXX) enable_testing() set(ESPRESSIO_COMMAND_INCLUDE_DIR "" CACHE PATH "Path containing ESPressio_Command.hpp") +set(ESPRESSIO_OBSERVABLE_INCLUDE_DIR "" CACHE PATH "Path containing ESPressio_Observable.hpp") add_executable( test_console @@ -22,7 +23,7 @@ add_executable( target_compile_features(test_event_console PRIVATE cxx_std_17) target_compile_options(test_event_console PRIVATE -Wall -Wextra -Wpedantic -Werror) -target_include_directories(test_event_console PRIVATE stubs ../src ${ESPRESSIO_COMMAND_INCLUDE_DIR}) +target_include_directories(test_event_console PRIVATE stubs ../src ${ESPRESSIO_COMMAND_INCLUDE_DIR} ${ESPRESSIO_OBSERVABLE_INCLUDE_DIR}) add_test(NAME EventConsoleContract COMMAND test_event_console) add_executable( @@ -32,5 +33,5 @@ add_executable( target_compile_features(test_command_console PRIVATE cxx_std_17) target_compile_options(test_command_console PRIVATE -Wall -Wextra -Wpedantic -Werror) -target_include_directories(test_command_console PRIVATE stubs ../src ${ESPRESSIO_COMMAND_INCLUDE_DIR}) +target_include_directories(test_command_console PRIVATE stubs ../src ${ESPRESSIO_COMMAND_INCLUDE_DIR} ${ESPRESSIO_OBSERVABLE_INCLUDE_DIR}) add_test(NAME CommandConsoleContract COMMAND test_command_console) From 7aee430412708a621f4c314038e84c9663b76ec3 Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 21:13:05 +0200 Subject: [PATCH 22/22] ci: include Observable in Command 0.3.0 host validation --- .github/workflows/host-tests.yml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/host-tests.yml b/.github/workflows/host-tests.yml index 6c7345b..de55e1b 100644 --- a/.github/workflows/host-tests.yml +++ b/.github/workflows/host-tests.yml @@ -17,8 +17,17 @@ jobs: repository: Flowduino/ESPressio-Command ref: 0.3.0 path: deps/ESPressio-Command + - name: Checkout ESPressio Observable 3.0.1 + uses: actions/checkout@v4 + with: + repository: Flowduino/ESPressio-Observable + ref: 3.0.1 + path: deps/ESPressio-Observable - name: Configure - run: cmake -S tests -B build -DESPRESSIO_COMMAND_INCLUDE_DIR="$GITHUB_WORKSPACE/deps/ESPressio-Command/src" + run: >- + cmake -S tests -B build + -DESPRESSIO_COMMAND_INCLUDE_DIR="$GITHUB_WORKSPACE/deps/ESPressio-Command/src" + -DESPRESSIO_OBSERVABLE_INCLUDE_DIR="$GITHUB_WORKSPACE/deps/ESPressio-Observable/src" - name: Build run: cmake --build build --parallel - name: Test @@ -99,7 +108,6 @@ jobs: -fno-rtti lib_ldf_mode = deep+ lib_deps = - WiFi ../dependencies/ESPressio-Observable ../dependencies/ESPressio-Units ../dependencies/ESPressio-Timing