Skip to content

libsig

A lightweight IoT platform.

libsig is the code. The product it is meant to become is a lightweight IoT platform. The aim is that you build libsig onto your devices and run cloud instances that process the signal data. The unit a system is assembled from is the capsule, a piece of code that is meant to run on a device or in the cloud. Today capsules run in the host, a program that runs on POSIX systems (Linux and macOS). See the Roadmap for what is planned and not built.

Capsules

Units of logic. A capsule has named input and output terminals and a table of the properties it accepts. Built-in capsules include a counter, a simulator, a logger, a filter, a switch and a state-change detector.

Services

Wire capsules together. A service connects output terminals to input terminals and runs its capsules on one worker thread.

Host + API + UI

Manage it live. The host, sighost, loads a JSON project and runs it. A management API (C and REST), a WebSocket signal feed and a web UI let you inspect, control and edit a running project.

flowchart LR
    Sim[Sim<br/>simulator] -- signal --> Scale[Scale<br/>scale]
    Scale -- signal --> Log[Log<br/>logger]
    subgraph svc["service first (one worker thread)"]
        Sim
        Scale
        Log
    end
    UI[Web UI] -. REST .-> API[management API]
    API -. start / stop / edit .-> svc

A project is a directory of JSON files. Each capsule configuration names a capsule and its properties; each service lists configurations as instances and connects their terminals. The management API and the web UI edit those same files.

This is the handler of the scale capsule from the tutorial. It multiplies each incoming integer by a configured factor and sends the result on.

static sig_status_t scale_signal(sig_capsule_instance *instance, const sig_value *signal,
const char *terminal_name) {
sig_int_t n;
sig_int_t product;
sig_value scaled;
(void) terminal_name;
if (sig_value_get_int(signal, &n) != SIG_OK) {
sig_log_warn("scale %s: dropping a signal that is not an int", instance->name);
return SIG_OK;
}
if (__builtin_mul_overflow(n, sig_capsule_instance_int(instance, SCALE_FACTOR), &product)) {
sig_log_warn("scale %s: dropping a signal whose scaled value overflows", instance->name);
return SIG_OK;
}
scaled = sig_value_int(product);
return sig_capsule_instance_notify(instance, SIG_TERMINAL_DEFAULT, &scaled);
}

Make your first capsule builds it, wires it into a service and runs it.

These items are planned. None of them is built. Nothing above this heading depends on them.

  • Microcontroller targets (planned): running capsules on a microcontroller, for example an Arduino reading a GPIO pin. libsig supports POSIX only today.
  • Secure channels between deployments (planned): carrying signals between separate libsig deployments over TCP, MQTT or ZMQ.
  • Cloud instances subscribing to device data (planned): a cloud deployment that receives and processes the signals a device produces.
Docs Architecture API reference