Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Metrum: A Telemetry System for Reticulum Networks

Metrum is an open-source telemetry system designed for Reticulum networks. It provides a standardized way to collect, process, and transmit sensor data, enabling efficient and reliable communication between devices and nodes.

Git Repository

How Metrum Works

Metrum is a framework designed for sending telemetry data (sensor readings) over Reticulum networks. It implements a publisher-subscriber pattern that allows sensor data to be efficiently transmitted from sensor nodes (publishers) to data collection nodes (subscribers).

Key components of the system include:

  1. Publisher: Collects data from sensors and distributes it to interested subscribers
  2. Subscriber: Discovers publishers and subscribes to their sensor data
  3. Reticulum Network: The underlying transport mechanism that enables communication
  4. SenML Format: A standardized format for representing sensor measurements
  5. CBOR Encoding: Efficient binary serialization for compact data transmission

The Publisher Side

The publisher in Metrum operates as follows:

  1. Initialization:

    • The publisher is created with a specific sensor interface
    • It establishes its identity on the Reticulum network
    • It announces its presence as a telemetry publisher
  2. Sensor Data Collection:

    • Periodically reads data from connected sensors
    • Formats this data according to the SenML specification
    • Encodes the data using CBOR for efficient transmission
  3. Data Distribution:

    • Manages a list of active subscribers
    • Distributes sensor readings to all subscribed nodes
    • Periodically re-announces its presence to allow new subscribers to discover it

The sensors are abstracted through a SensorInterface class, which handles the specifics of reading from physical or virtual sensors.

The Subscriber Side

The subscriber operates as follows:

  1. Discovery:

    • Monitors the Reticulum network for publisher announcements
    • Records information about discovered publishers
  2. Connection:

    • Establishes links to publishers of interest
    • Sends subscription requests to activate the data flow
  3. Data Processing:

    • Receives CBOR-encoded SenML data from publishers
    • Decodes the data and processes it through a callback function
    • In the provided example, stores the data in InfluxDB for later analysis
    • Implements a retry queue for handling temporary database unavailability
  4. Reconnection:

    • Monitors the status of publisher connections
    • Automatically attempts to reconnect to disconnected publishers

Communication Flow

The communication between publisher and subscriber follows these steps:

  1. The publisher announces its presence on the Reticulum network
  2. The subscriber discovers the publisher through these announcements
  3. The subscriber establishes a connection to the publisher
  4. The subscriber sends a subscription request
  5. The publisher adds the subscriber to its active list
  6. The publisher periodically collects and transmits sensor data
  7. The subscriber receives, processes, and stores the data

This approach allows for a flexible and resilient system where publishers and subscribers can dynamically discover each other and establish communication without centralized coordination.

Data Format

The data is structured using SenML (Sensor Measurement Lists), which provides a standardized way to represent sensor readings. A SenML record typically includes:

  • Name: Identifies the sensor or measurement (e.g., "temperature")
  • Value: The actual reading value
  • Unit: The unit of measurement (e.g., "Celsius")
  • Timestamp: When the reading was taken

This structured format ensures that all sensor data is properly labeled and can be correctly interpreted by the receiving systems.

Advantages of this Architecture

  1. Decentralization: No single point of failure in the system
  2. Flexibility: Easy to add new sensors or subscribers
  3. Efficiency: CBOR encoding minimizes bandwidth usage
  4. Standardization: Using SenML ensures interoperability
  5. Resilience: Automatic reconnection and data queuing handle network instability

This architecture makes Metrum well-suited for sensor networks in challenging environments or where network connections may be intermittent.

Diátaxis Structure

Our documentation is structured around the four needs identified by Diátaxis:

  • Tutorials: Step-by-step guides for getting started with Metrum.
  • How-to Guides: Practical instructions for achieving specific goals with Metrum.
  • Technical Reference: Detailed descriptions of Metrum's components, APIs, and interfaces.
  • Explanation: In-depth discussions of Metrum's architecture, design decisions, and underlying principles.

This structure allows us to provide a comprehensive and user-friendly documentation set that addresses the needs of different users.

Contributors

Metrum is a framework for decentralized sensor data communication that works over Reticulum networks. It follows a publisher-subscriber pattern and uses standardized formats like SenML (Sensor Measurement Lists) and CBOR (Concise Binary Object Representation) for efficient data transmission.

Communication Philosophy

