Protocol definition#
The JA-121T protocol definition provides a definition of generic system properties, as well as two groups of MQTT topics. The first group consists of a list of topics where ja2mqtt publishes state changes as they occur in Jablotron. The second group consists of a list of topics that ja2mqtt subscribes to, which clients can use to query section and peripheral states. The protocol definition is a YAML configuration file that uses Jinja2 template with data from the Jablotron topology provided in the main configuration file.
Note
The protocol definition is provided in ja2mqtt.yaml
and you normally do not need to modify this file unless you want to change the way how JA121 protocol is implemented by ja2mqtt.
The definition file should include a version
property that defines the schema version of the file. ja2mqtt validates the file against the schema of the specified version, and the valid version is 1.0
.
version: 1.0
System properties#
The system properties provide a definition for the correlation ID, correlation timeout, and the number of bits in peripheral states.
The correlation ID is the field name in incoming requests (received via a topic that ja2mqtt is subscribed to) that ja2mqtt copies to the outgoing response (sent via a topic that ja2mqtt publishes). The correlation timeout is the maximum time in seconds that ja2mqtt uses to relate incoming and outgoing events and to which the correlation ID applies. When correlation ID is not present, ja2mqtt will not correlate any data.
The property prfstate_bits
defines a number of bits in PRFSTATE
object. This value depends on a number of peripherals that your Jablotron system uses.
The topic_prefix
property defines a prefix for both publishing and subscribing topics. By default, the prefix is ja2mqtt
. However, it may be useful to change the prefix when you have multiple ja2mqtt instances using a single MQTT broker, and you want to segregate events from both instances.
The following configuration shows the system property definitions with initial values.
system:
correlation_id: 'corrid'
correlation_timeout: 1.5
prfstate_bits: 24
topic_prefix: 'ja2mqtt'
Jinja templates#
The Jablotron topology may have multiple sections and peripherals that could have different rules but share the same parameters. To address this, ja2mqtt definition file utilizes Jinja2 templates and Jablotron topology data to define parametrized publishing and subscribing topic rules.
For instance, the following code shows how MQTT topics for all sections can be defined:
{% for s in topology.section %}
- name: ja2mqtt/section/{{ s.name }}
rules:
- read: !py pattern('STATE {{ s.code }} (READY|ARMED_PART|ARMED|SERVICE|BLOCKED|OFF)')
write:
section_code: {{ s.code }}
section_name: {{ s.name }}
state: !py data.match.group(1)
{% endfor %}
This code uses a for
loop to iterate through all sections in the topology and generates MQTT topics based on the specified rules.
MQTT topics#
ja2mqtt publishes events on a number of topics and subscribes to topics to receive requests to query or control Jablotron system. Any topic starts with a topic prefix (ja2mqtt
by default) and is followed by a type and an optional sub-type or a location. The topic names are automatically generated based on ja2mqtt topic definition and Jablotron topology.
Hint
You can use the command ja2mqtt config topics -c config.yaml
to retrieve the publishing and subscribing topics that your configuration defines.
Publishing topics#
ja2mqtt utilizes MQTT topics to publish state changes for both sections and peripherals. The topics include general-purpose topics such as ja2mqtt/heartbeat
, ja2mqtt/error
, and ja2mqtt/response
, as well as specific topics for section and peripheral state changes. The publishing topics are defined in the serial2mqtt
property, which apart from the topic name it also defines a set of rules that determine the data to be read from the serial interface and written to MQTT.
Sections#
The section topics follow the format {prefix}/section/{name}
, where {prefix}
is the topic prefix defined in system
properties and {name}
refers to the section name. As an example of a topic and a rule for the house
section, suppose we have the following configuration that specifies a topic for publishing section state changes under the name ja2mqtt/section/house
:
- name: section/house
rules:
- read: !py section_state('STATE (1) (READY|ARMED_PART|ARMED|SERVICE|BLOCKED|OFF)',1,2)
write:
section_code: 1
section_name: house
state: !py data.state
updated: !py data.updated
In this configuration, the read
property of the rule matches the data in the serial interface using the provided regular expression, which defines the possible state changes for section 1 as READY
, ARMED_PART
, ARMED
, SERVICE
, BLOCKED
, or OFF
. The function section_state
is a built-in function that tracks the state change for a section and updates the time at which the section state was last changed. Once the read
condition is met, the data is written to MQTT under the topic named ja2mqtt/section/house
. The written data fields include the section code (set to 1), the section name (set to “house”), the section state (set to the matched group from the regular expression), and the time of the last section state update.
In the write
property, you can define arbitrary sub-properties as data to be sent to MQTT. When specifying values for the data, you can use any arbitrary values or a Python expression. The scope to evaluate the expression includes the data
variable that contains the data read from the serial interface. If you use a built-in function in the read
property of the rule, you can access various properties of the result of the function such as the match
object that can be used for pattern
and section_state
functions.
In the example, for the following serial interface data,
STATE 1 ARMED
the topic with name ja2mqtt/section/house
will be published with the following data:
{
"section_code": 1,
"section_name": "house",
"state": "ARMED",
"updated": 1683727085.619606
}
Peripherals#
The ja2mqtt definition file specifies the topics for publishing changes in peripheral states. The peripheral topics follow the format ja2mqtt/{type}/{location}
, where {type}
refers to the type of peripheral (e.g. motion, siren, magnet, smoke) and {location}
refers to the location of the peripheral device (e.g. garage
, house/groundfloor/office
, etc.). The types and locations are taken from the Jablotron topology in the main configuration file and can be defined by the user.
Although the rules for these topics are similar to the ones for MQTT topics, ja2mqtt uses different functions to decode the peripheral states that JA-121T transmits through the serial interface as PRFSTATE {number}
. Here, {number}
is an octal number that encodes the peripheral states. ja2mqtt includes decoding and encoding functions for this PRFSTATE
octal number based on the JA-121T serial protocol.
The following example provides a topic rule to read the PRFSTATE
message in the serial interface and generate event data with five properties: name
, type
, pos
, state
, and updated
. The read
property of the rule uses a Python expression with the prf_state
function that utilizes the internal peripheral state object and checks if the state of the peripheral on position 3
has changed (i.e., from ON to OFF or from OFF to ON). If the state has changed, the write
property specifies the data to be generated for the event, including the name of the peripheral, its type, position, state and updated time. Since this rule is only applicable to a single peripheral state change topic, and the PRFSTATE
number may indicate state changes for multiple peripherals, the process_next_rule
property is included to allow for the processing of the next topic rule and the generation of events for other peripheral state changes.
Here is the example YAML configuration:
- name: motion/garage
rules:
- read: !py prf_state(3)
write:
name: garage
type: motion
pos: 1
state: !py data.state
updated: !py data.updated
process_next_rule: True
Subscribing topics#
Ja2mqtt subscribes to multiple topics to receive requests that clients can use to query or control the Jablotron system. The topic rules are defined such that the read
property specifies the format of the event data, while the write
property defines the string that ja2mqtt writes to the serial interface.
Sections#
Topics for sections are in a form {prefix}/section/{name}/{verb}
where {prefix}
is a topic prefix, {name}
is the section name, and {verb}
represents a type of operation to perform, i.e. get
, set
, unset
, and setp
to retrieve a section state, arm or disarm a section or partially arm a section.
In addition, there is a topic with the name ja2mqtt/section/get
that can be used to retrieve the state of all sections. The following example presents a rule for this topic with a read
property that defines incoming event data with a pin
property. The pattern
function specifies a regular expression that the pin
property value must match. If the value does not match, the request will not be processed, and an error will be logged. The write
property defines a string to be written to the serial interface. The format
function formats the string with the pin
parameter taken from the event data. The request_ttl
property defines a TTL (time-to-live) for the corresponding responses that will be generated as a result of the operation. A TTL value of 99
indicates that up to 99 responses will be correlated with this request. This is necessary because the JA-121T command STATE
results in several STATE
serial interface events generated by Jablotron, for which ja2mqtt creates publishing events. The correlation of such messages is still limited by the correlation_timeout
system property.
- name: section/get
rules:
- read:
pin: !py pattern("^[0-9]{4}$")
write: !py format("{pin} STATE",pin=data.pin)
request_ttl: 99
Peripherals#
To retrieve the state of peripherals, the following rule uses the write_prf_state
function that generates the string PRFSTATE
, which is then written to the serial interface. The function makes sure that subsequent peripheral state events will be published under the corresponding MQTT topics, regardless of the change in the peripheral state.
- name: prfstate/get
rules:
- write: !py write_prf_state()
request_ttl: 128
All states#
The ja2mqtt protocol definition includes a all/get
topic that allows retrieval of states for both sections and peripherals. The following YAML code displays the rules for this topic, which are constructed from rules of the section/get
and prfstate/get
topics.
- name: all/get
rules:
- write: !py write_prf_state()
request_ttl: 128
- read:
pin: !py pattern("^[0-9]{4}$")
write: !py format("{pin} STATE",pin=data.pin)
request_ttl: 99