Project website: https://manythreads.github.io/horme/
The following assumes a Linux environment.
docker
docker-compose
Arch based:
# pacman -S docker docker-compose
Debian based:
See documentation for Debian or Ubuntu.
See documentation for Linux post-installation steps.
Before starting the reconfiguration environment declaration file needs to be created for the specific use case.
A template for such a file can be found under reconf/.env.template
.
This can be copied as reconf/.env
and individually adjusted to the specific usage/deployment scenario.
Build test services:
$ ./build_images.sh
To build the reconf
app, its container and run the container:
$ docker-compose up --build --remove-orphans reconf
$ docker-compose up --build --remove-orphans reconf_debug
To start the container into an interactive tty (useful for testing code changes quickly):
$ docker-compose run --rm reconf_dev
To stop any and all associated containers, auxilliary or otherwise:
$ docker-compose down -v --remove-orphans
$ docker system prune -a --volumes
$ docker-compose logs [mosquitto|neo4j|...]
The HorME configuration & re-configuration system manages the dynamic instantiation and communication between between compliant but otherwise independent service applications. Services are specified by configuration files, which must contain the relevant information for instantiating the service as well as their dependencies. All managed services are required to handle their own message publication and subscription via the MQTT protocol. Services are instantiated by the configuration system and are passed a set of required service parameters as program arguments. If a service is defined with dependencies, the configuration system is obliged to send the service an initial configuration message, containing a list of MQTT topics, to which the service must subscribe. All topics are generated, defined and communicated by the configuration system.
The service configuration file format is as of yet not finally pinned down, but currently includes the following properties:
{
"cmd": {
"exec": "[command or path to executable (string)]",
"args": ["[arguments (list of strings, maybe empty)]"]
}
}
{
"cmd": {
"exec": "node dist/services/ceiling-lamp/service.js --color",
"args": []
}
}
Every compliant service must accept and handle an ordered set of program arguments, which are passed down to it by the configuration system.
- service UUID: an unique string assigned to the service instance
- service topic: the unique topic (path) string assigned to the service
- MQTT host: the MQTT host address
- MQTT authentication (optional): either username and password, only username or no argument at all (all strings)
The configuration system hands only the "raw" topic string to each service, any topic prefixes must be appended by the service itself (see Section 3.4).
The MQTT host argument is passed in the following format:
{protocol}://{hostname|ip-address}:{port}
tcp://mosquitto:1883
As of now, only the TCP protocol is used.
There are two scenarios, in which the configuration system will send a configuration message to a service, and only services specifying dependent services in their configuration need bother with configuration messages at all.
- initial configuration (notifying the service of the topics of its dependencies)
- reconfiguration (notifying the service of added and removed dependencies)
The format of configuration messages is as follows:
{
"add": ["[list of subscriptions (strings)]"],
"del": ["[list of subscriptions (strings)]"]
}
Each subscription entry has the following structure:
{
"uuid": "[string]",
"type": "[string]",
"topic": "[string]"
}
Either list may be empty, but the property must still be present in the message.
Initial configuration messages must never contain any removals (empty list in
del
property).
All communicated topics are "raw", i.e., without any prefixes (see
Section 3.4).
All configuration messages must be sent as retain
messages, meaning they will
be stored by the MQTT broker.
All topics generated by the configuration system must adhere to the following format:
{$apartment-identifier}/{"global"|$room-identifier}/{$service-type}{$service-uuid}
Note, that the service-type
and service-uuid
are concatenated in the final
part of the topic.
In order to avoid topic string parsing as much as possible, services are
encouraged to send their type and uuid in every message they publish.
Services, that are not associated with a specific room have the special
"global"
string in their topic instead of a room-identifier
.
Topics may be prefixed with one of four possible prefix strings:
data
conf
fail
inf
A fifth cmd
prefix is reserved for potential use at a later stage
Services that publish data must publish it to their assigned topic prefixed with
data
and services with dependencies must listen to their assigned topic
prefixed with conf
for configuration messages.
The fail
prefix is exclusively reserved for failure notification by the
configuration system and the inf
prefix is reserved for event and state
inference communication.
A service of type light-switch
with the UUID 550e8400-e29b-11d4-a716-446655440000
must publish all of its registered events to the following topic and any
dependent services must likewise subscribe to it:
data/apt-421/bedroom/light-switch550e8400-e29b-11d4-a716-446655440000
A service of type ceiling-lamp
with the UUID 79cfa266-06fb-11eb-adc1-0242ac120002
must subscribe to this topic:
conf/apt-421/bedroom/ceiling-lamp79cfa266-06fb-11eb-adc1-0242ac120002
(bound to change)
As of now, the following service types are modelled:
light-switch
camera-motion-detect
failure-detect
ceiling-lamp
Both light-switch
and camera-motion-detect
services can be used to infer
presence in their respective room.
failure-detect
services are exclusively used to detect failure of
light-switch
service instances (for now).
Both failure-detect
and ceiling-lamp
depend on any number of light-switch
services (two as of now).
All services publish their state in messages of the following format:
{
"uuid": "[string]",
"type": "[string]",
"value": "[on|off]", // for now there are only binary sensor services
"timestamp": "[unsigned long integer]" // UNIX time in seconds
}
TODO