Metrum's communication philosophy is based on the following principles:

  1. Heterogeneity: Metrum is designed to work in diverse and heterogeneous networks, where devices and sensors may have different capabilities, protocols, and data formats.
  2. Scalability: Metrum is built to scale, handling large amounts of sensor data from multiple devices and sources.
  3. Flexibility: Metrum provides a flexible framework for integrating with different sensors, devices, and systems.
  4. Efficiency: Metrum optimizes data transmission and reception, minimizing overhead and ensuring reliable communication.

Communication Architecture

The system consists of the following components:

flowchart TB
    subgraph "Publisher Node"
        Sensor["Sensor Interface"] --> MetrumPublisher["MetrumSensorPublisher"]
        MetrumPublisher --> CBOR1["CBOR Encoding"]
        CBOR1 --> SenML1["SenML Formatting"]
    end
    
    subgraph "Reticulum Network"
        Network["Decentralized Network"]
    end
    
    subgraph "Subscriber Node"
        MetrumSubscriber["MetrumSensorSubscriber"] --> CBOR2["CBOR Decoding"]
        CBOR2 --> SenML2["SenML Processing"]
        SenML2 --> InfluxDB["InfluxDB Storage"]
    end
    
    MetrumPublisher -->|"Announce/Publish"| Network
    Network -->|"Connect/Subscribe"| MetrumSubscriber
    
    classDef sensor fill:#f9f,stroke:#333,stroke-width:2px
    classDef publisher fill:#bbf,stroke:#333,stroke-width:2px
    classDef network fill:#dfd,stroke:#333,stroke-width:2px
    classDef subscriber fill:#fbb,stroke:#333,stroke-width:2px
    classDef storage fill:#ffd,stroke:#333,stroke-width:2px
    
    class Sensor sensor
    class MetrumPublisher,CBOR1,SenML1 publisher
    class Network network
    class MetrumSubscriber,CBOR2,SenML2 subscriber
    class InfluxDB storage
  • Publishers: Devices or nodes that collect and transmit sensor data.
  • Subscribers: Devices or nodes that receive and process sensor data.
  • Reticulum Network: A decentralized network that enables communication between devices and nodes.
  • InfluxDB: Time series database (TSDV) used for storing IoT Datapoints.

Specifications

Metrum uses the following specifications for communication:

  1. CBOR Encoding: Metrum uses CBOR (Concise Binary Object Representation) encoding for transmitting sensor data.
  2. Reticulum Protocol: Metrum communicates over Reticulum networks using the Reticulum protocol.
  3. Sensor Data Format: Metrum uses a standardized sensor data format, which includes:
  • Metric: A string representing the sensor measurement (e.g., temperature, humidity).
  • Value: The sensor reading value.
  • Unit: The unit of measurement for the sensor reading (e.g., Celsius, Fahrenheit).
  • Timestamp: The timestamp for the sensor reading.

Defining Sensors

To define a sensor in Metrum, you need to create a class that inherits from the SensorInterface abstract base class. The class should implement the following methods:

  1. read_sensors: This method collects sensor data and returns it as a dictionary.

Here is an example of a sensor definition:

from metrum import SensorInterface

class ExampleSensor(SensorInterface):
    """Mock sensor for testing serialization"""

    def read_sensors(self):
        """Return mock sensor readings with proper SenML formatting"""
        readings = {
            "temperature": {
                "value": 25.5,
                "unit": SenmlUnits.SENML_UNIT_DEGREES_CELSIUS,
                "name": SenmlNames.KPN_SENML_TEMPERATURE,
            },
            "pressure": {
                "value": 101325,
                "unit": SenmlUnits.SENML_UNIT_PASCAL,
                "name": SenmlNames.KPN_SENML_PRESSURE,
            },
            "humidity": {
                "value": 65.0,
                "unit": SenmlUnits.SENML_UNIT_RELATIVE_HUMIDITY,
                "name": SenmlNames.KPN_SENML_HUMIDITY,
            },
        }
        return readings

The SensorInterface takes serializes the sensor readings as SenML using CBOR encoding.

Sensor Data Format

The sensor data format used in Metrum is based on the SenML (Sensor Measurement Lists) specification. SenML is a lightweight, binary format for representing sensor data.

A SenML record consists of the following fields:

  • Name: A string representing the sensor measurement (e.g., temperature, humidity).
  • Value: The sensor reading value.
  • Unit: The unit of measurement for the sensor reading (e.g., Celsius, Fahrenheit).
  • Timestamp: The timestamp for the sensor reading.

Communication Flow

The communication flow in Metrum is as follows:

  1. Publisher Announcement: The publisher announces its presence and available metrics to the Reticulum network.
  2. Subscriber Connection: The subscriber establishes a connection to the publisher and requests subscription to specific metrics.
  3. Telemetry Data Transmission: The publisher transmits telemetry data to the subscriber using CBOR encoding.
  4. Data Processing: The subscriber processes the received telemetry data and stores it in a database or performs other actions.
