Skip to content

Commit 5dc088a

Browse files
author
joerggollnick
committed
new feature mqtt_filter to start a command and give feedback
1 parent f9d95cc commit 5dc088a

File tree

2 files changed

+75
-30
lines changed

2 files changed

+75
-30
lines changed

HANDBOOK.md

Lines changed: 66 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -321,12 +321,12 @@ _mqttwarn_ supports a number of services (listed alphabetically below):
321321
* [ionic](#ionic)
322322
* [azure_iot](#azure_iot)
323323
* [irccat](#irccat)
324-
* [launch](#launch)
325324
* [linuxnotify](#linuxnotify)
326325
* [log](#log)
327326
* mastodon (see [tootpaste](#tootpaste))
328327
* [mattermost](#mattermost)
329328
* [mqtt](#mqtt)
329+
* [mqtt_filter](#mqtt_filter)
330330
* [mqttpub](#mqttpub)
331331
* [mysql](#mysql)
332332
* [mysql_dynamic](#mysql_dynamic)
@@ -1286,30 +1286,6 @@ targets = {
12861286
Requires:
12871287
* gobject-introspection Python bindings
12881288
1289-
### `launch`
1290-
1291-
The `launch` target excutes the specified program and its arguments. It is similar
1292-
to `pipe` but it doesn't open a pipe to the program. It provides stdout as response
1293-
to configured queue.
1294-
Example use cases are f.e. IoT buttons which publish a message when they are pushed
1295-
and the excute an external program. It is also a clone of [mqtt-launcher](https://github.com/jpmens/mqtt-launcher).
1296-
1297-
```ini
1298-
[config:launch]
1299-
targets = {
1300-
# full_topic, topic[0], topic[1], args[0], .....
1301-
'touch' : [ None,0,0,'touch', '/tmp/executed' ],
1302-
'fritzctl' : [ None,0,0,'/usr/bin/fritzctl', 'temperature', "{args[0]}", "{args[1]}" ]
1303-
'backup' : ["response/{topic[1]}/{topic[2]}",0,0,'/usr/bin/sudo','/usr/sbin/dirvish','--vault', "{args[0]}" ],
1304-
}
1305-
```
1306-
1307-
To pass the published data (json args array) to the command, use `{args[0]}` and `{args[1]}` which then gets replaced. Message looks like `'{ "args" : ["' + temp + '","' + room + '"] }'` for `fritzctl`.
1308-
outgoing_topic is constructed by parts of incoming topic or as full_incoming topic.
1309-
1310-
Note, that for each message targeted to the `launch` service, a new process is
1311-
spawned (fork/exec), so it is quite "expensive".
1312-
13131289
### `log`
13141290
13151291
The `log` service allows us to use the logging system in use by _mqttwarn_
@@ -1448,6 +1424,71 @@ This shows the currently full configuration possible. Global values from the
14481424
authentication (`auth`) or (`tls`) you may omit those sections. (The `defaults`
14491425
section must exist.)
14501426
1427+
### `mqtt_filter`
1428+
1429+
The `mqtt_filter` target executes the specified program and its arguments. It is similar
1430+
to `pipe` but it doesn't open a pipe to the program. It provides stdout as response
1431+
to a configured queue.
1432+
Example use cases are f.e. IoT buttons which publish a message when they are pushed
1433+
and the execute an external program. It is also a clone of [mqtt-launcher](https://github.com/jpmens/mqtt-launcher).
1434+
With no response configured it acts like `execute` with multiple arguments.
1435+
1436+
To pass the published data (json args array) to the command, use `{args[0]}` and `{args[1]}` which then gets replaced. Message looks like `'{ "args" : ["' + temp + '","' + room + '"] }'` for `fr
1437+
itzctl`.
1438+
1439+
outgoing_topic is constructed by parts of incoming topic or as full_incoming topic.
1440+
1441+
```ini
1442+
[config:mqtt_filter]
1443+
targets = {
1444+
# full_topic, topic[0], topic[1], args[0], .....
1445+
'touch' : [ None,0,0,'touch', '/tmp/executed' ],
1446+
'fritzctl' : [ None,0,0,'/usr/bin/fritzctl','--loglevel=ERROR','temperature', "{args[0]}", "{args[1]}" ]
1447+
'backup' : ["response/{topic[1]}/{topic[2]}",0,0,'/usr/bin/sudo','/usr/sbin/dirvish','--vault', "{args[0]}" ],
1448+
}
1449+
```
1450+
1451+
Use case for fritzctl is to change the requested temperature for a connected thermostat.
1452+
Topic is constructed as /home/{room}/temperature/{action}.
1453+
1454+
```
1455+
def TemperatureConvert( data=None, srv=None):
1456+
1457+
# optional debug logger
1458+
if srv is not None:
1459+
srv.logging.debug('data={data}, srv={srv}'.format(**locals()))
1460+
1461+
topic = str( data.get('topic','') )
1462+
1463+
# init
1464+
room = ''
1465+
action = 'status'
1466+
1467+
# /home/{room}/temperature/{action}
1468+
parts = topic.split('/')
1469+
1470+
for idx, part in enumerate( parts ):
1471+
if idx == 1:
1472+
room = part
1473+
1474+
if idx == 3:
1475+
action = part
1476+
1477+
temp = str( data.get('payload','sav') )
1478+
if temp == '':
1479+
temp = 'sav'
1480+
1481+
if action == 'set':
1482+
cmd = '{ "args" : ["' + temp + '","' + room + '"] }'
1483+
1484+
return cmd
1485+
```
1486+
1487+
Use case for backup is to run a dirvish backup triggered by a simple mqtt message.
1488+
1489+
Note, that for each message targeted to the `mqtt_filter` service, a new process is
1490+
spawned (fork/exec), so it is quite "expensive".
1491+
14511492
### `mqttpub`
14521493
14531494
This service publishes a message to the broker _mqttwarn_ is connected to. (To
Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/usr/bin/env python
22
# -*- coding: utf-8 -*-
33

4-
__author__ = 'Tobias Brunner <tobias()tobru.ch>'
4+
__author__ = 'Joerg Gollnick <github+mqttwarn()wurzelbenutzer.de>'
55
__copyright__ = 'Copyright 2016 Tobias Brunner / 2021 Joerg Gollnick'
66
__license__ = """Eclipse Public License - v 1.0 (http://www.eclipse.org/legal/epl-v10.html)"""
77

@@ -14,7 +14,7 @@ def plugin(srv, item):
1414

1515
srv.logging.debug("*** MODULE=%s: service=%s, target=%s", __file__, item.service, item.target)
1616

17-
# same as for ssh - extract args from json item.message
17+
# same as for ssh
1818
args=json.loads(item.message)["args"]
1919

2020
if type(args) is list and len(args) == 1:
@@ -25,13 +25,17 @@ def plugin(srv, item):
2525
elif type(args) is str or type(args) is unicode:
2626
args=(quote(args),)
2727

28+
# parse topic
2829
topic=list(map( lambda x: quote(x), item.topic.split('/') ))
29-
outgoing_topic = item.addrs[0].format(full_topic=quote(item.topic),topic=topic)
30+
31+
# replace palceholders args[0], args[1] ..., full_topic, topic[0],
32+
outgoing_topic = item.addrs[0].format(args=args,full_topic=quote(item.topic),topic=topic)
3033
qos = item.addrs[1]
3134
retain = item.addrs[2]
3235
addrs = item.addrs[3:]
33-
# replace args[0], args[1] ...
34-
cmd = [i.format(args=args) for i in addrs]
36+
37+
cmd = [i.format(args=args, full_topic=quote(item.topic),topic=topic) for i in addrs]
38+
3539
srv.logging.debug("*** MODULE=%s: service=%s, command=%s outgoing_topic=%s", __file__, item.service, str( cmd ),outgoing_topic)
3640

3741
try:

0 commit comments

Comments
 (0)