Appearance
Overview
Coldwave eOS exposes the device data model as a flake::Service. Telemetry values are represented as properties on that service. Your firmware updates those properties locally, and Coldwave synchronizes them with the Coldwave Backend when you call sync() and the backend connection is attached.
This document covers:
- Initializing Coldwave and obtaining a
flake::Serviceinstance - Understanding
cwClientvs.cwRouternode types - Attaching to the Coldwave Backend
- Updating telemetry properties and syncing them
- Handling writable properties from the backend
- The relevant parts of the Coldwave and
flake::ServiceAPI
Architecture
At a high level:
- Coldwave core (C API): handles device identity, connectivity, budget management and the backend connection (
coldwave_init,coldwave_backend_attach,coldwave_get_remaining_budget, …). - flake::Service (C++ API): represents your device/service object and its properties; you use it to read/write properties, register callbacks and perform
sync(). - Device firmware: reads sensors, maintains internal state and uses
service->set<PropTag>()to expose telemetry properties.
Node types: cwClient vs. cwRouter
Coldwave distinguishes between two node roles via coldwave_init_t::node_type:
cwClient– endpoint device- The Coldwave Backend acts as the router.
- The device maintains a point-to-point (PTP) connection to the backend.
- No local Coldwave clients connect to this device.
- Typical use: sensor/actuator node that only talks to the Coldwave Backend.
cwRouter– router / gateway device- The embedded device itself acts as a Coldwave router.
- It can accept multiple local Coldwave clients (other devices using
cwClient) over TCP. - It can also connect to the Coldwave Backend, routing traffic between local clients and the backend.
- Typical use: building gateway, line controller, or aggregation node.
Example: Router node (cwRouter)
cpp
// Example: router/gateway device that accepts local Coldwave clients
coldwave_init_t cw_init = COLDWAVE_INIT_DEFAULT;
cw_init.node_type = cwRouter;
cw_init.app_semver = APP_VERSION_STR;
cw_init.device_id = DEVICE_ID; // const char*
cw_init.product_id = "G2SF";
cw_init.hw_id = "WGM160P022";
cw_init.opt.router.no_local_tls = 1;
cw_init.opt.router.local_tcp_port = 9986;
cw_init.opt.router.local_network_interface = nullptr;
cw_init.opt.router.auth_callback = nullptr;
cw_init.opt.router.auto_update_disabled = 1;
cw_init.opt.router.max_clients = 5;In this configuration:
- The device listens on TCP port
9986for local Coldwave clients. - TLS for local connections is disabled (
no_local_tls = 1). - Up to 5 local clients can connect.
- The router can still attach to the Coldwave Backend to forward traffic.
Example: Client node (cwClient)
cpp
// Example: client device that only connects to the Coldwave Backend
coldwave_init_t cw_init = COLDWAVE_INIT_DEFAULT;
cw_init.node_type = cwClient;
cw_init.app_semver = APP_VERSION_STR;
cw_init.device_id = DEVICE_ID; // const char*, e.g. IMEI
cw_init.product_id = "YD42";
cw_init.hw_id = "EFR32MG26";
cw_init.backend.fqdn = COLDWAVE_BACKEND_URL;
cw_init.backend.ca_cert = backend_ca; // DER bytes, or nullptr for unencrypted PTP
cw_init.backend.ca_cert_len = backend_ca_len;
cw_init.net_device_handle = modem_fd; // open("modem0", ...) / open("wlan0") / open("eth0")
cw_init.net_device_type = cwNetLte; // or cwNetWiFi / cwNetEthernet
// client-specific options:
cw_init.opt.client.monthly_data_limit_bytes = 6U * 1024U * 1024U; // track ~6 MB/monthHere:
- The device acts purely as a client.
- The Coldwave Backend is the router.
- The connection is point-to-point; there are no local Coldwave clients on this device.
For simple telemetry devices, cwClient is usually what you want. For gateways that aggregate multiple local nodes, use cwRouter.
Typical data flow (for both node types):
- Firmware updates local properties via
service->set<PropTag>(value). - Firmware periodically calls
service->sync(timeout_ms)to exchange updates with the backend. - Incoming writes from the backend (or from local clients via a router) trigger registered callbacks (
service->on<PropTag>(...)). - If a monthly data limit is configured, Coldwave tracks the consumed volume for reporting (see
coldwave_get_remaining_budget()); rate limits are enforced by the backend, not on the device.