flowchart TB
    subgraph "Data Collection"
        S1["Temperature Sensor"] --> |"Reading"| SI["Sensor Interface"]
        S2["Pressure Sensor"] --> |"Reading"| SI
        S3["Humidity Sensor"] --> |"Reading"| SI
    end
    
    subgraph "Publisher Processing"
        SI --> |"read_sensors()"| SP["SenML Pack"]
        SP --> |"CBOR encoding"| CD["CBOR Data"]
    end
    
    subgraph "Transmission"
        CD --> |"Reticulum Transport"| RN["Reticulum Network"]
        RN --> |"Packet Delivery"| SD["Subscriber Decoder"]
    end
    
    subgraph "Subscriber Processing"
        SD --> |"CBOR decoding"| SP2["SenML Pack"]
        SP2 --> |"Data Processing"| DP["Data Points"]
        DP --> |"Write API"| IF["InfluxDB"]
        DP --> |"If InfluxDB unavailable"| RQ["Retry Queue"]
        RQ -.-> |"Retry later"| IF
    end
    
    classDef collection fill:#e1f5fe,stroke:#333,stroke-width:1px
    classDef publisher fill:#e8f5e9,stroke:#333,stroke-width:1px
    classDef network fill:#fff9c4,stroke:#333,stroke-width:1px
    classDef subscriber fill:#f9e1fd,stroke:#333,stroke-width:1px
    
    class S1,S2,S3,SI collection
    class SP,CD publisher
    class RN network
    class SD,SP2,DP,IF,RQ subscriber

Example Use Case

Here is an example of how to define a sensor and use it with Metrum:

# Define a sensor class like above
publisher = MetrumPublisher(sensor=ExampleSensor(), config_path="config.toml")

# Announce the publisher and publish telemetry data
publisher.announce()
publisher.publish_telemetry()

This example demonstrates how to define a sensor class, create a Metrum publisher instance, and publish telemetry data using the Reticulum protocol.

TODO Later

  • pluggable transport layer
  • use minimal amount of bandwith
  • try to use standards when possible

Design Decisions

Metrum's design is based on the following principles:

  • Scalability: Metrum is designed to handle large amounts of sensor data from multiple devices.
  • Flexibility: Metrum provides a flexible framework for integrating with different sensors, devices, and systems.

Communication Flow

The following workflow diagram illustrates the process of publishing and subscribing to telemetry data using Metrum:

sequenceDiagram
    participant S as Sensor
    participant P as Publisher
    participant R as Reticulum Network
    participant Sub as Subscriber
    participant DB as InfluxDB
    
    Note over P,R: Publisher Initialization
    P->>P: Initialize with sensor interface
    P->>R: Announce presence (with SenML capability)
    
    Note over R,Sub: Subscriber Discovery
    R->>Sub: Forward publisher announce
    Sub->>Sub: Record publisher details
    
    Note over Sub,P: Connection Establishment
    Sub->>R: Request path to publisher
    R->>Sub: Path established
    Sub->>P: Establish link
    P->>Sub: Link acknowledged
    Sub->>P: Send subscription request
    P->>P: Activate subscriber
    
    loop At collection interval
        S->>P: Read sensor data
        P->>P: Format as SenML
        P->>P: Encode with CBOR
        P->>Sub: Send telemetry data
        Sub->>Sub: Decode CBOR
        Sub->>DB: Store SenML data
        
        alt InfluxDB unavailable
            Sub->>Sub: Queue data for retry
        end
    end
    
    loop At announce interval
        P->>R: Re-announce presence
    end

Hardware Guide

Always make sure on AliExpress and similar sites, that you are buying the full chip, not just a module. Often the sellers list the cheapest module or case, as the list price.

Budget Starter Kit (5 Nodes) - ~€150 Total

DeviceHeltec LoRa 32 V3QuantityUnit PriceTotal
MCUESP32-S3FN85x€25€125
Purchase LinksAliExpress Search
Antennas868/915 MHz 2dBi5x€3€15
CasesOptional plastic5x€2€10

Pros: Cheap, WiFi+BLE, OLED display, good for learning
Cons: Power-hungry (~90-200mA), not suitable for long-term battery use
Best for: Indoor nodes, mains power, development, short-term mobile use

Low-Power Starter Kit (5 Nodes) - ~€300 Total

DeviceHeltec T114 Mesh Node V2QuantityUnit PriceTotal
MCUnRF52840 + SX12625x€50€250
Purchase LinksAliExpress Muzi Works | Rokland | Amazon
Solar Panels1W each5x€8€40
CasesWaterproof IP655x€2€10

