dbus2mqtt 0.4.1__tar.gz → 0.4.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of dbus2mqtt might be problematic. Click here for more details.
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/.github/release-drafter.yml +4 -5
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/.pre-commit-config.yaml +3 -3
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/PKG-INFO +6 -4
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/README.md +5 -3
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/docker/Dockerfile.dev +1 -1
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/docker/Dockerfile.pypi +1 -1
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/docs/examples/dbus2mqtt_internal_state.yaml +7 -1
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/docs/examples/home_assistant_media_player.md +1 -1
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/docs/examples/home_assistant_media_player.yaml +4 -5
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/docs/examples/linux_desktop.yaml +0 -4
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/docs/examples.md +1 -1
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/docs/flows.md +37 -11
- dbus2mqtt-0.4.2/renovate.json +36 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/src/dbus2mqtt/config/__init__.py +8 -1
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/src/dbus2mqtt/dbus/dbus_client.py +1 -1
- dbus2mqtt-0.4.2/src/dbus2mqtt/flow/actions/log_action.py +36 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/src/dbus2mqtt/flow/flow_processor.py +5 -1
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/src/dbus2mqtt/mqtt/mqtt_client.py +29 -8
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/src/dbus2mqtt/template/templating.py +11 -0
- dbus2mqtt-0.4.2/tests/flow/actions/test_log.py +28 -0
- dbus2mqtt-0.4.1/renovate.json +0 -22
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/.dockerignore +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/.env.example +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/.github/scripts/release-versions.py +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/.github/workflows/ci.yml +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/.github/workflows/docker-dev.yml +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/.github/workflows/docker-stable.yml +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/.github/workflows/pre-commit.yml +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/.github/workflows/publish.yml +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/.github/workflows/release-drafter.yml +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/.gitignore +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/.python-version +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/.vscode/launch.json +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/.vscode/settings.json +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/.yamllint.yml +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/LICENSE +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/docs/debugging.md +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/docs/examples/bluez.md +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/docs/examples/bluez.yaml +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/docs/examples/dbus2mqtt_internal_state.md +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/docs/examples/linux_desktop.md +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/pyproject.toml +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/src/dbus2mqtt/__init__.py +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/src/dbus2mqtt/__main__.py +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/src/dbus2mqtt/config/jsonarparse.py +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/src/dbus2mqtt/dbus/dbus_types.py +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/src/dbus2mqtt/dbus/dbus_util.py +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/src/dbus2mqtt/dbus/introspection_patches/mpris_playerctl.py +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/src/dbus2mqtt/dbus/introspection_patches/mpris_vlc.py +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/src/dbus2mqtt/event_broker.py +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/src/dbus2mqtt/flow/__init__.py +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/src/dbus2mqtt/flow/actions/context_set.py +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/src/dbus2mqtt/flow/actions/mqtt_publish.py +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/src/dbus2mqtt/main.py +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/src/dbus2mqtt/template/dbus_template_functions.py +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/tests/__init__.py +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/tests/config/fixtures/payload_template_jinja_expressions.yaml +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/tests/config/fixtures/payload_template_off.yaml +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/tests/config/fixtures/schedule_cron_trigger.yaml +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/tests/config/test_config.py +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/tests/config/test_examples.py +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/tests/conftest.py +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/tests/dbus/test_dbus_client.py +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/tests/dbus/test_dbus_client_mqtt_command.py +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/tests/flow/actions/test_context_set.py +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/tests/flow/actions/test_mqtt_publish.py +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/tests/flow/test_flow_processor.py +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/tests/flow/triggers/test_dbus_client_triggers.py +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/tests/template/test_templating.py +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/tests/template/test_templating_config.py +0 -0
- {dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/uv.lock +0 -0
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
name-template: 'v$RESOLVED_VERSION
|
|
1
|
+
name-template: 'v$RESOLVED_VERSION'
|
|
2
2
|
tag-template: 'v$RESOLVED_VERSION'
|
|
3
3
|
exclude-labels:
|
|
4
4
|
- dependencies
|
|
5
|
+
- skip-changelog
|
|
5
6
|
categories:
|
|
6
7
|
- title: 🚨 Breaking changes
|
|
7
8
|
labels:
|
|
@@ -13,13 +14,13 @@ categories:
|
|
|
13
14
|
- title: 🐛 Bug Fixes
|
|
14
15
|
labels:
|
|
15
16
|
- bugfix
|
|
16
|
-
- title: 🧰
|
|
17
|
+
- title: 🧰 Misc
|
|
17
18
|
labels:
|
|
18
19
|
- chore
|
|
19
20
|
- documentation
|
|
20
21
|
- title: ⬆️ Dependency updates
|
|
21
22
|
labels:
|
|
22
|
-
-
|
|
23
|
+
- dependencies
|
|
23
24
|
exclude-contributors:
|
|
24
25
|
- jwnmulder
|
|
25
26
|
autolabeler:
|
|
@@ -47,6 +48,4 @@ version-resolver:
|
|
|
47
48
|
default: patch
|
|
48
49
|
change-template: '* $TITLE (#$NUMBER)'
|
|
49
50
|
template: |
|
|
50
|
-
## Changes
|
|
51
|
-
|
|
52
51
|
$CHANGES
|
|
@@ -33,7 +33,7 @@ repos:
|
|
|
33
33
|
- --strict
|
|
34
34
|
|
|
35
35
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
36
|
-
rev: v0.12.
|
|
36
|
+
rev: v0.12.2
|
|
37
37
|
hooks:
|
|
38
38
|
- id: ruff
|
|
39
39
|
args:
|
|
@@ -42,11 +42,11 @@ repos:
|
|
|
42
42
|
- I
|
|
43
43
|
|
|
44
44
|
- repo: https://github.com/astral-sh/uv-pre-commit
|
|
45
|
-
rev: 0.7.
|
|
45
|
+
rev: 0.7.19
|
|
46
46
|
hooks:
|
|
47
47
|
- id: uv-lock
|
|
48
48
|
|
|
49
49
|
- repo: https://github.com/RobertCraigie/pyright-python
|
|
50
|
-
rev: v1.1.
|
|
50
|
+
rev: v1.1.403
|
|
51
51
|
hooks:
|
|
52
52
|
- id: pyright
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dbus2mqtt
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Summary: A Python tool to expose Linux D-Bus signals, methods and properties over MQTT - featuring templating, payload enrichment and Home Assistant-ready examples
|
|
5
5
|
Project-URL: Repository, https://github.com/jwnmulder/dbus2mqtt.git
|
|
6
6
|
Project-URL: Issues, https://github.com/jwnmulder/dbus2mqtt/issues
|
|
@@ -32,8 +32,8 @@ Description-Content-Type: text/markdown
|
|
|
32
32
|
|
|
33
33
|
# dbus2mqtt
|
|
34
34
|
|
|
35
|
-
**dbus2mqtt** is a Python application that bridges **
|
|
36
|
-
It lets you forward D-Bus signals and properties to MQTT topics, call D-Bus methods via MQTT messages, and shape payloads using flexible **Jinja2 templating**.
|
|
35
|
+
**dbus2mqtt** is a Python application that bridges **DBus** with **MQTT**.
|
|
36
|
+
It lets you forward Linux D-Bus signals and properties to MQTT topics, call D-Bus methods via MQTT messages, and shape payloads using flexible **Jinja2 templating**.
|
|
37
37
|
|
|
38
38
|
This makes it easy to integrate Linux desktop services or system signals into MQTT-based workflows - including **Home Assistant**.
|
|
39
39
|
|
|
@@ -154,6 +154,8 @@ or
|
|
|
154
154
|
mqtt:
|
|
155
155
|
host: localhost
|
|
156
156
|
port: 1883
|
|
157
|
+
subscription_topics:
|
|
158
|
+
- dbus2mqtt/#
|
|
157
159
|
```
|
|
158
160
|
|
|
159
161
|
### Exposing dbus methods
|
|
@@ -224,7 +226,7 @@ dbus:
|
|
|
224
226
|
|
|
225
227
|
## Flows
|
|
226
228
|
|
|
227
|
-
|
|
229
|
+
A reference of all supported flow triggers and actions can be found on [Flows](https://github.com/jwnmulder/dbus2mqtt/blob/main/docs/flows.md)
|
|
228
230
|
|
|
229
231
|
## Jinja templating
|
|
230
232
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# dbus2mqtt
|
|
2
2
|
|
|
3
|
-
**dbus2mqtt** is a Python application that bridges **
|
|
4
|
-
It lets you forward D-Bus signals and properties to MQTT topics, call D-Bus methods via MQTT messages, and shape payloads using flexible **Jinja2 templating**.
|
|
3
|
+
**dbus2mqtt** is a Python application that bridges **DBus** with **MQTT**.
|
|
4
|
+
It lets you forward Linux D-Bus signals and properties to MQTT topics, call D-Bus methods via MQTT messages, and shape payloads using flexible **Jinja2 templating**.
|
|
5
5
|
|
|
6
6
|
This makes it easy to integrate Linux desktop services or system signals into MQTT-based workflows - including **Home Assistant**.
|
|
7
7
|
|
|
@@ -122,6 +122,8 @@ or
|
|
|
122
122
|
mqtt:
|
|
123
123
|
host: localhost
|
|
124
124
|
port: 1883
|
|
125
|
+
subscription_topics:
|
|
126
|
+
- dbus2mqtt/#
|
|
125
127
|
```
|
|
126
128
|
|
|
127
129
|
### Exposing dbus methods
|
|
@@ -192,7 +194,7 @@ dbus:
|
|
|
192
194
|
|
|
193
195
|
## Flows
|
|
194
196
|
|
|
195
|
-
|
|
197
|
+
A reference of all supported flow triggers and actions can be found on [Flows](https://github.com/jwnmulder/dbus2mqtt/blob/main/docs/flows.md)
|
|
196
198
|
|
|
197
199
|
## Jinja templating
|
|
198
200
|
|
|
@@ -25,7 +25,7 @@ RUN --mount=type=cache,target=/root/.cache/uv \
|
|
|
25
25
|
uv sync --frozen --no-dev
|
|
26
26
|
|
|
27
27
|
# Then, use a final image without uv
|
|
28
|
-
FROM python:3.13-slim-bookworm
|
|
28
|
+
FROM python:3.13-slim-bookworm@sha256:6544e0e002b40ae0f59bc3618b07c1e48064c4faed3a15ae2fbd2e8f663e8283
|
|
29
29
|
# It is important to use the image that matches the builder, as the path to the
|
|
30
30
|
# Python executable must be the same, e.g., using `python:3.12-slim-bookworm`
|
|
31
31
|
# will fail.
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# mqtt:
|
|
2
2
|
# host:
|
|
3
3
|
# port:
|
|
4
|
+
# subscription_topics:
|
|
5
|
+
# - dbus2mqtt/#
|
|
4
6
|
|
|
5
7
|
dbus:
|
|
6
8
|
subscriptions:
|
|
@@ -37,4 +39,8 @@ flows:
|
|
|
37
39
|
payload_type: json
|
|
38
40
|
payload_template:
|
|
39
41
|
now: "{{ now().isoformat() }}"
|
|
40
|
-
|
|
42
|
+
dbus_list_res: "{{ dbus_list('*') }}"
|
|
43
|
+
- type: log
|
|
44
|
+
level: INFO
|
|
45
|
+
msg: >
|
|
46
|
+
Just published: dbus_list={{ dbus_list('*') }} to topic 'dbus2mqtt/state'
|
|
@@ -12,7 +12,7 @@ Pre-requisites:
|
|
|
12
12
|
Features:
|
|
13
13
|
|
|
14
14
|
* dbus subscription using `org.mpris.MediaPlayer2.*` wildcard to support multiple concurrent MRPIS players
|
|
15
|
-
* Every 5 seconds, the state
|
|
15
|
+
* Every 5 seconds, the state of the `first` known MPRIS player is published to MQTT topic `dbus2mqtt/org.mpris.MediaPlayer2/state`
|
|
16
16
|
* Every MPRIS property update immediately publishes the state to MQTT topic `dbus2mqtt/org.mpris.MediaPlayer2/state`
|
|
17
17
|
* Support for player commands (see below)
|
|
18
18
|
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
# mqtt:
|
|
2
|
-
# host:
|
|
3
|
-
# port:
|
|
4
|
-
|
|
5
1
|
dbus:
|
|
6
2
|
subscriptions:
|
|
7
3
|
|
|
@@ -68,10 +64,13 @@ dbus:
|
|
|
68
64
|
topic: dbus2mqtt/org.mpris.MediaPlayer2/state
|
|
69
65
|
payload_type: json
|
|
70
66
|
payload_template: |
|
|
67
|
+
{% set metadata = player_properties.get('Metadata') or {} %}
|
|
68
|
+
{% set metadata_xesam_url = metadata.get('xesam:url', '') | urldecode %}
|
|
71
69
|
{{
|
|
72
70
|
{ 'bus_name': mpris_bus_name }
|
|
73
71
|
| combine(player_properties)
|
|
74
|
-
| combine
|
|
72
|
+
| combine({ 'Position': seeked_position } if seeked_position else {})
|
|
73
|
+
| combine({ 'Metadata': { 'xesam:url': metadata_xesam_url } }, recursive=True)
|
|
75
74
|
}}
|
|
76
75
|
|
|
77
76
|
- name: "publish local art image"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Flows
|
|
2
2
|
|
|
3
|
-
**dbus2mqtt** allows you to add additional processing logic (flows) for when events occur. Configuration is
|
|
3
|
+
**dbus2mqtt** allows you to add additional processing logic (flows) for when events occur. Configuration is done in yaml and a complete example can be found in [home_assistant_media_player.yaml](https://github.com/jwnmulder/dbus2mqtt/blob/main/docs/examples/home_assistant_media_player.yaml) which is part of the [MPRIS to Home Assistant Media Player integration](https://github.com/jwnmulder/dbus2mqtt/blob/main/docs/examples/home_assistant_media_player.md) example
|
|
4
4
|
|
|
5
5
|
Flows can be defined on a global or dbus subscription level and can be triggered by any of the following events:
|
|
6
6
|
|
|
@@ -9,12 +9,26 @@ Flows can be defined on a global or dbus subscription level and can be triggered
|
|
|
9
9
|
* `object_added` when a new bus_name is registered on dbus
|
|
10
10
|
* `object_removed` when a bus_name is removed from dbus
|
|
11
11
|
|
|
12
|
-
Within each flow a set of actions can be configured. These are executed in order
|
|
12
|
+
Within each flow a set of actions can be configured. These are executed in the order as defined in yaml
|
|
13
13
|
|
|
14
|
+
* `log` for logging message
|
|
14
15
|
* `context_set` to set variables
|
|
15
16
|
* `mqtt_publish` to publish a mqtt message
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
An example
|
|
19
|
+
|
|
20
|
+
```yaml
|
|
21
|
+
flows:
|
|
22
|
+
- name: "Example flow"
|
|
23
|
+
triggers:
|
|
24
|
+
- type: schedule
|
|
25
|
+
interval: {seconds: 5}
|
|
26
|
+
actions:
|
|
27
|
+
- type: log
|
|
28
|
+
msg: hello from example flow
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Some action parameters allow the use of jinja2 templating. dbus2mqtt supports both builtin jinja2 filters and comes with additional filters from [jinja2-ansible-filters](https://pypi.org/project/jinja2-ansible-filters/). When supported, it is documented below.
|
|
18
32
|
|
|
19
33
|
## Flow triggers
|
|
20
34
|
|
|
@@ -22,7 +36,6 @@ Actions support string templating which is based on jinja2
|
|
|
22
36
|
|
|
23
37
|
```yaml
|
|
24
38
|
type: schedule
|
|
25
|
-
cron: {second: 5}
|
|
26
39
|
interval: {seconds: 5}
|
|
27
40
|
```
|
|
28
41
|
|
|
@@ -41,6 +54,12 @@ When triggered, the following context parameters are available
|
|
|
41
54
|
|
|
42
55
|
### dbus_signal
|
|
43
56
|
|
|
57
|
+
```yaml
|
|
58
|
+
type: dbus_signal
|
|
59
|
+
interface: org.freedesktop.DBus.Properties
|
|
60
|
+
signal: PropertiesChanged
|
|
61
|
+
```
|
|
62
|
+
|
|
44
63
|
DBus signals triggers must be configured with an anterface and path. Note that only subscribed signals can be configured as a trigger.
|
|
45
64
|
|
|
46
65
|
| key | description |
|
|
@@ -86,6 +105,19 @@ When triggered, the following context parameters are available
|
|
|
86
105
|
|
|
87
106
|
## Flow actions
|
|
88
107
|
|
|
108
|
+
### log
|
|
109
|
+
|
|
110
|
+
```yaml
|
|
111
|
+
type: log
|
|
112
|
+
msg: your log message
|
|
113
|
+
levvel: INFO
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
| key | type | description |
|
|
117
|
+
|------------------|------------------|--------------|
|
|
118
|
+
| msg | str | a templated string |
|
|
119
|
+
| level | str | One of ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"], defaults to 'INFO' |
|
|
120
|
+
|
|
89
121
|
### context_set
|
|
90
122
|
|
|
91
123
|
```yaml
|
|
@@ -101,8 +133,6 @@ global_context: {}
|
|
|
101
133
|
| dbus_object_context | dict | Per dbus object context, shared between multiple flow executions. Value can be a dict of strings or dict of templated strings |
|
|
102
134
|
| global_context | dict | Global context, shared between multiple flow executions, over all subscriptions. Value can be a dict of strings or dict of templated strings |
|
|
103
135
|
|
|
104
|
-
|
|
105
|
-
|
|
106
136
|
### mqtt_publish
|
|
107
137
|
|
|
108
138
|
```yaml
|
|
@@ -113,11 +143,7 @@ payload_template: {PlaybackStatus: "Off"}
|
|
|
113
143
|
```
|
|
114
144
|
|
|
115
145
|
| key | type | description |
|
|
116
|
-
|
|
146
|
+
|------------------|------------------|--------------|
|
|
117
147
|
| topic | string | mqtt topic the messaage is published to |
|
|
118
148
|
| payload_type | string | any of [json, yaml, text], defaults to json, format the message is published in to mqtt |
|
|
119
149
|
| payload_template | string, dict | value can be a string, a dict of strings, a templated string or a nested dict of templated strings |
|
|
120
|
-
|
|
121
|
-
## Jinja2 based templating
|
|
122
|
-
|
|
123
|
-
Some configuration values allow the use of jinja 2 templating. dbus2mqtt supports both the builtin filters and comes with additional filters from [jinja2-ansible-filters](https://pypi.org/project/jinja2-ansible-filters/)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
|
3
|
+
"extends": ["local>jwnmulder/renovate-config"],
|
|
4
|
+
|
|
5
|
+
"labels": ["dependencies"],
|
|
6
|
+
|
|
7
|
+
"packageRules": [
|
|
8
|
+
{
|
|
9
|
+
"matchJsonata": ["isBreaking"],
|
|
10
|
+
"dependencyDashboardApproval": true
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"matchFileNames": [".pre-commit-config.yaml"],
|
|
14
|
+
"matchUpdateTypes": ["minor", "patch"],
|
|
15
|
+
"automerge": true,
|
|
16
|
+
"addLabels": ["automerge"]
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"description": "Disable Renovate for .python-version",
|
|
20
|
+
"matchFileNames": [".python-version"],
|
|
21
|
+
"enabled": false
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"matchDatasources": ["docker"],
|
|
25
|
+
"matchPackageNames": ["python"],
|
|
26
|
+
"pinDigests": true,
|
|
27
|
+
"separateMinorPatch": true
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"matchDatasources": ["docker"],
|
|
31
|
+
"matchPackageNames": "python",
|
|
32
|
+
"matchUpdateTypes": ["patch", "pin", "digest"],
|
|
33
|
+
"extends": ["schedule:weekly"]
|
|
34
|
+
}
|
|
35
|
+
]
|
|
36
|
+
}
|
|
@@ -107,8 +107,14 @@ class FlowActionMqttPublishConfig:
|
|
|
107
107
|
type: Literal["mqtt_publish"] = "mqtt_publish"
|
|
108
108
|
payload_type: Literal["json", "yaml", "text", "binary"] = "json"
|
|
109
109
|
|
|
110
|
+
@dataclass
|
|
111
|
+
class FlowActionLogConfig:
|
|
112
|
+
msg: str
|
|
113
|
+
type: Literal["log"] = "log"
|
|
114
|
+
level: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] = "INFO"
|
|
115
|
+
|
|
110
116
|
FlowActionConfig = Annotated[
|
|
111
|
-
FlowActionMqttPublishConfig | FlowActionContextSetConfig,
|
|
117
|
+
FlowActionMqttPublishConfig | FlowActionContextSetConfig | FlowActionLogConfig,
|
|
112
118
|
Field(discriminator="type")
|
|
113
119
|
]
|
|
114
120
|
|
|
@@ -157,6 +163,7 @@ class MqttConfig:
|
|
|
157
163
|
username: str
|
|
158
164
|
password: SecretStr
|
|
159
165
|
port: int = 1883
|
|
166
|
+
subscription_topics: list[str] = field(default_factory=lambda: ['dbus2mqtt/#'])
|
|
160
167
|
|
|
161
168
|
@dataclass
|
|
162
169
|
class Config:
|
|
@@ -512,7 +512,7 @@ class DbusClient:
|
|
|
512
512
|
# clean lingering interface messgage handler from bus
|
|
513
513
|
self.bus.remove_message_handler(proxy_interface._message_handler)
|
|
514
514
|
|
|
515
|
-
# For now that InterfacesRemoved signal means the entire object is removed
|
|
515
|
+
# For now that InterfacesRemoved signal means the entire object is removed from D-Bus
|
|
516
516
|
del self.subscriptions[bus_name].path_objects[path]
|
|
517
517
|
|
|
518
518
|
# cleanup the entire BusNameSubscriptions if no more objects are subscribed
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
|
|
2
|
+
import logging
|
|
3
|
+
|
|
4
|
+
from jinja2.exceptions import TemplateError
|
|
5
|
+
|
|
6
|
+
from dbus2mqtt import AppContext
|
|
7
|
+
from dbus2mqtt.config import FlowActionLogConfig
|
|
8
|
+
from dbus2mqtt.flow import FlowAction, FlowExecutionContext
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
class LogAction(FlowAction):
|
|
13
|
+
|
|
14
|
+
def __init__(self, config: FlowActionLogConfig, app_context: AppContext):
|
|
15
|
+
self.config = config
|
|
16
|
+
self.templating = app_context.templating
|
|
17
|
+
|
|
18
|
+
async def execute(self, context: FlowExecutionContext):
|
|
19
|
+
|
|
20
|
+
render_context = context.get_aggregated_context()
|
|
21
|
+
|
|
22
|
+
log_msg = self.config.msg
|
|
23
|
+
log_level = logging._nameToLevel.get(self.config.level.upper(), logging.INFO)
|
|
24
|
+
|
|
25
|
+
try:
|
|
26
|
+
log_msg = await self.templating.async_render_template(
|
|
27
|
+
templatable=self.config.msg,
|
|
28
|
+
context=render_context,
|
|
29
|
+
res_type=str
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
except TemplateError as e:
|
|
33
|
+
logger.warning(f"Error rendering jinja template, flow: '{context.name or ''}', msg={e}, msg={self.config.msg}, render_context={render_context}", exc_info=True)
|
|
34
|
+
return
|
|
35
|
+
|
|
36
|
+
logger.log(level=log_level, msg=log_msg)
|
|
@@ -17,6 +17,7 @@ from dbus2mqtt.config import (
|
|
|
17
17
|
from dbus2mqtt.event_broker import FlowTriggerMessage
|
|
18
18
|
from dbus2mqtt.flow import FlowAction, FlowExecutionContext
|
|
19
19
|
from dbus2mqtt.flow.actions.context_set import ContextSetAction
|
|
20
|
+
from dbus2mqtt.flow.actions.log_action import LogAction
|
|
20
21
|
from dbus2mqtt.flow.actions.mqtt_publish import MqttPublishAction
|
|
21
22
|
|
|
22
23
|
logger = logging.getLogger(__name__)
|
|
@@ -102,8 +103,11 @@ class FlowActionContext:
|
|
|
102
103
|
action = None
|
|
103
104
|
if action_config.type == "context_set":
|
|
104
105
|
action = ContextSetAction(action_config, self.app_context)
|
|
105
|
-
|
|
106
|
+
elif action_config.type == "mqtt_publish":
|
|
106
107
|
action = MqttPublishAction(action_config, self.app_context)
|
|
108
|
+
elif action_config.type == "log":
|
|
109
|
+
action = LogAction(action_config, self.app_context)
|
|
110
|
+
|
|
107
111
|
if action:
|
|
108
112
|
res.append(action)
|
|
109
113
|
|
|
@@ -13,6 +13,8 @@ import paho.mqtt.client as mqtt
|
|
|
13
13
|
import yaml
|
|
14
14
|
|
|
15
15
|
from paho.mqtt.enums import CallbackAPIVersion
|
|
16
|
+
from paho.mqtt.packettypes import PacketTypes
|
|
17
|
+
from paho.mqtt.properties import Properties
|
|
16
18
|
from paho.mqtt.subscribeoptions import SubscribeOptions
|
|
17
19
|
|
|
18
20
|
from dbus2mqtt import AppContext
|
|
@@ -27,8 +29,11 @@ class MqttClient:
|
|
|
27
29
|
self.event_broker = app_context.event_broker
|
|
28
30
|
|
|
29
31
|
unique_client_id_postfix = ''.join(random.choices(string.ascii_lowercase + string.digits, k=6))
|
|
32
|
+
self.client_id_prefix = "dbus2mqtt-"
|
|
33
|
+
self.client_id = f"{self.client_id_prefix}{unique_client_id_postfix}"
|
|
34
|
+
|
|
30
35
|
self.client = mqtt.Client(
|
|
31
|
-
client_id=
|
|
36
|
+
client_id=self.client_id,
|
|
32
37
|
protocol=mqtt.MQTTv5,
|
|
33
38
|
callback_api_version=CallbackAPIVersion.VERSION2
|
|
34
39
|
)
|
|
@@ -84,7 +89,16 @@ class MqttClient:
|
|
|
84
89
|
if first_message:
|
|
85
90
|
await asyncio.wait_for(self.connected_event.wait(), timeout=5)
|
|
86
91
|
|
|
87
|
-
|
|
92
|
+
publish_properties = Properties(PacketTypes.PUBLISH)
|
|
93
|
+
publish_properties.UserProperty = ("client_id", self.client_id)
|
|
94
|
+
|
|
95
|
+
publish_info = self.client.publish(
|
|
96
|
+
topic=msg.topic,
|
|
97
|
+
payload=payload or "",
|
|
98
|
+
properties=publish_properties
|
|
99
|
+
)
|
|
100
|
+
publish_info.wait_for_publish(timeout=1000)
|
|
101
|
+
|
|
88
102
|
if first_message:
|
|
89
103
|
logger.info(f"First message published: topic={msg.topic}, payload={payload_log_msg}")
|
|
90
104
|
first_message = False
|
|
@@ -100,22 +114,29 @@ class MqttClient:
|
|
|
100
114
|
logger.warning(f"on_connect: Failed to connect: {reason_code}. Will retry connection")
|
|
101
115
|
else:
|
|
102
116
|
logger.info(f"on_connect: Connected to {self.config.host}:{self.config.port}")
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
client.subscribe("dbus2mqtt/#", options=SubscribeOptions(noLocal=True))
|
|
117
|
+
|
|
118
|
+
subscriptions = [(t, SubscribeOptions(noLocal=True)) for t in self.config.subscription_topics]
|
|
119
|
+
client.subscribe(subscriptions)
|
|
107
120
|
|
|
108
121
|
self.loop.call_soon_threadsafe(self.connected_event.set)
|
|
109
122
|
|
|
110
123
|
def on_message(self, client: mqtt.Client, userdata: Any, msg: mqtt.MQTTMessage):
|
|
111
124
|
|
|
112
|
-
#
|
|
113
|
-
|
|
125
|
+
# Skip retained messages
|
|
114
126
|
payload = msg.payload.decode()
|
|
115
127
|
if msg.retain:
|
|
116
128
|
logger.info(f"on_message: skipping msg with retain=True, topic={msg.topic}, payload={payload}")
|
|
117
129
|
return
|
|
118
130
|
|
|
131
|
+
# Skip messages being sent by other dbus2mqtt clients
|
|
132
|
+
if msg.properties:
|
|
133
|
+
user_properties: list[tuple[str, object]] = getattr(msg.properties, "UserProperty", [])
|
|
134
|
+
client_id = next((str(v) for k, v in user_properties if k == "client_id"), None)
|
|
135
|
+
if client_id and client_id != self.client_id:
|
|
136
|
+
logger.info(f"on_message: skipping msg from another dbus2mqtt client, topic={msg.topic}, client_id={client_id}")
|
|
137
|
+
if client_id and client_id.startswith(self.client_id_prefix):
|
|
138
|
+
return
|
|
139
|
+
|
|
119
140
|
try:
|
|
120
141
|
json_payload = json.loads(payload) if payload else {}
|
|
121
142
|
logger.debug(f"on_message: msg.topic={msg.topic}, msg.payload={json.dumps(json_payload)}")
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import urllib.parse
|
|
1
2
|
|
|
2
3
|
from datetime import datetime
|
|
3
4
|
from typing import Any, TypeVar
|
|
@@ -7,11 +8,18 @@ from jinja2.nativetypes import NativeEnvironment
|
|
|
7
8
|
|
|
8
9
|
TemplateResultType = TypeVar('TemplateResultType')
|
|
9
10
|
|
|
11
|
+
def urldecode(string):
|
|
12
|
+
return urllib.parse.unquote(string)
|
|
13
|
+
|
|
10
14
|
class TemplateEngine:
|
|
11
15
|
def __init__(self):
|
|
12
16
|
|
|
13
17
|
engine_globals = {}
|
|
14
18
|
engine_globals['now'] = datetime.now
|
|
19
|
+
engine_globals['urldecode'] = urldecode
|
|
20
|
+
|
|
21
|
+
engine_filters = {}
|
|
22
|
+
engine_filters['urldecode'] = urldecode
|
|
15
23
|
|
|
16
24
|
self.jinja2_env = NativeEnvironment(
|
|
17
25
|
loader=BaseLoader(),
|
|
@@ -32,6 +40,9 @@ class TemplateEngine:
|
|
|
32
40
|
self.jinja2_env.globals.update(engine_globals)
|
|
33
41
|
self.jinja2_async_env.globals.update(engine_globals)
|
|
34
42
|
|
|
43
|
+
self.jinja2_env.filters.update(engine_filters)
|
|
44
|
+
self.jinja2_async_env.filters.update(engine_filters)
|
|
45
|
+
|
|
35
46
|
def add_functions(self, custom_functions: dict[str, Any]):
|
|
36
47
|
self.jinja2_env.globals.update(custom_functions)
|
|
37
48
|
self.jinja2_async_env.globals.update(custom_functions)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from dbus2mqtt.config import (
|
|
6
|
+
FlowActionLogConfig,
|
|
7
|
+
FlowTriggerScheduleConfig,
|
|
8
|
+
)
|
|
9
|
+
from dbus2mqtt.flow.flow_processor import FlowTriggerMessage
|
|
10
|
+
from tests import mocked_app_context, mocked_flow_processor
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@pytest.mark.asyncio
|
|
14
|
+
async def test_context():
|
|
15
|
+
|
|
16
|
+
app_context = mocked_app_context()
|
|
17
|
+
|
|
18
|
+
trigger_config = FlowTriggerScheduleConfig()
|
|
19
|
+
processor, flow_config = mocked_flow_processor(app_context, trigger_config, actions=[
|
|
20
|
+
FlowActionLogConfig(
|
|
21
|
+
msg="{{ 'templated-test-str' }}",
|
|
22
|
+
level="INFO"
|
|
23
|
+
)
|
|
24
|
+
])
|
|
25
|
+
|
|
26
|
+
await processor._process_flow_trigger(
|
|
27
|
+
FlowTriggerMessage(flow_config, trigger_config, datetime.now())
|
|
28
|
+
)
|
dbus2mqtt-0.4.1/renovate.json
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
|
3
|
-
"extends": [
|
|
4
|
-
"local>jwnmulder/renovate-config"
|
|
5
|
-
],
|
|
6
|
-
|
|
7
|
-
"labels": ["dependencies"],
|
|
8
|
-
|
|
9
|
-
"packageRules": [
|
|
10
|
-
{
|
|
11
|
-
"matchFileNames": [".pre-commit-config.yaml"],
|
|
12
|
-
"matchUpdateTypes": ["minor", "patch"],
|
|
13
|
-
"automerge": true,
|
|
14
|
-
"addLabels": ["automerge"]
|
|
15
|
-
},
|
|
16
|
-
{
|
|
17
|
-
"description": "Disable Renovate for .python-version",
|
|
18
|
-
"matchFileNames": [".python-version"],
|
|
19
|
-
"enabled": false
|
|
20
|
-
}
|
|
21
|
-
]
|
|
22
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/src/dbus2mqtt/dbus/introspection_patches/mpris_playerctl.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dbus2mqtt-0.4.1 → dbus2mqtt-0.4.2}/tests/config/fixtures/payload_template_jinja_expressions.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|