Home

Awesome

SmartServer

This is a python3 based server for SmartHomes based on MQTT to provide device configurations and to collect log messages of devices. It is designed to be used with my Micropython SmartHome Node project pysmartnode which runs on esp8266 and esp32. It can of course be used without using that project just for collecting log messages in your MQTT network. This project can be run as a standalone component or as a plugin for Home-Assistant (see homeassistant branch).

1. How it works

Providing configurations

In order to be able to quickly change some settings for my ESP8266/ESP32 I wanted a central place I could easily change some values and the microcontroller would pick it up on reset. So if a device publishes to home/login/<device-id>/set the server knows that the device <device-id> is requesting its configuration, loads it from files and publishes it to home/login/<device-id>. The structure of the configuration is completely up to you and depends on the implementation on the microcontroller. The server only loads the files and publishes it. More details about how the configuration is saved can be found under 3.2.

Collecting log messages

The server listens to the topic home/log/#. Every publish topic should have the structure home/log/<log_level>/<device_id>. The standard python log levels are supported. Every log messages is being saved to the general log file to have everything in one place as well as to a client log file where only the messages of that clients are saved.

I decided to use this structure for logging messages as it makes it easy to subscribe to all error or critical log messages of all devices without knowing which devices are actually used. That way I could have a MQTT-Client on my phone subscribing to home/log/critical/# and I will get notified if one device has a serious problem.

2. Dependencies

The library depends on the paho mqtt library and python3 as asyncio is used. If you want to use the hjson file syntax, you should have that library installed. I prefer it as it is more readable than json and makes comments possible. If hjson is not installed, it will be ignored and no .hjson file will be loaded. Pyyaml is also needed as the file mapping device-ids to a custom name uses the yaml format as it is easier to read.

So in a short list, this project depends on:

3. Getting started

3.1. Configuration

The included config_example.py can be copied to config.py otherwise this will be done on the first startup. Change the MQTT configuration as needed.

3.2. Providing device configurations

As soon as a device publishes to the configuration request topic home/login/<device-id>/set a new directory is created within the Clients directory in the root of the project. The name of this directory defaults to the device-id in the topic. Inside that directory the client log file is created as well as a config directory.

There are 2 general possibilities to provide a configuration, either by having a config.json or config.hjson file in the root of the client directory (not in the config directory) or by providing a file for each component in the config directory.

config.hjson / config.json

If this file is provided, the server does not check for files inside the config directory. The file will be read and published "as-is" as json, without modifying any of its content.

files inside config

This configuration method can be easier as you can just drop off the configuration of a certain component as .json or .hjson and do not need to paste it into a single configuration file. The server will create a dictionary with the filename (without the extension .json/.hjson) as the key and the content of that file as the value.

Additionally to the component configuration files it is possible to create a file _order.(h)json that contains a list of the components in the order in which they have to be loaded by the microcontroller. Example:

[
  i2c
  htu
]

This way you can make sure that the dependencies of htu are matched by loading the component i2c before htu gets loaded. If this file is not found, the server adds a generic _order entry in the dict containing the list of components as value.

3.3. Changing a configuration

Changing the configuration of a client is possible at all times as the files are being reloaded every time the server receives a config request or log message for that client.

3.4. Changing a device name

As it can be quite challenging to keep in mind which device-id belonged to which device, it is possible to define a custom name in the file device_names.yaml in the root of the project. You just have to replace the null after the device-id with the name you would like your device to have. Once the server receives a new configuration request or log message to that device, the device's configuration directory will be renamed to the name you chose. And so will be the log file. Of course the directory can be renamed manually after the name has been put into the device_names.yaml.

4. Install and run with Docker

Clone this repo and change into the directory with cd SmartServer.

Create your personal config.py file.

Build a docker image with

docker build -t smartserver .

The last . "Dot" is important! To run the SmartServer

docker run -d -v /<pathtodir>/SmartServer:/usr/src/app --name smartserver smartserver:latest

You can find the SmartServer Logs at /<pathtodir>/SmartServer