Pros: Ultra-low power (11µA sleep), solar-ready, 1.14" TFT display, no soldering required, built-in BMS
Cons: More expensive, BLE only (no WiFi)
Best for: Long-term deployment, solar nodes, battery operation, remote locations

Why T114 over RAK4631? The Heltec T114 is plug-and-play with built-in battery management and display, while RAK4631 requires additional BMS components and soldering.

Protocol Architecture Comparison

This guide covers three distinct mesh networking approaches with fundamentally different transport mechanisms:

  • Meshtastic: Application-layer mesh protocol over LoRa PHY/MAC
  • Reticulum: SDLC-based (Synchronous Data Link Control) networking stack, transport-agnostic
  • OpenMANET: IP-based MANET (Mobile Ad-Hoc Network) over WiFi HaLow (802.11ah)

Critical Engineering Distinction: Reticulum operates at the data link layer without IP dependencies, while OpenMANET maintains full IP stack compatibility. This architectural difference impacts power consumption, protocol overhead, and network interoperability.

Hardware Platform Analysis

Microcontroller Architectures

ESP32 Family Characteristics
  • Architecture: Xtensa 32-bit LX6/LX7 dual-core
  • Power Profile: High consumption - 90-200mA active, ~900µA deep sleep
  • Radio Integration: WiFi + Bluetooth + LoRa (external)
  • Use Cases: Mains-powered base stations, vehicle installations, development
  • Cost: Low (€15-35 per node)
nRF52840 Characteristics
  • Architecture: 32-bit ARM Cortex-M4F with FPU, 64MHz
  • Power Profile: Ultra-low - 2-11µA sleep, ~125mA TX@20dBm
  • Radio Integration: BLE 5.0 + LoRa (external)
  • Use Cases: Battery/solar nodes, remote sensors, handheld devices
  • Cost: Medium (€40-70 per node)

LoRa Transceiver Performance Matrix

ParameterSX1276/1278SX1262/1268SX1280
Frequency Range137-1020 MHz150-960 MHz2.4 GHz
Max TX Power+20 dBm+22 dBm+12.5 dBm
RX Sensitivity-148 dBm-148 dBm-132 dBm
Sleep Current0.2 µA1.6 µA1.1 µA
RX Current10.8 mA4.2 mA6.8 mA
TX Current @20dBm87 mA38 mA25 mA
EfficiencyLegacyBestHigh speed

Recommendation: SX1262/1268 offers the best power efficiency and is used in modern devices like Heltec T114.

Complete Hardware Bill of Materials

Meshtastic Devices

Budget ESP32 Platforms
DeviceHeltec LoRa 32 V3
MCUESP32-S3FN8 (240MHz dual-core)
LoRaSX1262
Frequency433/868/915/923 MHz variants
TX Power22 dBm
Display0.96" OLED 128×64
WiFi/BTYes / BLE 5.0
GPSNo
BatteryJST SH1.25-2 connector, built-in BMS
CaseOptional plastic case available
Price€25-30
Power90-200mA active, ~900µA sleep
Best ForLearning, indoor nodes, short-term mobile
PurchaseAliExpress | Amazon
DeviceLILYGO T-Beam
MCUESP32 WROVER-B
LoRaSX1276/SX1278
Frequency433/868/915/923 MHz variants
TX Power20 dBm
DisplayOptional 0.96" OLED
WiFi/BTYes / Classic BT + BLE
GPSNEO-6M/NEO-8M
Battery18650 holder
CaseNo (requires DIY)
Price€35-45
Power150-300mA active (with GPS)
Best ForMobile tracking, vehicle installation
PurchaseAliExpress
Ultra-Low Power nRF52 Platforms
DeviceHeltec T114 Mesh Node V2
MCUnRF52840 (ARM Cortex-M4F, 64MHz)
LoRaSX1262
Frequency433/470/868/915 MHz variants
TX Power22 dBm
Display1.14" TFT 135×240, 262K colors
WiFi/BTNo / BLE 5.0
GPSOptional module
BatteryJST 1.25mm connector, built-in BMS
SolarJST 1.25mm solar input
CaseOptional enclosures
Price€45-60
Power11µA sleep, 23µA Meshtastic mode
Best ForSolar nodes, long-term battery deployment
PurchaseMuzi Works | Rokland
User Review"Nearly a week on single 18650 without solar. Stays fully charged even on cloudy days."
All-in-One Solutions
DeviceLILYGO T-Echo
MCUnRF52840
LoRaSX1262
Frequency433/868/915/923 MHz variants
TX Power22 dBm
Display1.54" E-Paper (ultra-low power)
WiFi/BTNo / BLE 5.0
GPSAir530Z
BatteryBuilt-in 1200mAh
CaseInjection-molded (included)
Price€55-70
PowerUltra-low with e-paper display
Best ForHandheld use, harsh environments

