Architecture¶
Py ToloMEO organises microservice logic into four layers — service, plugin, messaging, and task. Each layer has a single responsibility and communicates with adjacent layers through well-defined interfaces.
The diagram below gives the high-level picture: how an inbound command travels from the ToloMEO cloud down to a plugin, and how outbound data and events travel back up to the cloud.
A service is configured declaratively through an inner Meta class — its
plugin class, messaging strategy, and commands. These settings are assembled
across the whole class hierarchy at class-definition time, so subclasses
extend behaviour by declaration rather than by overriding.
Service Layer¶
The service (built on ServiceBase / NATSService) is the top-level
orchestrator and owns four collaborators: the messaging strategy, a command
registry, a plugin registry, and a task manager. It:
- Subscribes to
commands.{name}.reqand decodes inbound commands - Runs a service-level command if one is registered, otherwise routes the
command to the plugin identified by the payload's
id - Publishes command responses to
events.params, sensor data toevents.data, and OTA/status events toevents.infos - Publishes a heartbeat to
heartbeat.{name}.service; sensor data and info arrive via push — plugins callpush_reading/push_info, which invoke a callback the service publishes from. There is no polling loop.
A service holds one plugin class but many plugin instances, keyed by plugin ID. SenML records are built in this layer before publishing — the messaging layer never sees SenML.
Plugin Layer¶
Plugins encapsulate domain logic and are decoupled from the transport. The
two built-in base classes are SensorPlugin (for continuous metric
publishing) and OTAPlugin (for firmware update management). Each plugin:
- Declares its commands, input metrics, and output metrics in a
Metaclass (output metrics are namespaced with the plugin ID) - Manages its own connection lifecycle to hardware or external resources
- Runs background tasks (e.g. sensor read loops) on its own task manager and pushes readings to the service through a data-available callback — delivery is entirely push-driven, with no polling on the service side
Messaging Layer¶
NATSMessageStrategy wraps the nats-py client and is pure transport: it
serialises payloads to JSON and publishes or subscribes on NATS subjects. It
performs no SenML encoding — that belongs to the service layer. The service
interacts with it only through the MessageStrategyABC interface. Swapping the
strategy class in Meta is the only change needed to use a different
transport.
ToloMEO Platform Context¶
A deployed Py ToloMEO microservice runs on an edge device. It connects to the
ToloMEO cloud platform through the connhex-edge-agent (a NATS proxy). The
platform sends commands inbound (operator triggers an OTA update) and receives
data outbound (sensor readings, OTA status events). Py ToloMEO handles the
edge side of this contract.
See also

