dbus2mqtt 0.4.1__py3-none-any.whl → 0.4.2__py3-none-any.whl
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/config/__init__.py +8 -1
- dbus2mqtt/dbus/dbus_client.py +1 -1
- dbus2mqtt/flow/actions/log_action.py +36 -0
- dbus2mqtt/flow/flow_processor.py +5 -1
- dbus2mqtt/mqtt/mqtt_client.py +29 -8
- dbus2mqtt/template/templating.py +11 -0
- {dbus2mqtt-0.4.1.dist-info → dbus2mqtt-0.4.2.dist-info}/METADATA +6 -4
- {dbus2mqtt-0.4.1.dist-info → dbus2mqtt-0.4.2.dist-info}/RECORD +11 -10
- {dbus2mqtt-0.4.1.dist-info → dbus2mqtt-0.4.2.dist-info}/WHEEL +0 -0
- {dbus2mqtt-0.4.1.dist-info → dbus2mqtt-0.4.2.dist-info}/entry_points.txt +0 -0
- {dbus2mqtt-0.4.1.dist-info → dbus2mqtt-0.4.2.dist-info}/licenses/LICENSE +0 -0
dbus2mqtt/config/__init__.py
CHANGED
|
@@ -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:
|
dbus2mqtt/dbus/dbus_client.py
CHANGED
|
@@ -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)
|
dbus2mqtt/flow/flow_processor.py
CHANGED
|
@@ -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
|
|
dbus2mqtt/mqtt/mqtt_client.py
CHANGED
|
@@ -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)}")
|
dbus2mqtt/template/templating.py
CHANGED
|
@@ -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)
|
|
@@ -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
|
|
|
@@ -2,22 +2,23 @@ dbus2mqtt/__init__.py,sha256=VunubKEH4_lne9Ttd2YRpyXjZMIAzyD2eiJ2sfvvTFU,362
|
|
|
2
2
|
dbus2mqtt/__main__.py,sha256=NAoa3nwgBSQI22eWzzRx61SIDThDwXmUofWWZU3_4-Q,71
|
|
3
3
|
dbus2mqtt/event_broker.py,sha256=Hp5yurhP8FkAO-y0l2grygHxR2e37ZQ7QScjcQDA2UU,1334
|
|
4
4
|
dbus2mqtt/main.py,sha256=Kr2LRVxWcPDtNwCj8Eqz9TxtGLAVrV4q0nizKh1pLXc,4539
|
|
5
|
-
dbus2mqtt/config/__init__.py,sha256=
|
|
5
|
+
dbus2mqtt/config/__init__.py,sha256=947_dLVt8qq7P3p15jGIy5Vf1jUUMGrh1xr_DVhZclQ,5372
|
|
6
6
|
dbus2mqtt/config/jsonarparse.py,sha256=VJGFeyQJcOE6bRXlSRr3FClvN_HnmiIlEGmOgNM0oCc,1214
|
|
7
|
-
dbus2mqtt/dbus/dbus_client.py,sha256=
|
|
7
|
+
dbus2mqtt/dbus/dbus_client.py,sha256=WHsmOiaJ5SY6zk-C99m83MEpycnUyGpsYmGopJJbPE8,39690
|
|
8
8
|
dbus2mqtt/dbus/dbus_types.py,sha256=NmPD9um499e49Pk8DWH4IrIPQh1BinHYQgoXllCNiDw,777
|
|
9
9
|
dbus2mqtt/dbus/dbus_util.py,sha256=h-1Y8Mvz9bj9X7mPZ8LghkvXDrujdJHK0__AOW373hE,697
|
|
10
10
|
dbus2mqtt/dbus/introspection_patches/mpris_playerctl.py,sha256=q93d_Yp93u3Y-9q0dRdKW5hrij9GK3CFqKhUWVE8uw4,5883
|
|
11
11
|
dbus2mqtt/dbus/introspection_patches/mpris_vlc.py,sha256=Cf-o-05W6gUoKpcYR7n0dRi-CrbeASPTwkyEzZGnU3Y,4241
|
|
12
12
|
dbus2mqtt/flow/__init__.py,sha256=tAL-CjXQHq_tGTKctIdOZ5teVKBtcJs6Astq_RdruV8,1540
|
|
13
|
-
dbus2mqtt/flow/flow_processor.py,sha256
|
|
13
|
+
dbus2mqtt/flow/flow_processor.py,sha256=N-btGap1wqnM4zKyulH_5KQhGi0IRlsK2cHrrnomMQQ,8922
|
|
14
14
|
dbus2mqtt/flow/actions/context_set.py,sha256=dIT39MJJVb0wuRI_ZM3ssnXYfa-iyB4o_UZD-1BZL2g,1087
|
|
15
|
+
dbus2mqtt/flow/actions/log_action.py,sha256=2_-YEKkX5kvFzK6x4v-Hx3u2PEM8fip_4buMg_ij-oI,1156
|
|
15
16
|
dbus2mqtt/flow/actions/mqtt_publish.py,sha256=psNkTvaR3JZwAwpM4AqiZTDnA5UQX9r4CUZ1LA7iRW4,2366
|
|
16
|
-
dbus2mqtt/mqtt/mqtt_client.py,sha256=
|
|
17
|
+
dbus2mqtt/mqtt/mqtt_client.py,sha256=P6rxVNA2M_wxhI3RcHpvayEEmcUQGGDG6hkLmjiqY1w,6056
|
|
17
18
|
dbus2mqtt/template/dbus_template_functions.py,sha256=UEoXK2PqDKF6jR4vTFHQwq58f5APnOJr7B1_I1zW8yM,2449
|
|
18
|
-
dbus2mqtt/template/templating.py,sha256=
|
|
19
|
-
dbus2mqtt-0.4.
|
|
20
|
-
dbus2mqtt-0.4.
|
|
21
|
-
dbus2mqtt-0.4.
|
|
22
|
-
dbus2mqtt-0.4.
|
|
23
|
-
dbus2mqtt-0.4.
|
|
19
|
+
dbus2mqtt/template/templating.py,sha256=YzE6-pBoATrV7nXkgxSiLlbxgbC65-2wGiFPHgIDd9g,4470
|
|
20
|
+
dbus2mqtt-0.4.2.dist-info/METADATA,sha256=K8XT049Ryv76ssq7GeUYSRjeZbsWLYSvVoOHrA1bfeY,8105
|
|
21
|
+
dbus2mqtt-0.4.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
22
|
+
dbus2mqtt-0.4.2.dist-info/entry_points.txt,sha256=pmmacoHCsvTTUB5dIPaY4i0H9gX7BQlpd3rBU-Jbv3A,50
|
|
23
|
+
dbus2mqtt-0.4.2.dist-info/licenses/LICENSE,sha256=a4bIEgyA9rrnAfUN90CgbgZ6BQIFHeABkk0JihiBaxM,1074
|
|
24
|
+
dbus2mqtt-0.4.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|