Services#
Introduction#
This section of the documentation will outline how to configure mqttwarn services. Services are instances of service plugins, using Python modules to implement notifier components.
Later, you will learn how to subscribe to MQTT topics, and map them to the services you have defined here.
You can choose from a variety of Notifier catalog, or you can write your own notification plugin easily, see Creating custom notification plugins.
Configuration#
Configuration sections called [config:xxx] configure settings for a service,
where xxx is the name of the service. When a service is launched, a corresponding
section is mandatory to be present in the mqttwarn configuration file.
A service configuration section has a mandatory option called targets, which is
used to define groups of multiple recipients or targets. It is expected to be a
dictionary, where each item defines an individual service point for a particular
service.
The keys are target names, and the structure and value depends on what the particular service plugin implementation expects.
The original configuration variant, still used by many service plugins, looks like this.
[config:xxx]
targets = {
    'targetname1': [ 'address1', 'address2' ],
    'targetname2': [ 'address3', 'address4' ],
  }
Note
Historically, as outlined in the example above, the value / right-hand side of the
recipient/target group map, was exclusively defined as a list, and as such, the
term address list was used.
Nowadays, after a few evolution cycles of mqttwarn, the value can have a different data type and structure, depending on the particular service plugin. As such, the term target address descriptor is used now.
For example, after implementing named target address descriptor options, the configuration of the Pushsafer service plugin is much more capable now.
[config:pushsafer]
targets = {
    'basic': { 'private_key': '3SAz1a2iTYsh19eXIMiO' },
    'extraphone': { 'private_key': '3SAz1a2iTYsh19eXIMiO', 'time_to_live': 60, 'priority': 2, 'retry': 60, 'expire': 600, 'answer': 0 }
    }
Other than the mandatory targets option, and an optional module option, these sections
may have more options. Some of them may even be required for a particular service.
Effectively, this configuration snippet defines individual groups of “target addresses” for a particular service, and assigns them “target names”. Using those groups, it is, for example, possible to define different…
- target paths for the - fileservice.
- database tables for the - mysqlservice.
- topic names for outgoing - mqttpublishers.
- hostname/port number combinations for - xbmc, etc.
General options#
Individual services offer different configuration options, however there are a few settings optionally available to all services.
For example, the decode_utf8 option, which is True by default, can be
turned off for a whole service definition. This makes it suitable to receive
and process binary or other non-UTF8 data.
# Don't assume incoming MQTT message to be encoded in UTF-8.
# This is applicable for receiving and processing binary data.
decode_utf8 = False
Launching services#
In order to launch configured services, you will have to add them to the global
defaults section of the mqttwarn.ini configuration file. For launching
multiple services, please use a comma-separated list.
[defaults]
launch = xxx, foo
Module resolvement#
Resolving the name#
The Python module name for the service will be determined…
- from the name of the definition itself. For - [config:xxx], it would be- xxx.- [config:xxx]
- from the value of the optional - moduleoption within that configuration section, when given.- [config:custom-service] module = xxx - Note - A service definition using the - module = xxxvariant will use the Python module- xxx, however it has its own distinct set of service options. It is thus possible to have several service configurations for the same underlying service, with different configurations, e.g. one for files that should have notifications appended, and one for files that should get truncated before writes.- Example- Consider this configuration file in which we want two services of type log. We launch an additional - xxxlogservice here, also based on the- logmodule.- # Note how both services must be launched. [defaults] launch = log, xxxlog # Configure two individual services, both using the `log` module. [config:log] targets = { 'debug' : [ 'debug' ], } # Note how the xxxlog is instantiated from log. [config:xxxlog] module = log targets = { 'debug' : [ 'debug' ], } # The topic subscription rule using both services. [topic/1] targets = log:debug, xxxlog:debug 
Resolving the module#
There are three options how the module name will be resolved to a Python module.
- When the module name is a plain string without a dot, and does not end with - .py, it will be resolved to a module filename inside the built-in mqttwarn/services directory.
- When the module name contains a dot, and does not end with - .py, it will be resolved as an absolute dotted reference to a Python module, see From package.
- When the module name ends with a - .pysuffix, it will be treated as a reference to a Python file, see From file.
Loading external services#
In order to bring in custom sink components to mqttwarn in form of service
notification plugins, there are two options. We will explore them on behalf of
corresponding example configuration snippets.
From package#
When the module name contains a dot, and does not end with .py, it will be
resolved as an absolute dotted reference using Python’s importlib.
In this way, it is easy to load modules from other packages than mqttwarn.
This configuration snippet outlines how to load a custom plugin from a Python
module referenced in “dotted” notation. Modules will be searched for in all
directories listed in sys.path, so any installed Python package will be
available. Additional directories can be added by using the PYTHONPATH
environment variable.
Example
[defaults]
; name the service providers you will be using.
launch = log, file, acme.foobar
[config:acme.foobar]
targets = {
    'default'  : [ 'default' ],
  }
[test/plugin-module]
; echo '{"name": "temperature", "value": 42.42}' | mosquitto_pub -h localhost -t test/plugin-module -l
targets = acme.foobar:default
format = {name}: {value}
From file#
When the module name ends with a .py suffix, it will be treated as a
reference to a Python file. It can be either absolute, or relative to
the current working directory, or relative to the directory of the
configuration file.
This configuration snippet outlines how to load a custom plugin from a Python
file referenced by file name. When relative file names are given, they will be
resolved from the directory of the mqttwarn.ini file, which is, by default,
the /etc/mqttwarn folder.
Example
[defaults]
; name the service providers you will be using.
launch = log, file, acme/foobar.py
[config:acme/foobar.py]
targets = {
    'default'  : [ 'default' ],
  }
[test/plugin-file]
; echo '{"name": "temperature", "value": 42.42}' | mosquitto_pub -h localhost -t test/plugin-file -l
targets = acme/foobar.py:default
format = {name}: {value}
Creating custom notification plugins#
Creating new service plugins is easy, and we recommend you use the file
plugin as a blueprint and start from there.
Plugins are invoked with two arguments, srv and item. srv is an object
with some helper functions, and item a dictionary which contains information
on the message which is to be handled by the plugin. item has the following
top-level keys:
item = {
    'service'       : 'string',       # Name of handling service (`twitter`, `file`, ...)
    'target'        : 'string',       # Name of target (`o1`, `janejol`) in service
    'addrs'         : list,           # List of addresses from SERVICE_targets
    'config'        : dict,           # None or dict from SERVICE_config {}
    'topic'         : 'string',       # MQTT topic the message was received on
    'payload'       : 'string',       # Raw message payload
    'message'       : 'string',       # Formatted message (if no format string, then equals payload)
    'data'          : None,           # Dictionary with transformation data
    'title'         : 'mqttwarn',     # Optional title from title{}
    'priority'      : 0,              # Optional priority from priority{}
}