Reticulum RNode Hardware

Important: Reticulum supports the Heltec T114 and other nRF52840 devices via RNode firmware as nodes.

Supported Platforms
DeviceLILYGO LoRa32 V2.1
MCUESP32 WROVER-B
LoRaSX1276/SX1278
Frequency433/868/915 MHz variants
TX Power17 dBm
Display0.96" OLED
WiFi/BTYes / BLE
GPSNo
BatteryJST connector
Case3D-printable STL files
Price€20-30
FirmwareRNode via rnodeconf --autoinstall
Best ForDIY handheld RNodes
DeviceHeltec T114 (RNode Compatible)
SupportFull RNode firmware support
Installationrnodeconf --autoinstall
AdvantagesUltra-low power, professional grade
Use CaseBattery-powered RNode deployments
RNode Firmware Support Matrix
MCU PlatformSupported BoardsFlash MethodReticulum Support
ESP32Generic ESP32, LILYGO, HeltecSerial/USB✅ Full
nRF52840T114, RAK4631, custom designsUF2 bootloader✅ Full
ATmega1284pHomebrew designsISP/Arduino✅ Limited
ATmega2560Arduino Mega compatibleUSB/ISP✅ Limited

WiFi HaLow Hardware (Experimental)

Development Modules
DeviceSeeed Studio Wio WM6180
StandardIEEE 802.11ah (WiFi HaLow)
Frequency902-928 MHz ISM band
RangeUp to 1 km (line of sight)
Data Rate150 kbit/s - 32.5 Mbps
TX Power21±1 dBm
Price€50-80
StatusExperimental, OpenMANET compatible
ReticulumNot directly supported (IP-based vs SDLC)
PurchaseSeeed Studio

Antenna Specifications

LoRa Antennas
TypeFrequencyGainImpedancePriceApplication
Omnidirectional868/915 MHz2-3 dBi50Ω€5-15Base stations
High-gain Yagi868/915 MHz8-12 dBi50Ω€20-50Point-to-point links
Magnetic Mount433 MHz3 dBi50Ω€10-25Vehicle mobile
Whip AntennaAll bands2.1 dBi50Ω€3-8Handheld devices

Purchase Links: AliExpress Antennas | Search for your specific frequency band

Power and Environmental

Solar Power Systems
ComponentSpecificationPricePurpose
1W Solar Panel6V, 167mA€8-15Single T114 node
5W Solar Panel12V, 417mA€25-40Multiple ESP32 nodes
Charge Controller6-24V input€15-40Waveshare Module
18650 Battery2500-3500mAh€5-12Primary storage
Enclosures
TypeIP RatingMaterialPrice RangeUse Case
Waterproof BoxIP65-IP67ABS Plastic€10-30Permanent outdoor
Transparent CaseIP54Polycarbonate€5-15Temporary/indoor
Metal EnclosureIP67Aluminum€25-60Professional installation

Power Analysis

Battery Life Calculations

PlatformSleep CurrentActive CurrentBattery Life (2500mAh)
ESP32 + SX1276900µA - 2mA87-200mA2-14 days
nRF52 + SX1262 (T114)11µA38-125mA6+ months
WiFi HaLow~10-50µA40-60mA3-6 months

Solar Sizing Guidelines

Daily Power = (Sleep Hours × Sleep Current) + (TX Hours × TX Current)

ESP32 Node: ~0.1W average → 5W panel minimum (3x safety factor)
T114 Node: ~0.01W average → 1W panel sufficient (10x safety factor)

Regional Frequency Regulations

RegionPrimary BandPower LimitDuty CycleNotes
Europe868 MHz25mW ERP1% or 10%SRD regulations
North America915 MHz1W EIRPNonePart 15.247
Asia-Pacific433/923 MHz25-50mWVariesCountry-specific
Germany868 MHz25mW ERP1%/10%BNetzA approved

Network Architecture

Meshtastic Topology

  • Max nodes per channel: 100-200 (duty cycle limited)
  • Hop limit: 3-7 hops typical
  • Channel utilization: <10% (regulatory requirement)
  • Optimal spacing: 1-5 km (terrain dependent)

