Architecture¶
Oizom edge software runs on Raspberry Pi (ARM), containerized with Docker, and communicates with a Gateway container over HTTP/WebSocket.
Layer Stack¶
main.py
└── Sensor/Sensor.py (orchestrator)
├── OzWrapper/* (sensor category wrappers)
│ └── drivers/* (hardware drivers: I2C, SPI, UART, Modbus)
├── Manager/Manager.py (HTTP client → Gateway)
└── Network/Network.py (connectivity monitor)
Entry point: main.py → Sensor.setup() → Sensor.loop()
Key Components¶
Sensor (Orchestrator)¶
Sensor/Sensor.py initializes all sensor wrappers based on device config fetched from the
Gateway, then runs the sensing loop: read → average → publish. It manages threads and
queues for async communication (Modbus, LoRa, Sigfox, HMI, Socket).
OzWrapper (Sensor Abstractions)¶
Each wrapper in OzWrapper/ covers one sensor category (temperature, dust, CO₂, wind, etc.)
and abstracts over multiple hardware drivers for the same measurement type. All wrappers
extend SensorBase.GenericSensor.
GenericSensor ABC¶
Every wrapper must implement these four methods:
Method |
Purpose |
|---|---|
|
One-time setup, config parsing |
|
Hardware init, GPIO/bus open |
|
Read raw values from driver |
|
Post-process and publish |
drivers (Hardware Drivers)¶
Low-level drivers in drivers/ communicate directly with sensor ICs over I2C, SPI, UART,
or Modbus. One directory per sensor IC (e.g. drivers/BME280/, drivers/CubicPM3006/).
Manager (Gateway Client)¶
Manager/Manager.py is the HTTP client to the Gateway container. It:
Fetches device config via
GET /query/configPosts averaged sensor data via
POST /query/dataPosts realtime data for live dashboards
Network (Connectivity Monitor)¶
Network/Network.py checks internet reachability and communicates with a Network Manager
service. If connectivity is lost, data is queued locally until reconnect.
Config Flow¶
Gateway /query/config
↓
Manager.getConfig()
↓
Sensor.setup() ← determines which sensors/wrappers to initialize
↓
Sensor.loop() ← read → average → publish
Device config comes from the Gateway at startup — it determines which sensors are enabled.
Static base config lives in Configuration/config.json.
Communication Interfaces¶
Async interfaces use queue.Queue for decoupled message passing:
Interface |
Transport |
Queue |
|---|---|---|
|
WebSocket |
✓ |
|
RS-485 Modbus |
✓ |
|
LoRa radio |
✓ |
|
Sigfox cellular |
✓ |
|
Raw TCP |
✓ |
Logging¶
All logging uses utils/oizom_logger.py (OizomLogger).
Never use bare print() or logging.getLogger() — always use the
context_logger.info_with_context() pattern.