- DeMoL - A DSL for modeling IoT Devices
Device Modeling Language (DeMoL) - A DSL for modeling IoT devices.
Enables automated source code generation currently for RaspberryPi and RiotOS.
...
| Feature | Summary | |
|---|---|---|
| βοΈ | Protocol-Agnostic |
|
| π | Documentation |
|
| π§© | Modularity |
|
| π¦ | Dependencies |
|
This project requires the following dependencies:
- Programming Language: Python 3.7+
- Packages: textX, jinja2
- Package Manager: Pip
Download this repository and either use the CLI and the API of the DSL directly from source, or in docker container.
- Pull this repository locally
git clone https://github.com/lianoumaria/demol.git- Create a Virtual environment (Optional Step)
python -m venv venv && source ./venv/bin/activate- Install the DSL package in
developmode
python setup.py developThe DeMoL DSL is built using the textX framework and provides a declarative approach to modeling IoT devices.
The grammar is modular and split into 5 interconnected files located in demol/grammar/:
| File | Purpose | Key Concepts |
|---|---|---|
device.tx |
Main device model definition | DeviceModel, Connection, Settings |
component.tx |
Board & peripheral hardware specs | Board, Sensor, Actuator, Pins |
communication.tx |
Message broker configurations | AMQPBroker, MQTTBroker, RedisBroker |
common.tx |
Common utilities | FQN, Import, Comments |
utils.tx |
Additional utilities | FQN handling, Keywords |
The language is built around these fundamental concepts:
- Device - Complete IoT device definition with metadata and configuration
- Board - Microcontroller/SBC hardware (ESP32, Raspberry Pi, etc.)
- Peripheral - External sensors and actuators (BME680, SRF04, etc.)
- Connection - Defines how peripherals connect to boards (power + IO)
- MessageBroker - Communication infrastructure (MQTT, AMQP, Redis)
- Network - WiFi configuration
File Extensions:
.dev- Device models (complete IoT device definitions).hwd- Hardware component models (boards and peripherals)
Every .dev file follows this structure:
Metadata
name: "DeviceName"
description: "Device description"
author: "author_name"
os: Raspbian // or RiotOS
end
Network
ssid: "WiFi_SSID"
passwd: "password"
address: 192.168.1.100 // optional
channel: "6" // optional
end
Broker<MQTT> BrokerName
host: "mqtt.example.com"
port: 1883
ssl: False
auth:
username: "user"
password: "pass"
end
Components
board: BoardModelName
peripherals:
- PeripheralModel(InstanceName1)
- PeripheralModel(InstanceName2)
end
Connection
peripheral: InstanceName1
powerConnections:
- board_pin -- peripheral_pin
ioConnections:
- type: gpio
pin: board_pin -- peripheral_pin
endpoint:
topic: "device/sensor/topic"
type: Publisher
settings:
- setting_name: type = value
end
Describes the device and target platform:
Metadata
name: "SmartSensor"
description: "Environmental monitoring sensor"
author: "developer_name"
os: Raspbian // Raspbian or RiotOS
end
Target Operating Systems:
Raspbian- For Raspberry Pi devicesRiotOS- For embedded systems (ESP32, ESP8266, etc.)
WiFi network settings:
Network
ssid: "IoT_Network"
passwd: "secure_password"
address: 192.168.1.50 // optional static IP
channel: "11" // optional WiFi channel
end
Specifies the hardware composition:
Components
board: RaspberryPi_4B_4GB
peripherals:
- BME680(EnvSensor)
- SonarSRF04(DistanceSensor)
- WS2812(StatusLED)
end
Features:
- Board references are resolved from the global repository in
demol/builtin_models/boards/ - Peripheral models are loaded from
demol/builtin_models/peripherals/ - Supports multi-file imports using FQN (Fully Qualified Names)
- Named peripheral instances for easy reference in connections
Boards are defined in .hwd files and describe microcontroller/SBC specifications using the Board[Type] name syntax:
Board[RPI] RaspberryPi_4B_4GB
operational
vcc: 5V
memory:
flash: 16 gb
ram: 4 gb
cpu:
cpu_family: PiArmCortex
max_freq: 1500 mhz
fpu: true
wifi:
name: wifi_0
freq: 2.4 ghz
bluetooth: BT5
ioVcc: 3V3
end
pins
PPIN power_5v[5V] @ 2;
PPIN gnd_1[GND] @ 6;
DPIN p_21[gpio,sda-1] @ 40;
DPIN p_22[gpio,scl-1] @ 38;
end
end
Board Types: RPI (Raspberry Pi), ESP (ESP32/ESP8266), ARDUINO
Pin Syntax:
PPIN- Power pins (VCC, GND)DPIN- Digital/IO pins with functions
Pin Functions: gpio, adc, dac, pwm-<channel>, sda-<bus>, scl-<bus>, mosi-<bus>, miso-<bus>, sck-<bus>, cs-<bus>, tx-<bus>, rx-<bus>
Power Types: GND, 3V3, 5V, 12V
Sensors use the Sensor[Type] name syntax where Type indicates the sensor category and its message schema:
Sensor[Env] BME680
operational
vcc: 5V
ioVcc: 3V3
powerConsumption: 3 mW
piTpl: "bme680" // optional - RaspberryPi template
riotTpl: "bme680" // optional - RiotOS template
end
pins
PPIN vcc[5V] @ 1;
PPIN gnd[GND] @ 5;
DPIN sda[sda-0] @ 2;
DPIN scl[scl-0] @ 3;
end
attributes
ATTR poll_period[int] = 10;
ATTR humidity_oversample[int] = 2;
ATTR temperature_oversample[int] = 8;
end
end
Available Sensor Types: Distance, Temperature, Humidity, Gas, Pressure, Env, AirQuality, Light, UV, Sound, Acceleration, Gyroscope, Magnetometer, IMU, Tracker, Proximity, Motion, Presence, ADC, Current, Voltage, Power, Flow, Level, Weight, Force, Vibration, Camera, RFID, Fingerprint, GPS, Color
For complete sensor type documentation and message schemas, see SENSORS_ACTUATORS.md.
Actuators use the Actuator[Type] name syntax:
Actuator[ServoController] PCA9685
operational
vcc: 5V
ioVcc: 5V
end
pins
PPIN GND_1[GND] @ 1;
DPIN SCL_1[scl-0] @ 2;
DPIN SDA_1[sda-0] @ 3;
PPIN VCC_1[5V] @ 4;
end
attributes
ATTR num_servos[int] = 16;
ATTR frequency[int] = 50;
end
end
Available Actuator Types: MotorController, ServoController, Relay, Switch, Led, LedArray, NeoPixel, Display, LCD, OLED, Buzzer, Speaker, Stepper, DCMotor, Pump, Valve, Heater, Cooler, Fan
For complete actuator type documentation and command schemas, see SENSORS_ACTUATORS.md.
Units:
- Memory:
b,kb,mb,gb - Frequency:
hz,khz,mhz,ghz - Distance:
mm,cm,m - Power:
uW,mW,W
Connections define how peripherals connect to the board through power and IO pins:
Connection
peripheral: DistanceSensor
powerConnections:
- gnd_1 -- gnd
- power_5v -- vcc
ioConnections:
- type: gpio
name: trigger // optional
pin: p_13 -- trigger
input: False // optional mode
output: True
pullup: False
pulldown: False
open_drain: False
- type: gpio
name: echo
pin: p_14 -- echo
endpoint:
topic: "sensors/distance"
type: Publisher
end
Connection
peripheral: EnvSensor
powerConnections:
- gnd_1 -- GND
- power_5v -- VCC
ioConnections:
- type: i2c
name: env_i2c // optional
slave_address: 0x76
pins:
sda: p_21 -- sda
scl: p_22 -- scl
endpoint:
topic: "sensors/environment"
type: Publisher
settings:
- poll_period: int = 5
- enable_gas: bool = True
end
Connection
peripheral: DisplayModule
powerConnections:
- gnd_1 -- GND
- power_3v3 -- VCC
ioConnections:
- type: spi
name: display_spi // optional
pins:
mosi: p_23 -- mosi
miso: p_19 -- miso
sck: p_18 -- sck
cs: p_5 -- cs
endpoint:
type: Subscriber
end
Connection
peripheral: GPSModule
powerConnections:
- gnd_1 -- GND
- power_5v -- VCC
ioConnections:
- type: uart
name: gps_uart // optional
pins:
tx: p_1 -- tx
rx: p_3 -- rx
baudrate: 115200
endpoint:
topic: "sensors/gps"
type: Publisher
end
endpoint:
topic: "device/sensor/data" // optional, auto-generated if omitted
type: Publisher // Publisher, Subscriber, RPC, Action
Auto-generated Topics: If topic is omitted, it's generated as <device_name>.<peripheral_type>.<peripheral_msg>.<instance_name> (e.g., mydevice.sensor.env.mysensor)
Define peripheral-specific runtime configurations:
settings:
- poll_rate: int = 10
- threshold: float = 25.5
- sensor_name: str = "BME680"
- enable_filter: bool = True
- thresholds: list = [10, 20, 30, 40]
- config: dict = {
timeout: int = 5000,
retry: bool = True,
max_attempts: int = 3
}
end
Setting Types: int, float, str, bool, list, dict
DeMoL supports three message broker types:
Broker<MQTT> MyMqttBroker
host: "mqtt.example.com"
port: 1883
ssl: False
basePath: "/mqtt" // optional
webPath: "/ws" // optional
webPort: 8080 // optional
auth:
username: "sensor_client"
password: "secure_pass"
end
Broker<AMQP> MyAmqpBroker
host: "rabbitmq.example.com"
port: 5672
vhost: "/" // optional
topicExchange: "amq.topic" // optional
rpcExchange: "amq.rpc" // optional
ssl: False
auth:
username: "guest"
password: "guest"
end
Broker<Redis> MyRedisBroker
host: "redis.example.com"
port: 6379
db: 0 // optional
ssl: False
auth:
username: "default"
password: "redis_pass"
end
Authentication Methods:
- Username/Password:
auth: username: "user" password: "pass" - API Key:
auth: key: "api_key_value" - Certificate:
auth: cert: "cert_string"orcertPath: "/path/to/cert"
Here's a complete device model demonstrating all features:
Metadata
name: "SmartEnvironmentMonitor"
description: "Multi-sensor environmental monitoring device"
author: "john_doe"
os: Raspbian
end
Network
ssid: "IoT_Network"
passwd: "secure_password"
end
Broker<MQTT> SmartHomeBroker
host: "mqtt.smarthome.local"
port: 1883
ssl: True
auth:
username: "sensor_node"
password: "node_pass"
end
Components
board: RaspberryPi_4B_4GB
peripherals:
- BME680(EnvSensor)
- SonarSRF04(DistanceSensor)
- WS2812(StatusLED)
end
Connection
peripheral: EnvSensor
powerConnections:
- gnd_1 -- GND
- power_5v -- VCC
ioConnections:
- type: i2c
slave_address: 0x76
pins:
sda: p_21 -- sda
scl: p_22 -- scl
endpoint:
topic: "home/environment/living_room"
type: Publisher
settings:
- poll_period: int = 5
- humidity_oversample: int = 2
- pressure_oversample: int = 4
- temperature_oversample: int = 8
end
Connection
peripheral: DistanceSensor
powerConnections:
- gnd_2 -- gnd
- power_5v -- vcc
ioConnections:
- type: gpio
name: trigger
pin: p_23 -- trigger
- type: gpio
name: echo
pin: p_24 -- echo
endpoint:
topic: "home/distance/entrance"
type: Publisher
end
Connection
peripheral: StatusLED
powerConnections:
- gnd_3 -- GND
- power_5v -- VCC
ioConnections:
- type: gpio
name: LedControl
pin: GPIO10 -- DIN
endpoint:
type: Subscriber
settings:
- colors: list = ['0xFF0000', '0x00FF00', '0x0000FF']
- brightness: int = 128
- num_leds: int = 12
end
## π Supported Sensors & Actuators
DeMoL supports **35 sensor types** and **23 actuator types** covering a wide range of IoT applications:
### Sensor Categories
- **Environmental**: Temperature, Humidity, Pressure, Gas, Env, AirQuality, Light, UV, Sound
- **Motion & Position**: Distance, Proximity, Motion, Presence, Acceleration, Gyroscope, Magnetometer, IMU, Tracker
- **Specialized**: ADC, Current, Voltage, Power, Flow, Level, Weight, Force, Vibration
- **Smart**: Camera, RFID, Fingerprint, GPS, Color
### Actuator Categories
- **Basic**: MotorController, ServoController, Relay, Switch
- **Display & Light**: Led, LedArray, NeoPixel, Display, LCD, OLED
- **Sound**: Buzzer, Speaker
- **Advanced**: Stepper, DCMotor, Pump, Valve, Heater, Cooler, Fan
### Message Schemas
Each sensor and actuator type has a defined message schema for standardized communication:
**Example Sensor Message (Environmental):**
```json
{
"temperature": 23.5,
"humidity": 65.2,
"pressure": 1013.25,
"gas": 450.0,
"timestamp": 1638360000000
}
Example Actuator Command (NeoPixel):
{
"leds": [
{"index": 0, "r": 255, "g": 0, "b": 0},
{"index": 1, "r": 0, "g": 255, "b": 0}
],
"brightness": 128,
"mode": "static",
"timestamp": 1638360000000
}For complete documentation of all sensor and actuator types with their message schemas, see SENSORS_ACTUATORS.md.
For a complete formal specification of the DeMoL language, see SEMANTICS.md, which provides:
- Abstract Syntax: Mathematical representation of DeMoL constructs using syntactic domains and abstract syntax trees
- Formal Grammar: Complete EBNF specification of the concrete syntax
- Static Semantics: Well-formedness rules, type checking, and validation using inference rules
- Operational Semantics: Runtime behavior defined via small-step transition systems covering device initialization, broker connections, GPIO/I2C/SPI/UART operations, and message passing
- Axiomatic Semantics: Hoare logic specifications with pre/post conditions and invariants for device operations
- Type System: Complete type judgments, typing rules, and subtyping relations
- Verification Conditions: Safety properties (no short-circuits, voltage limits), liveness properties (message delivery, sensor readings), and correctness conditions
This formal foundation enables rigorous reasoning about device models, verified code generation, and static analysis tools.
The DSL provides a command-line interface (CLI) for operating on models.
venv [I] β demol --help
Usage: demol [OPTIONS] COMMAND [ARGS]...
An example CLI for interfacing with a document
Options:
--help Show this message and exit.
Commands:
gen
validate
The gen command provides means of executing M2T transformations and provides subcommands, while the validate is used to validate input models.
To validate a device model, for example the ./examples/raspi_iot_device.dev, head to the examples directory and execute:
demol validate raspi_iot_device.devYou should see an output similar to the below, in case of successful validation of the model.
[*] Running validation for model rpi_iot_device.dev
PowerPinConnection:
gnd_1 -> gnd
PowerPinConnection:
power_5v -> vcc
I2C-Connection:
SDA: p_21 -> sda
SCL: p_22 -> scl
[*] Validation passed!Otherwise, the parser will raise an error:
textx.exceptions.TextXSemanticError: rpi_iot_device.dev:29:17: Unknown object "MyBME2" of class "PeripheralDef"The repository includes several utility scripts in the scripts/ directory for validation and code generation testing:
Validates all builtin board and peripheral models (.hwd files) to ensure they comply with the DeMoL grammar and semantics.
python scripts/validate_builtin_models.pyGenerates Raspberry Pi code for all example models in examples/, validating the code generation pipeline.
python scripts/generate_rpi_examples.pyValidates all example models in examples/ against the grammar.
python scripts/validate_examples.pyTODO...
Commlib-py is protected under the MIT License. For more details, refer to the MIT LICENSE uri.
TODO ...