Reticulum Network Design

  • Transport agnostic: LoRa, WiFi, Ethernet, Serial, Packet Radio
  • No hop limits: Dynamic route discovery
  • Bandwidth adaptation: Automatic rate adjustment
  • Heterogeneous: Mix different radio technologies

OpenMANET Architecture

  • IP-based: Full TCP/IP stack
  • Range: Up to 3 km (WiFi HaLow)
  • Device capacity: 1000+ nodes per AP
  • Protocols: B.A.T.M.A.N. Advanced, OLSR

Setup and Configuration

Video Resources

Hardware Setup Guide: YouTube - RNode Hardware Setup

Application Usage: YouTube - Meshtastic App Tutorial

Installation Commands

Reticulum/RNode Setup
# Install RNode configuration utility  
pip install rns --upgrade

# Auto-install firmware (supports T114)
# Or use the web based installer: https://liamcottle.github.io/rnode-flasher/
rnodeconf --autoinstall

Meshtastic Firmware
# Web-based installer (recommended)
# Visit: https://flasher.meshtastic.org/

# For T114: Select "Heltec Mesh Node T114"
OpenMANET (WiFi HaLow)
# Download OpenWRT image
wget https://github.com/OpenMANET/openwrt/releases/latest

# Flash to supported hardware
# See: https://openmanet.github.io/docs/initial-setup.html

Integration Notes

Reticulum + OpenMANET

Currently incompatible due to fundamental differences:

  • Reticulum: SDLC-based, no IP layer
  • OpenMANET: IP-based MANET protocols

Future Integration: Possible through bridge applications or protocol gateways.

OpenMANET Resources:

Purchasing Summary

For Beginners: 2x Heltec LoRa 32 V3 (€50) + antennas (€10) = €60 total

For Serious Deployment: 5x Heltec T114 (€250) + solar panels (€40) + cases (€10) = €300 total

Purchase Priority:

  1. T114 for battery/solar nodes - No soldering, built-in BMS, ultra-low power
  2. ESP32 for mains-powered base stations - WiFi capability, lower cost
  3. Professional antennas for range improvement
  4. Proper enclosures for permanent deployment

Further Reading


This guide reflects current hardware availability as of September 2025. Verify specifications and regional compliance before deployment.

Installation

You can install it with

uv pip install metrum

Or install from this git repo

Fix GPIO and I2C permission errors

How to fix I2C and GPIO permission errors. Run as root

chown :i2c /dev/i2c-1
chown :gpio /dev/gpiochip0
chown :gpio /dev/gpio
chown :gpio /dev/gpiomem
chown :i2c /dev/i2c-2

Getting Started with Metrum

This tutorial will guide you through the process of installing and configuring Metrum on your Reticulum network.

Step 1: Install Metrum

To install Metrum, run the following command:

uv pip install metrum

Step 2: Configure Your Reticulum Network Follow this guide on how to write your reticulum config file.

Step 3: Configure Metrum

Metrum can be configured using a TOML file. The default configuration file path is ~/.config/metrum/config.toml.

[sensor]
class = "metrum.sensors.computer.ExampleSensor"
device_id = "urn:dev:metrum:b97893bb5cb3170e5b09c653c7f759b7"
read_interval = 1                                             
collection_interval = 10
announce_interval = 20
id_filename = "id_computer_sensor" 

[influxdb]
url = "url of the influx db server"
org = "first-org"
bucket = "sensor-data"
retry_interval = 60                                          

Step 4: Define a Sensor

Create a new class that inherits from SensorInterface:

class ExampleSensor(SensorInterface):
    """Mock sensor for testing serialization"""

    def read_sensors(self):
        """Return mock sensor readings with proper SenML formatting"""
        readings = {
            "temperature": {
                "value": 25.5,
                "unit": SenmlUnits.SENML_UNIT_DEGREES_CELSIUS,
                "name": SenmlNames.KPN_SENML_TEMPERATURE,
            },
            "pressure": {
                "value": 101325,
                "unit": SenmlUnits.SENML_UNIT_PASCAL,
                "name": SenmlNames.KPN_SENML_PRESSURE,
            },
            "humidity": {
                "value": 65.0,
                "unit": SenmlUnits.SENML_UNIT_RELATIVE_HUMIDITY,
                "name": SenmlNames.KPN_SENML_HUMIDITY,
            },
        }
        return readings

Run the your custom Environmental Sensor with settings from your config:

uv run --extra computer metrum -p

Or if you have lm_sensors installed, you can run the Computer Sensor

uv run --extra computer metrum -p

Start the subscriber on any device, which is inside connected by the Reticulum network

uv run metrum -s 

Caveats

