Skip to content
SalzDevsPublic

About

Real-time sensor dashboard in C99 — config-driven metrics, Raylib UI, ring-buffer history. MIT

Topics

Resources

Contributing

Stars

4 stars

Watchers

0 watching

Forks

Repository files navigation

Aether

logo

Aether CI

Aether is a small C99 application that displays sensor readings from configured HTTP data sources in a real-time Raylib dashboard.

Aether dashboard

Features

  • Load any number of sensors from a YAML config, each with an arbitrary list of named metrics carrying units (temperature (C), pressure (hPa), ...)
  • Adaptive card grid: each metric renders as a chip with its value, sparkline, and up/down change indicator
  • Card detail view with large trend lines and min/avg/max stats per metric
  • Tabbed navigation: a tab holds as many cards as fit the window; overflow goes to numbered tabs (1 2 ... N), clickable and bound to Alt/Cmd + 1..9
  • Settings modal to toggle trend lines, value animation, and change indicators at runtime
  • HTTP data sources polled on background threads (CivetWeb + OpenSSL), so slow or unreachable endpoints never freeze the dashboard
  • Liveness model per metric: live, stale, offline, or error with reason
  • Fixed-slot task scheduler decoupled from data handling
  • Bounded per-sensor reading history (ring buffers)
  • Unit tests for configuration, history, scheduler, sensor, source, HTTP mapping, and dashboard layout modules

Demo

Aether demo

Requirements

  • C compiler with C99 support (GCC or Clang)
  • make
  • pkg-config
  • Raylib
  • libyaml
  • OpenSSL 3 (OpenSSL 1.1 also works)

CivetWeb (HTTP client) and cJSON (JSON parsing) are vendored under third_party/ — both MIT licensed, no installation needed.

macOS

brew install raylib libyaml openssl pkg-config

Linux

sudo apt-get install gcc make pkg-config cmake \
  libx11-dev libxrandr-dev libxi-dev libxcursor-dev libxinerama-dev \
  libgl1-mesa-dev libglu1-mesa-dev libasound2-dev \
  libyaml-dev libssl-dev

(The X11/OpenGL headers are needed because raylib links them even for a headless compile.)

Build and run

Build the application:

make

Run it:

./main

Clean generated files:

make clean

Run tests

Build and run all unit tests:

make test

The test suite covers:

  • sensor metrics, source binding, reading application, and liveness;
  • HTTP JSON path mapping, backoff, timeouts, and error handling (against loopback mock servers);
  • reading history ordering, oldest-entry eviction, and metric statistics;
  • task scheduling;
  • YAML configuration loading, including malformed input, unknown keys, missing ids, growing registries, and source validation;
  • dashboard layout math: tab capacity, pagination limits, and range mapping.

Configuration

Sensor data is loaded from:

config/sensors.yaml

Example:

sensors:
  - id: 1
    name: temperature_sensor
    metrics:
      - name: temperature
        unit: C
        value: 22.5
      - name: humidity
        unit: "%"
        value: 45

Each sensor requires:

Field Description
id Unique numeric sensor identifier
name Readable sensor name
metrics List of metrics, each with name, unit and value

Note: a % unit must be quoted ("%") because YAML reserves the percent sign.

Data sources

Live values come from HTTP endpoints declared in:

config/sources.yaml

Example:

sources:
  - id: weather_api
    name: Weather API
    url: https://example.com/metrics.json
    poll_interval_s: 10
    timeout_s: 5
    headers:
      Authorization: Bearer TOKEN

Metrics opt into live polling from config/sensors.yaml:

metrics:
  - name: temperature
    unit: C
    value: 22.5          # initial display value until live data arrives
    source: weather_api  # id from sources.yaml
    path: current.temperature_2m  # dot-separated JSON path

Each source is polled on a background thread, so slow or unreachable endpoints never freeze the dashboard. Metrics without a source keep their configured value statically.

Controls

Input Action
Click the cogwheel (top right) Open/close the settings modal
Click a card Open that sensor's detail view
Click a numbered tab (bottom) Jump to that tab
Alt/Cmd + 1..9 Jump directly to tab N
← / → Previous / next tab
Esc Close the detail view or settings modal

Project structure

.
├── assets/fonts/    Bundled font (JetBrains Mono, SIL OFL)
├── config/          Sensor and source configuration YAML
├── docs/            Screenshots and demo media
├── third_party/    Vendored CivetWeb (HTTP) and cJSON (JSON), both MIT
├── config/          YAML parsing: sensors, sources, settings (libyaml)
├── sensor/          Sensor data model and source-bound readings
├── source/          Data-source types, status model, validation
├── history/         Bounded per-sensor reading history (ring buffer)
├── scheduler/       Periodic task scheduling
├── http/            HTTP polling workers (CivetWeb + cJSON + pthreads)
├── ui/              Dashboard rendering, layout math, theme (Raylib)
├── tests/           Unit tests (one executable per module)
├── main.c           Application entry point
└── Makefile         Build and test commands

Architecture

sensors.yaml + sources.yaml
      │
      ▼
configuration parser (binds metrics to sources)
      │
      ▼
sensor registry ◄── HTTP poll workers (one thread per source)
      │                    │
      ▼                    ▼
Raylib dashboard     per-sensor reading history (ring buffers)

License

This project is licensed under the MIT License.

About

Real-time sensor dashboard in C99 — config-driven metrics, Raylib UI, ring-buffer history. MIT

Topics

Resources

Contributing

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages