Skip to content

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::Service instance
  • Understanding cwClient vs. cwRouter node 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::Service API

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:

  • cwClientendpoint 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.
  • cwRouterrouter / 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
#define COLDWAVE_INIT                               \
{                                                   \
 /* .node_type */ cwRouter,                         \
 /* .app_semver */ APP_VERSION_STR,                 \
 /* .device_id */ 0,                                \ 
 /* .product_id */ "G2SF",                          \
 /* .hw_id */ "WGM160P022",                         \
 /* .opts */ {                                      \
   /*   .no_local_tls */ 1,                         \ 
   /*   .local_tcp_port */ 9986,                    \ 
   /*   .local_network_interface */ nullptr,        \ 
   /*   .auth_callback */ nullptr,                  \ 
   /*   .auto_update_disabled */ true,              \ 
   /*   .max_clients */ 5                           \ 
   }                                                \ 
 }

In this configuration:

  • The device listens on TCP port 9986 for 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
#define COLDWAVE_INIT                                           \        
{                                                               \
/* .node_type */ cwClient,                                      \
/* .app_semver */ APP_VERSION_STR,                              \
/* .device_id */ 0,                                             \
/* .product_id */ "YD42",                                       \
/* .hw_id */  "EFR32MG26",                                      \
{ /* client options are configured via cw_init.opt.client */ }  \
}

Here:

  • 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):

  1. Firmware updates local properties via service->set<PropTag>(value).
  2. Firmware periodically calls service->sync(timeout_ms) to exchange updates with the backend.
  3. Incoming writes from the backend (or from local clients via a router) trigger registered callbacks (service->on<PropTag>(...)).
  4. Coldwave enforces the configured monthly data budget and adjusts sync behavior accordingly.