Currently, there are two bugs:

  • Announces do not show up. Workaround read log of publisher and then run uv run metrum -s --dest <dest id>
  • Loading classes is hard-coded, will be fixed ASAP. Workaround: add your class to the run_publisher function in src/metrum/cli.py

How to Define a New Sensor Interface

Create a new class that inherits from SensorInterface inside sensor py

class ExampleSensor(SensorInterface):
    """Mock sensor for testing serialization"""

    def read_sensors(self):
        """Return mock sensor readings with proper SenML formatting"""
        readings = {
            "temperature": {
                "value": 25.5,
                "unit": SenmlUnits.SENML_UNIT_DEGREES_CELSIUS,
                "name": SenmlNames.KPN_SENML_TEMPERATURE,
            },
            "pressure": {
                "value": 101325,
                "unit": SenmlUnits.SENML_UNIT_PASCAL,
                "name": SenmlNames.KPN_SENML_PRESSURE,
            },
            "humidity": {
                "value": 65.0,
                "unit": SenmlUnits.SENML_UNIT_RELATIVE_HUMIDITY,
                "name": SenmlNames.KPN_SENML_HUMIDITY,
            },
        }
        return readings

TODO

  • explain how to define a good sensor and implement concise efficient packets
  • Create a PR for merging the sensor definiton into its own file

Metrum API

The Metrum API provides a set of classes and functions for working with sensors and telemetry data.

classDiagram
    class SensorInterface {
        +device_id
        +read_sensors()
        +collect_datapoints()
        +collect_reading()
    }
    
    class ExampleSensor {
        +read_sensors()
    }
    
    class MetrumSensorPublisher {
        -reticulum
        -identity
        -sensor
        -destination
        -subscribers
        +announce()
        +encode_announce_data()
        +get_subscriber_hash(link)
        +link_established(link)
        +packet_received(data, packet)
        +link_closed(link)
        +publish_senml()
        +run(collection_interval, announce_interval, read_interval)
    }
    
    class MetrumSensorSubscriber {
        -reticulum
        -identity
        -publishers
        -senml_callback
        +received_announce(destination_hash, announced_identity, app_data)
        +connect_to_publisher(destination_hash)
        +link_established(link, destination_hash)
        +link_closed(link, destination_hash)
        +packet_received(data, packet)
        +reconnect_disconnected(max_age)
    }
    
    class RNS {
        +Identity
        +Destination
        +Link
        +Packet
        +Transport
    }
    
    SensorInterface <|-- ExampleSensor
    MetrumSensorPublisher --> SensorInterface
    MetrumSensorPublisher --> RNS
    MetrumSensorSubscriber --> RNS
  • Classes:
    • MetrumPublisher: A class for publishing telemetry data.
    • MetrumSubscriber: A class for subscribing to telemetry data.
  • Functions:
    • announce(): Announces the publisher's presence to the Reticulum network.
    • publish_telemetry(): Publishes telemetry data to the Reticulum network.

Technical Reference

Reticulum Protocol

The Reticulum protocol is used for communication between devices and nodes on the network.

  • Transport: The Reticulum protocol uses a transport layer to ensure reliable data transmission.
  • Encryption: Metrum uses end-to-end encryption to secure telemetry data.

Explanation

System Architecture

Metrum is designed as a decentralized system, with publishers and subscribers communicating directly with each other.

  • Publishers: Devices or nodes that collect and transmit sensor data.
  • Subscribers: Devices or nodes that receive and process sensor data.

Minimal Efficient Telemetry Reporting Using Mesh (METRUM) Status: Draft Version: 0.2

Abstract

This document specifies a protocol for sensor telemetry over Reticulum networks. It defines a publish-subscribe pattern using Reticulum's destination announce mechanism for discovery and standardized CBOR tags for efficient sensor data representation.

  1. Introduction

    This specification defines a protocol for sending telemetry data over Reticulum networks. It leverages standardized CBOR tags for structured sensor data representation and Reticulum's native capabilities for network transport, discovery, and security.

    METRUM uses CBOR Tag 120 (IoT Data Point) as its primary data format, with Tag 103 (Geographic Coordinates) for location information when relevant. Together, these provide a complete representation for IoT telemetry that is both efficient and standardized.

  2. Terminology

    The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.

    Publisher: A node that produces telemetry data Subscriber: A node that consumes telemetry data IoT Data Point: A measurement value with associated metadata (timestamp, location) Geographic Coordinates: Location information in WGS-84 reference system

  3. Protocol Overview

    The protocol follows a publish-subscribe pattern:

    1. Publishers announce their presence with metadata describing available metrics
    2. Subscribers listen for announces and establish links to publishers
    3. Subscribers send subscription requests over links
    4. Publishers maintain subscriber lists and send telemetry data to subscribers
    5. Data is formatted using standardized CBOR tags
  4. Publisher Behavior

