|
SensESP 3.4.1-alpha
Universal Signal K sensor toolkit ESP32
|
The websocket connection to the Signal K server. More...
#include <sensesp/signalk/signalk_ws_client.h>
Classes | |
| struct | ReceivedUpdate |
| A single received delta entry awaiting dispatch on the main task. More... | |
Public Member Functions | |
| SKWSClient (const String &config_path, std::shared_ptr< SKDeltaQueue > sk_delta_queue, const String &server_address, uint16_t server_port, bool use_mdns=true) | |
| const String | get_server_address () const |
| uint16_t | get_server_port () const |
| virtual bool | to_json (JsonObject &root) override final |
| virtual bool | from_json (const JsonObject &config) override final |
| ValueProducer< int > & | get_delta_tx_count_producer () |
| ValueProducer< int > & | get_delta_rx_count_producer () |
| Get the delta rx count producer object. | |
| String | get_connection_status () |
| Get a String representation of the current connection state. | |
| void | on_disconnected () |
| Called when the websocket connection is disconnected. | |
| void | on_error (int handshake_status) |
| void | on_connected () |
| Called when the websocket connection is established. | |
| void | on_receive_delta (uint8_t *payload, size_t length) |
| Called when the websocket receives a delta. | |
| void | on_receive_updates (JsonDocument &message) |
| Called when a delta update is received. | |
| void | on_receive_put (JsonDocument &message) |
| Called when a PUT event is received. | |
| void | connect () |
| void | loop () |
| bool | is_connected () |
| void | restart () |
| Drop the current connection (detached, non-blocking teardown) and let the reconnect path rebuild it. | |
| bool | is_connect_due () const |
| void | send_delta () |
| void | sendTXT (String &payload) |
| Send some processed data to the websocket. | |
| bool | is_ssl_enabled () const |
| Check if SSL/TLS is enabled. | |
| String | get_auth_token () const |
| Current Signal K access token, or an empty string if none. | |
| void | set_ssl_enabled (bool enabled) |
| Enable or disable SSL/TLS manually. | |
| bool | is_send_meta_enabled () const |
Whether the WS subscribes with sendMeta=all. | |
| void | set_send_meta_enabled (bool enabled) |
| bool | is_tofu_enabled () const |
| Check if TOFU certificate verification is enabled. | |
| void | set_tofu_enabled (bool enabled) |
| Enable or disable TOFU certificate verification. | |
| bool | has_tofu_anchor () const |
| True if any trust anchor (pinned CA or leaf fingerprint) is stored. | |
| bool | has_tofu_ca () const |
| True if a pinned CA certificate is stored (CA-anchor mode). | |
| const String & | get_tofu_ca () const |
| bool | has_tofu_fingerprint () const |
| True if a pinned leaf fingerprint is stored (leaf-fingerprint mode). | |
| const String & | get_tofu_fingerprint () const |
| const String & | get_tofu_pin_cn () const |
| Identity (CN) of whatever is pinned, and whether it is a CA. | |
| bool | is_tofu_pin_ca () const |
| const String & | get_tofu_san () const |
| TOFU'd leaf identity (normalized DNS SAN set) bound in CA-anchor mode. A reconnecting leaf must chain to the pinned CA AND present this same identity, so a different leaf from the same CA is rejected. Empty in leaf-fingerprint mode (the fingerprint already binds identity). | |
| void | reset_tofu () |
| Reset the stored trust anchor (CA or leaf fingerprint). | |
| void | stash_pending_ca (const String &ca_pem, const String &cn) |
| Stash a candidate anchor seen during a handshake. Persisted only after the connection succeeds (commit_pending_tofu), so an unauthenticated MITM handshake cannot plant a trust anchor. | |
| void | stash_pending_leaf (const String &fingerprint, const String &cn) |
| void | set_pending_san (const String &san) |
| Record the leaf's identity (SAN set) for the pending CA anchor, captured at depth 0 and committed alongside the CA on success. | |
| void | clear_pending_tofu () |
| bool | has_pending_ca () const |
| True if a candidate CA has already been stashed this handshake. | |
| void | commit_pending_tofu () |
| Persist a stashed anchor after a successful (authenticated) connection. Called from on_connected(). | |
| void | flag_cert_error () |
| Flag a certificate rejection from the verify callback so the next disconnect surfaces as kSKWSCertificateError rather than a plain disconnect. | |
| uint32_t | client_generation () const |
| Generation tag of the currently-valid client. The event handler compares the generation it was registered with against this to drop callbacks from a client that has been handed off for destruction. | |
Public Member Functions inherited from sensesp::FileSystemSaveable | |
| FileSystemSaveable (const String &config_path) | |
| virtual bool | load () override |
| Load and populate the object from a persistent storage. | |
| virtual bool | save () override |
| Save the object to a persistent storage. | |
| virtual bool | clear () override |
| Delete the data from a persistent storage. | |
| bool | find_config_file (const String &config_path, String &filename) |
Public Member Functions inherited from sensesp::Saveable | |
| Saveable (const String &config_path) | |
| virtual bool | refresh () |
| Refresh the object. This may or may not access the persistent storage but is not expected to overwrite the object's state. | |
| const String & | get_config_path () const |
Public Member Functions inherited from sensesp::ValueProducer< SKWSConnectionState > | |
| ValueProducer () | |
| ValueProducer (const SKWSConnectionState &initial_value) | |
| virtual const SKWSConnectionState & | get () const |
| std::enable_if< std::is_base_of< ValueConsumer< typenameVConsumer::input_type >, VConsumer >::value &&std::is_convertible< SKWSConnectionState, typenameVConsumer::input_type >::value, std::shared_ptr< VConsumer > >::type | connect_to (std::shared_ptr< VConsumer > consumer) |
| Connect a producer to a transform with a different input type. | |
| std::enable_if< std::is_base_of< ValueConsumer< typenameVConsumer::input_type >, VConsumer >::value &&std::is_convertible< SKWSConnectionState, typenameVConsumer::input_type >::value, VConsumer * >::type | connect_to (VConsumer *consumer) |
| std::enable_if< std::is_base_of< ValueConsumer< typenameVConsumer::input_type >, VConsumer >::value &&std::is_convertible< SKWSConnectionState, typenameVConsumer::input_type >::value, VConsumer * >::type | connect_to (VConsumer &consumer) |
| void | emit (const SKWSConnectionState &new_value) |
Public Member Functions inherited from sensesp::Observable | |
| Observable () | |
| Observable (Observable &&other) | |
| Move constructor. | |
| void | notify () |
| int | attach (std::function< void()> observer) |
| Attach an observer callback. | |
| void | detach (int id) |
| Remove a previously attached observer by its ID. | |
Protected Member Functions | |
| bool | take_received_updates_semaphore (unsigned long int timeout_ms=0) |
| void | release_received_updates_semaphore () |
| void | enqueue_received_update (ReceivedUpdate &&update) |
Push a received delta entry onto the queue, enforcing a per-kind budget so a metadata burst (one meta-delta per subscribed path at subscribe time when sendMeta=all is enabled) cannot evict pending value deltas, and vice versa. Caller must hold received_updates_semaphore_. | |
| void | process_received_updates () |
| Loop through the received updates and process them. | |
| void | test_token (const String host, const uint16_t port) |
| void | send_access_request (const String host, const uint16_t port) |
| void | poll_access_request (const String host, const uint16_t port, const String href) |
| void | connect_ws (const String &host, const uint16_t port) |
| void | detach_teardown () |
| Hand client_ to a detached one-shot task that stops+destroys it, so the blocking teardown never runs on the caller's context. Nulls client_ and bumps client_generation_ / sets teardown_in_progress_ immediately; no-op if client_ is null. If the reaper task can't be spawned (OOM), the handle is stashed in pending_teardown_ and the spawn is retried on the next event-loop tick – never reaped synchronously, which would block the loop. | |
| void | reap_async (esp_websocket_client_handle_t old) |
Spawn the detached reaper for old; on spawn failure (OOM) stash it in pending_teardown_ for a later retry instead of blocking the loop with a synchronous reap. No-op if old is null. Call on the event-loop context. | |
| void | run_connect_attempt () |
| The (blocking) connect attempt — mDNS resolve, SSL detect, and the access-request / poll / connect_ws leg. Run on a one-shot worker task so none of it blocks the SK/event-loop context. connect() is the dispatcher. | |
| void | subscribe_listeners () |
| Subscribes the SK delta paths to the websocket. | |
| bool | get_mdns_service (String &server_address, uint16_t &server_port) |
| bool | detect_ssl () |
| void | set_connection_state (SKWSConnectionState state) |
| SKWSConnectionState | get_connection_state () |
| void | schedule_reconnect () |
| void | reset_reconnect_interval () |
Static Protected Member Functions | |
| static void | teardown_task (void *arg) |
| Body of the detached teardown task (stop+destroy+self-delete). | |
| static void | connect_worker (void *arg) |
Protected Attributes | |
| String | server_address_ = "" |
| uint16_t | server_port_ = 80 |
| String | conf_server_address_ = "" |
| uint16_t | conf_server_port_ = 0 |
| bool | use_mdns_ = true |
| String | client_id_ = "" |
| String | polling_href_ = "" |
| String | auth_token_ = NULL_AUTH_TOKEN |
| unsigned long | next_attempt_ms_ = 0 |
| unsigned long | connect_interval_ms_ = 2000 |
| bool | ssl_enabled_ = false |
| bool | tofu_enabled_ = true |
| bool | send_meta_enabled_ = true |
| String | tofu_fingerprint_ = "" |
| String | tofu_ca_pem_ = "" |
| String | tofu_san_ = "" |
| String | tofu_pin_cn_ = "" |
| bool | tofu_pin_is_ca_ = false |
| String | pending_ca_pem_ = "" |
| String | pending_fingerprint_ = "" |
| String | pending_cn_ = "" |
| String | pending_san_ = "" |
| bool | pending_is_ca_ = false |
| bool | pending_valid_ = false |
| std::atomic< bool > | cert_error_ {false} |
| TaskQueueProducer< SKWSConnectionState > | connection_state_ |
| SKWSConnectionState | task_connection_state_ |
| std::atomic< esp_websocket_client_handle_t > | client_ {nullptr} |
| std::atomic< uint32_t > | client_generation_ {0} |
| std::atomic< bool > | teardown_in_progress_ {false} |
| std::atomic< bool > | auth_job_running_ {false} |
| std::atomic< esp_websocket_client_handle_t > | pending_teardown_ {nullptr} |
| std::shared_ptr< SKDeltaQueue > | sk_delta_queue_ |
| TaskQueueProducer< int > | delta_tx_tick_producer_ {0, event_loop(), 990} |
| Emits the number of deltas sent since last report. | |
| Integrator< int, int > | delta_tx_count_producer_ {1, 0, ""} |
| Integrator< int, int > | delta_rx_count_producer_ {1, 0, ""} |
| uint32_t | last_oversize_log_ms_ = 0 |
| millis() timestamp of the last oversize-delta-drop warning, used to rate-limit it when a device keeps producing a delta larger than the buffer. 0 = never logged, so the next drop logs immediately. | |
| StaticSemaphore_t | received_updates_semaphore_buffer_ |
| SemaphoreHandle_t | received_updates_semaphore_ |
| std::list< ReceivedUpdate > | received_updates_ {} |
Protected Attributes inherited from sensesp::Saveable | |
| const String | config_path_ |
Protected Attributes inherited from sensesp::ValueProducer< SKWSConnectionState > | |
| SKWSConnectionState | output_ |
The websocket connection to the Signal K server.
Definition at line 80 of file signalk_ws_client.h.
| sensesp::SKWSClient::SKWSClient | ( | const String & | config_path, |
| std::shared_ptr< SKDeltaQueue > | sk_delta_queue, | ||
| const String & | server_address, | ||
| uint16_t | server_port, | ||
| bool | use_mdns = true |
||
| ) |
|
inline |
|
inline |
Generation tag of the currently-valid client. The event handler compares the generation it was registered with against this to drop callbacks from a client that has been handed off for destruction.
Definition at line 316 of file signalk_ws_client.h.
|
inline |
Persist a stashed anchor after a successful (authenticated) connection. Called from on_connected().
Definition at line 290 of file signalk_ws_client.h.
| void sensesp::SKWSClient::connect | ( | ) |
Definition at line 889 of file signalk_ws_client.cpp.
|
staticprotected |
Definition at line 949 of file signalk_ws_client.cpp.
|
protected |
Definition at line 1378 of file signalk_ws_client.cpp.
|
protected |
Hand client_ to a detached one-shot task that stops+destroys it, so the blocking teardown never runs on the caller's context. Nulls client_ and bumps client_generation_ / sets teardown_in_progress_ immediately; no-op if client_ is null. If the reaper task can't be spawned (OOM), the handle is stashed in pending_teardown_ and the spawn is retried on the next event-loop tick – never reaped synchronously, which would block the loop.
Definition at line 1501 of file signalk_ws_client.cpp.
|
protected |
Definition at line 844 of file signalk_ws_client.cpp.
|
protected |
Push a received delta entry onto the queue, enforcing a per-kind budget so a metadata burst (one meta-delta per subscribed path at subscribe time when sendMeta=all is enabled) cannot evict pending value deltas, and vice versa. Caller must hold received_updates_semaphore_.
Push a received delta onto the queue with a per-kind budget.
Caller must hold received_updates_semaphore_. Meta and value entries are budgeted independently so a meta burst (~one entry per subscribed path at subscribe time) cannot evict pending value deltas, and vice versa.
| update |
Definition at line 629 of file signalk_ws_client.cpp.
|
inline |
Flag a certificate rejection from the verify callback so the next disconnect surfaces as kSKWSCertificateError rather than a plain disconnect.
Definition at line 311 of file signalk_ws_client.h.
|
finaloverridevirtual |
Deserializes the current object data from a JsonObject.
Reimplemented from sensesp::Serializable.
Definition at line 1604 of file signalk_ws_client.cpp.
|
inline |
Current Signal K access token, or an empty string if none.
Returned as a bare JWT without the "Bearer " prefix. Intended for subsystems that need to piggy-back on the same SK credentials as the main delta websocket — for example, a BLE gateway that also needs to authenticate against signalk-server's provider API but does not have its own access-request flow.
Returns "" when SKWSClient has not yet obtained a token (either because the server does not require auth, or because the access-request flow is still in progress). Callers that need auth must handle the empty-string case, typically by deferring their own connect attempts until the main SK websocket is connected (which is a precondition for a valid token anyway).
Definition at line 170 of file signalk_ws_client.h.
|
inlineprotected |
| String sensesp::SKWSClient::get_connection_status | ( | ) |
Get a String representation of the current connection state.
Definition at line 1662 of file signalk_ws_client.cpp.
|
inline |
Get the delta rx count producer object.
Definition at line 110 of file signalk_ws_client.h.
|
inline |
Return a delta update ValueProducer that produces the number of sent deltas.
Definition at line 101 of file signalk_ws_client.h.
|
protected |
|
inline |
Definition at line 91 of file signalk_ws_client.h.
|
inline |
Definition at line 92 of file signalk_ws_client.h.
|
inline |
Definition at line 226 of file signalk_ws_client.h.
|
inline |
Definition at line 230 of file signalk_ws_client.h.
|
inline |
Identity (CN) of whatever is pinned, and whether it is a CA.
Definition at line 233 of file signalk_ws_client.h.
|
inline |
TOFU'd leaf identity (normalized DNS SAN set) bound in CA-anchor mode. A reconnecting leaf must chain to the pinned CA AND present this same identity, so a different leaf from the same CA is rejected. Empty in leaf-fingerprint mode (the fingerprint already binds identity).
Definition at line 240 of file signalk_ws_client.h.
|
inline |
True if a candidate CA has already been stashed this handshake.
Definition at line 287 of file signalk_ws_client.h.
|
inline |
True if any trust anchor (pinned CA or leaf fingerprint) is stored.
Definition at line 220 of file signalk_ws_client.h.
|
inline |
True if a pinned CA certificate is stored (CA-anchor mode).
Definition at line 225 of file signalk_ws_client.h.
|
inline |
True if a pinned leaf fingerprint is stored (leaf-fingerprint mode).
Definition at line 229 of file signalk_ws_client.h.
|
inline |
| bool sensesp::SKWSClient::is_connected | ( | ) |
|
inline |
Whether the WS subscribes with sendMeta=all.
When true, the signalk-server pushes metadata deltas (units, zones, displayName, displayUnits, etc.) over the same WebSocket connection as value deltas, so consumers don't have to make separate REST /meta requests per path.
Defaults to true. When enabled, meta-deltas can be consumed via SKMetadataListener. Disable only if you have a constrained client that doesn't want meta-deltas at all (they are otherwise ignored by SKValueListener since meta updates carry no values array).
Definition at line 196 of file signalk_ws_client.h.
|
inline |
Check if SSL/TLS is enabled.
Definition at line 152 of file signalk_ws_client.h.
|
inline |
Check if TOFU certificate verification is enabled.
Definition at line 205 of file signalk_ws_client.h.
|
inline |
Definition at line 234 of file signalk_ws_client.h.
| void sensesp::SKWSClient::loop | ( | ) |
Definition at line 1024 of file signalk_ws_client.cpp.
| void sensesp::SKWSClient::on_connected | ( | ) |
Called when the websocket connection is established.
Called in the websocket task context.
Definition at line 452 of file signalk_ws_client.cpp.
| void sensesp::SKWSClient::on_disconnected | ( | ) |
Called when the websocket connection is disconnected.
This method is called in the websocket task context.
Definition at line 414 of file signalk_ws_client.cpp.
| void sensesp::SKWSClient::on_error | ( | int | handshake_status | ) |
| void sensesp::SKWSClient::on_receive_delta | ( | uint8_t * | payload, |
| size_t | length | ||
| ) |
Called when the websocket receives a delta.
Called in the websocket task context.
| payload |
Definition at line 520 of file signalk_ws_client.cpp.
| void sensesp::SKWSClient::on_receive_put | ( | JsonDocument & | message | ) |
Called when a PUT event is received.
Called in the websocket task context.
| message |
Definition at line 730 of file signalk_ws_client.cpp.
| void sensesp::SKWSClient::on_receive_updates | ( | JsonDocument & | message | ) |
Called when a delta update is received.
Called in the websocket task context.
| message |
Definition at line 565 of file signalk_ws_client.cpp.
|
protected |
Definition at line 1248 of file signalk_ws_client.cpp.
|
protected |
Loop through the received updates and process them.
This method is called in the main task context.
Definition at line 667 of file signalk_ws_client.cpp.
|
protected |
Spawn the detached reaper for old; on spawn failure (OOM) stash it in pending_teardown_ for a later retry instead of blocking the loop with a synchronous reap. No-op if old is null. Call on the event-loop context.
Definition at line 1480 of file signalk_ws_client.cpp.
|
inlineprotected |
|
inlineprotected |
|
inline |
Reset the stored trust anchor (CA or leaf fingerprint).
Call this when the server's CA has changed legitimately so the device re-captures it on the next connection. Re-capture is trust-on-first-use; trigger it on a trusted network.
Definition at line 249 of file signalk_ws_client.h.
| void sensesp::SKWSClient::restart | ( | ) |
Drop the current connection (detached, non-blocking teardown) and let the reconnect path rebuild it.
Definition at line 1515 of file signalk_ws_client.cpp.
|
protected |
The (blocking) connect attempt — mDNS resolve, SSL detect, and the access-request / poll / connect_ws leg. Run on a one-shot worker task so none of it blocks the SK/event-loop context. connect() is the dispatcher.
Definition at line 956 of file signalk_ws_client.cpp.
|
inlineprotected |
|
protected |
Definition at line 1115 of file signalk_ws_client.cpp.
| void sensesp::SKWSClient::send_delta | ( | ) |
Definition at line 1522 of file signalk_ws_client.cpp.
| void sensesp::SKWSClient::sendTXT | ( | String & | payload | ) |
Send some processed data to the websocket.
Sends the specified payload to the server over the websocket this client is connected to. If no connection currently exist, the call is safely ignored.
Called in the websocket task context.
| payload |
Definition at line 790 of file signalk_ws_client.cpp.
|
inlineprotected |
Definition at line 501 of file signalk_ws_client.h.
|
inline |
Record the leaf's identity (SAN set) for the pending CA anchor, captured at depth 0 and committed alongside the CA on success.
Definition at line 277 of file signalk_ws_client.h.
|
inline |
|
inline |
Enable or disable SSL/TLS manually.
Note: SSL is normally auto-detected. Use this only if you need to override the auto-detection behavior.
Definition at line 178 of file signalk_ws_client.h.
|
inline |
Enable or disable TOFU certificate verification.
When enabled, the issuing CA (or, for servers that present no CA, the leaf certificate) is captured on first connection and verified on subsequent connections.
Definition at line 214 of file signalk_ws_client.h.
|
inline |
Stash a candidate anchor seen during a handshake. Persisted only after the connection succeeds (commit_pending_tofu), so an unauthenticated MITM handshake cannot plant a trust anchor.
Definition at line 261 of file signalk_ws_client.h.
|
inline |
Definition at line 268 of file signalk_ws_client.h.
|
protected |
Subscribes the SK delta paths to the websocket.
Called in the websocket task context.
Definition at line 470 of file signalk_ws_client.cpp.
|
inlineprotected |
|
staticprotected |
Body of the detached teardown task (stop+destroy+self-delete).
Definition at line 1468 of file signalk_ws_client.cpp.
|
protected |
Definition at line 1029 of file signalk_ws_client.cpp.
|
finaloverridevirtual |
Serializes the current object data into a JsonObject.
Reimplemented from sensesp::Serializable.
Definition at line 1582 of file signalk_ws_client.cpp.
|
protected |
Definition at line 405 of file signalk_ws_client.h.
|
protected |
Definition at line 329 of file signalk_ws_client.h.
|
protected |
Definition at line 373 of file signalk_ws_client.h.
|
protected |
Definition at line 393 of file signalk_ws_client.h.
|
protected |
Definition at line 398 of file signalk_ws_client.h.
|
protected |
Definition at line 327 of file signalk_ws_client.h.
|
protected |
Definition at line 323 of file signalk_ws_client.h.
|
protected |
Definition at line 324 of file signalk_ws_client.h.
|
protected |
Definition at line 332 of file signalk_ws_client.h.
|
protected |
Definition at line 375 of file signalk_ws_client.h.
|
protected |
Definition at line 415 of file signalk_ws_client.h.
|
protected |
Definition at line 414 of file signalk_ws_client.h.
|
protected |
Emits the number of deltas sent since last report.
Definition at line 413 of file signalk_ws_client.h.
|
protected |
millis() timestamp of the last oversize-delta-drop warning, used to rate-limit it when a device keeps producing a delta larger than the buffer. 0 = never logged, so the next drop logs immediately.
Definition at line 420 of file signalk_ws_client.h.
|
protected |
Definition at line 331 of file signalk_ws_client.h.
|
protected |
Definition at line 363 of file signalk_ws_client.h.
|
protected |
Definition at line 365 of file signalk_ws_client.h.
|
protected |
Definition at line 364 of file signalk_ws_client.h.
|
protected |
Definition at line 367 of file signalk_ws_client.h.
|
protected |
Definition at line 366 of file signalk_ws_client.h.
|
protected |
Definition at line 410 of file signalk_ws_client.h.
|
protected |
Definition at line 368 of file signalk_ws_client.h.
|
protected |
Definition at line 328 of file signalk_ws_client.h.
|
protected |
Definition at line 436 of file signalk_ws_client.h.
|
protected |
Definition at line 434 of file signalk_ws_client.h.
|
protected |
Definition at line 433 of file signalk_ws_client.h.
|
protected |
Definition at line 340 of file signalk_ws_client.h.
|
protected |
Definition at line 320 of file signalk_ws_client.h.
|
protected |
Definition at line 321 of file signalk_ws_client.h.
|
protected |
Definition at line 411 of file signalk_ws_client.h.
|
protected |
Definition at line 335 of file signalk_ws_client.h.
|
protected |
task_connection_state is used to track the internal task state which might be out of sync with the published connection state.
Definition at line 380 of file signalk_ws_client.h.
|
protected |
Definition at line 401 of file signalk_ws_client.h.
|
protected |
Definition at line 347 of file signalk_ws_client.h.
|
protected |
Definition at line 336 of file signalk_ws_client.h.
|
protected |
Definition at line 346 of file signalk_ws_client.h.
|
protected |
Definition at line 357 of file signalk_ws_client.h.
|
protected |
Definition at line 358 of file signalk_ws_client.h.
|
protected |
Definition at line 353 of file signalk_ws_client.h.
|
protected |
Definition at line 325 of file signalk_ws_client.h.