4.1. Announce Mechanism

Publishers MUST create a Reticulum destination with appropriate identity. Publishers MUST announce periodically using CBOR-encoded app_data that includes:

  • "type": Set to "telemetry"
  • "metrics": Array of available metrics
  • "version": Protocol version, currently "0.2"

4.2. Subscription Handling

Publishers MUST maintain a list of subscriber destinations. Upon receiving a subscription message, publishers SHOULD validate the request and add the subscriber to their list.

Publishers SHOULD remove subscribers from their list when the corresponding Reticulum link is broken.

  1. Subscriber Behavior

5.1. Discovery

Subscribers MUST register announce handlers to detect publishers. Subscribers SHOULD filter announces by app_data type field. The publisher's identity serves as the unique identifier for establishing connections.

5.2. Subscription

Subscribers MUST establish a link to desired publishers. Subscribers MUST send a subscription message containing:

  • "subscribe": Boolean set to true
  • "version": Protocol version, currently "0.2"
  1. Message Formats

6.1. Telemetry Data Structure

Each telemetry message MUST be a CBOR map containing:

  • "metric": String name of the measurement
  • "data": IoT Data Point (Tag 120) containing the measurement value and metadata

6.2. IoT Data Point (Tag 120)

METRUM uses CBOR Tag 120 to represent IoT Data Points as defined in its specification.

Tag 120 MUST be applied in one of two ways:

  1. Simple format: 120(value) This indicates a data point with the current UTC time as timestamp and undefined location.

  2. Array format: 120([value, timestamp_tag, location_tag]) Where:

    • value: The measurement value (REQUIRED)
    • timestamp_tag: Tag 1(epoch_time) (OPTIONAL)
    • location_tag: Tag 103([lat, lon, ...]) (OPTIONAL)

If the timestamp is omitted or null, it MUST be interpreted as the current UTC time. If the location is omitted or null, it MUST be interpreted as undefined geographic coordinates.

6.3. Geographic Coordinates (Tag 103)

When location information is included, METRUM uses CBOR Tag 103 as defined in its specification.

Tag 103 MUST be applied to an array with 2-4 elements:

103([latitude, longitude, elevation, uncertainty])

Where:

  • latitude: Decimal degrees (positive = North) (REQUIRED)

  • longitude: Decimal degrees (positive = East) (REQUIRED)

  • elevation: Height in meters (OPTIONAL)

  • uncertainty: Location uncertainty in meters (OPTIONAL)

    The coordinate reference system MUST be WGS-84. Omitting or setting elevation or uncertainty to null indicates these values are not provided.

6.4. Data Models and Examples

The following examples illustrate common telemetry data patterns using the CBOR tags:

6.4.1. Basic Measurement

A simple temperature reading without location:

{
  "metric": "temperature",
  "data": 120([23.5, 1(1500000000)])
}

6.4.2. Geo-tagged Measurement

A temperature reading with full location context:

{
  "metric": "temperature",
  "data": 120([23.5, 1(1500000000), 103([44.78659, 20.44890, 117, 5])])
}

Where the location array represents [latitude, longitude, elevation, uncertainty].

  1. Protocol Evolution

    This protocol is designed to evolve with Reticulum's capabilities. When Reticulum implements "group destinations" in future versions, METRUM will be extended to utilize this feature for more efficient multicast delivery of telemetry data to multiple subscribers.

  2. Security Considerations

    This protocol inherits security properties from Reticulum. All telemetry data is encrypted using Reticulum's mechanisms. Access control is provided through Reticulum's authentication capabilities.

  3. References

9.1. Normative References

[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.

[RFC8428] Jennings, C., et al., "Sensor Measurement Lists (SenML)", RFC 8428, August 2018.

[RNS] Qvist, M., "Reticulum Network Stack", https://github.com/markqvist/Reticulum

[TAG120] Vidovic, D., "CBOR Tag 120 - Internet of Things Data Points", https://github.com/allthingstalk/cbor/blob/master/CBOR-Tag120-Internet-of-Things-Data-Points.md

[TAG103] Vidovic, D., "CBOR Tag 103 - Geographic Coordinates", https://github.com/allthingstalk/cbor/blob/master/CBOR-Tag103-Geographic-Coordinates.md

[WGS-84] National Imagery and Mapping Agency, "Department of Defense World Geodetic System 1984", NIMA TR8350.2, January 2000.