dbus2mqtt 0.3.1__py3-none-any.whl → 0.4.1__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.

@@ -1,23 +1,37 @@
1
1
 
2
2
 
3
3
  from dataclasses import dataclass
4
+ from typing import Any
4
5
 
5
6
  import dbus_fast.aio as dbus_aio
6
7
 
7
- from dbus2mqtt.config import InterfaceConfig, SubscriptionConfig
8
+ from dbus2mqtt.config import (
9
+ SignalConfig,
10
+ SubscriptionConfig,
11
+ )
8
12
 
9
13
 
10
14
  class BusNameSubscriptions:
11
15
 
12
- def __init__(self, bus_name: str):
16
+ def __init__(self, bus_name: str, unique_name: str):
13
17
  self.bus_name = bus_name
18
+ self.unique_name = unique_name
14
19
  self.path_objects: dict[str, dbus_aio.proxy_object.ProxyObject] = {}
15
20
 
16
21
  @dataclass
17
22
  class SubscribedInterface:
18
23
 
19
- interface_config: InterfaceConfig
24
+ # interface_config: InterfaceConfig
20
25
  subscription_config: SubscriptionConfig
21
26
  bus_name: str
22
27
  path: str
23
28
  interface_name: str
29
+
30
+ @dataclass
31
+ class DbusSignalWithState:
32
+ bus_name: str
33
+ path: str
34
+ interface_name: str
35
+ subscription_config: SubscriptionConfig
36
+ signal_config: SignalConfig
37
+ args: list[Any]
@@ -1,19 +1,20 @@
1
- import json
1
+ import base64
2
2
  import re
3
3
 
4
4
  import dbus_fast.signature as dbus_signature
5
5
 
6
6
 
7
- def _variant_serializer(obj):
8
- if isinstance(obj, dbus_signature.Variant):
9
- return obj.value
10
- return obj
11
-
12
- def unwrap_dbus_object(o):
13
- # an easy way to get rid of dbus_fast.signature.Variant types
14
- res = json.dumps(o, default=_variant_serializer)
15
- json_obj = json.loads(res)
16
- return json_obj
7
+ def unwrap_dbus_object(obj):
8
+ if isinstance(obj, dict):
9
+ return {k: unwrap_dbus_object(v) for k, v in obj.items()}
10
+ elif isinstance(obj, list | tuple | set):
11
+ return type(obj)(unwrap_dbus_object(i) for i in obj)
12
+ elif isinstance(obj, dbus_signature.Variant):
13
+ return unwrap_dbus_object(obj.value)
14
+ elif isinstance(obj, bytes):
15
+ return base64.b64encode(obj).decode('utf-8')
16
+ else:
17
+ return obj
17
18
 
18
19
  def unwrap_dbus_objects(args):
19
20
  res = [unwrap_dbus_object(o) for o in args]
dbus2mqtt/event_broker.py CHANGED
@@ -7,12 +7,7 @@ from typing import Any
7
7
 
8
8
  import janus
9
9
 
10
- from dbus2mqtt.config import (
11
- FlowConfig,
12
- FlowTriggerConfig,
13
- SignalConfig,
14
- SubscriptionConfig,
15
- )
10
+ from dbus2mqtt.config import FlowConfig, FlowTriggerConfig
16
11
 
17
12
  logger = logging.getLogger(__name__)
18
13
 
@@ -23,15 +18,6 @@ class MqttMessage:
23
18
  payload: Any
24
19
  payload_serialization_type: str = "json"
25
20
 
26
- @dataclass
27
- class DbusSignalWithState:
28
- bus_name: str
29
- path: str
30
- interface_name: str
31
- subscription_config: SubscriptionConfig
32
- signal_config: SignalConfig
33
- args: list[Any]
34
-
35
21
  @dataclass
36
22
  class FlowTriggerMessage:
37
23
  flow_config: FlowConfig
@@ -43,7 +29,6 @@ class EventBroker:
43
29
  def __init__(self):
44
30
  self.mqtt_receive_queue = janus.Queue[MqttMessage]()
45
31
  self.mqtt_publish_queue = janus.Queue[MqttMessage]()
46
- self.dbus_signal_queue = janus.Queue[DbusSignalWithState]()
47
32
  self.flow_trigger_queue = janus.Queue[FlowTriggerMessage]()
48
33
  # self.dbus_send_queue: janus.Queue
49
34
 
@@ -51,7 +36,6 @@ class EventBroker:
51
36
  await asyncio.gather(
52
37
  self.mqtt_receive_queue.aclose(),
53
38
  self.mqtt_publish_queue.aclose(),
54
- self.dbus_signal_queue.aclose(),
55
39
  self.flow_trigger_queue.aclose(),
56
40
  return_exceptions=True
57
41
  )
@@ -63,7 +47,3 @@ class EventBroker:
63
47
  async def publish_to_mqtt(self, msg: MqttMessage):
64
48
  # logger.debug("publish_to_mqtt")
65
49
  await self.mqtt_publish_queue.async_q.put(msg)
66
-
67
- def on_dbus_signal(self, signal: DbusSignalWithState):
68
- # logger.debug("on_dbus_signal")
69
- self.dbus_signal_queue.sync_q.put(signal)
@@ -7,7 +7,13 @@ from typing import Any
7
7
  from apscheduler.schedulers.asyncio import AsyncIOScheduler
8
8
 
9
9
  from dbus2mqtt import AppContext
10
- from dbus2mqtt.config import FlowConfig, FlowTriggerConfig, FlowTriggerDbusSignalConfig
10
+ from dbus2mqtt.config import (
11
+ FlowConfig,
12
+ FlowTriggerConfig,
13
+ FlowTriggerDbusSignalConfig,
14
+ FlowTriggerObjectAddedConfig,
15
+ FlowTriggerObjectRemovedConfig,
16
+ )
11
17
  from dbus2mqtt.event_broker import FlowTriggerMessage
12
18
  from dbus2mqtt.flow import FlowAction, FlowExecutionContext
13
19
  from dbus2mqtt.flow.actions.context_set import ContextSetAction
@@ -103,7 +109,7 @@ class FlowActionContext:
103
109
 
104
110
  return res
105
111
 
106
- async def execute_actions(self, trigger_context: dict[str, Any] | None):
112
+ async def execute_actions(self, trigger_type: str, trigger_context: dict[str, Any] | None):
107
113
 
108
114
  # per flow execution context
109
115
  context = FlowExecutionContext(
@@ -111,6 +117,8 @@ class FlowActionContext:
111
117
  global_flows_context=self.global_flows_context,
112
118
  flow_context=self.flow_context)
113
119
 
120
+ context.context["trigger_type"] = trigger_type
121
+
114
122
  if trigger_context:
115
123
  context.context.update(trigger_context)
116
124
 
@@ -176,14 +184,20 @@ class FlowProcessor:
176
184
  finally:
177
185
  self.event_broker.flow_trigger_queue.async_q.task_done()
178
186
 
179
- def _trigger_config_to_str(self, config: FlowTriggerConfig) -> str:
187
+ def _trigger_config_to_str(self, msg: FlowTriggerMessage) -> str:
188
+ config = msg.flow_trigger_config
180
189
  if isinstance(config, FlowTriggerDbusSignalConfig):
181
190
  return f"{config.type}({config.signal})"
191
+ elif isinstance(config, FlowTriggerObjectAddedConfig) or isinstance(config, FlowTriggerObjectRemovedConfig):
192
+ path = msg.trigger_context.get('path') if msg.trigger_context else None
193
+ if path:
194
+ return f"{config.type}({path})"
182
195
  return config.type
183
196
 
184
197
  async def _process_flow_trigger(self, flow_trigger_message: FlowTriggerMessage):
185
198
 
186
- trigger_str = self._trigger_config_to_str(flow_trigger_message.flow_trigger_config)
199
+ trigger_type = flow_trigger_message.flow_trigger_config.type
200
+ trigger_str = self._trigger_config_to_str(flow_trigger_message)
187
201
  flow_str = flow_trigger_message.flow_config.name or flow_trigger_message.flow_config.id
188
202
 
189
203
  log_message = f"on_trigger: {trigger_str}, flow={flow_str}, time={flow_trigger_message.timestamp.isoformat()}"
@@ -196,4 +210,4 @@ class FlowProcessor:
196
210
  flow_id = flow_trigger_message.flow_config.id
197
211
 
198
212
  flow = self._flows[flow_id]
199
- await flow.execute_actions(trigger_context=flow_trigger_message.trigger_context)
213
+ await flow.execute_actions(trigger_type, trigger_context=flow_trigger_message.trigger_context)
dbus2mqtt/main.py CHANGED
@@ -8,6 +8,8 @@ import colorlog
8
8
  import dbus_fast.aio as dbus_aio
9
9
  import dotenv
10
10
 
11
+ from dbus_fast import BusType
12
+
11
13
  from dbus2mqtt import AppContext
12
14
  from dbus2mqtt.config import Config
13
15
  from dbus2mqtt.config.jsonarparse import new_argument_parser
@@ -23,7 +25,8 @@ logger = logging.getLogger(__name__)
23
25
 
24
26
  async def dbus_processor_task(app_context: AppContext, flow_scheduler: FlowScheduler):
25
27
 
26
- bus = dbus_aio.message_bus.MessageBus()
28
+ bus_type = BusType.SYSTEM if app_context.config.dbus.bus_type == "SYSTEM" else BusType.SESSION
29
+ bus = dbus_aio.message_bus.MessageBus(bus_type=bus_type)
27
30
 
28
31
  dbus_client = DbusClient(app_context, bus, flow_scheduler)
29
32
  app_context.templating.add_functions(jinja_custom_dbus_functions(dbus_client))
@@ -36,7 +39,8 @@ async def dbus_processor_task(app_context: AppContext, flow_scheduler: FlowSched
36
39
  await asyncio.gather(
37
40
  dbus_client_run_future,
38
41
  asyncio.create_task(dbus_client.dbus_signal_queue_processor_task()),
39
- asyncio.create_task(dbus_client.mqtt_receive_queue_processor_task())
42
+ asyncio.create_task(dbus_client.mqtt_receive_queue_processor_task()),
43
+ asyncio.create_task(dbus_client.dbus_object_lifecycle_signal_processor_task())
40
44
  )
41
45
 
42
46
  async def mqtt_processor_task(app_context: AppContext):
@@ -103,9 +107,19 @@ def main():
103
107
 
104
108
  config: Config = cast(Config, parser.instantiate_classes(cfg))
105
109
 
110
+ class NamePartsFilter(logging.Filter):
111
+ def filter(self, record):
112
+ record.name_last = record.name.rsplit('.', 1)[-1]
113
+ # record.name_first = record.name.split('.', 1)[0]
114
+ # record.name_short = record.name
115
+ # if record.name.startswith("dbus2mqtt"):
116
+ # record.name_short = record.name.split('.', 1)[-1]
117
+ return True
118
+
106
119
  handler = colorlog.StreamHandler(stream=sys.stdout)
120
+ handler.addFilter(NamePartsFilter())
107
121
  handler.setFormatter(colorlog.ColoredFormatter(
108
- '%(log_color)s%(levelname)s:%(name)s:%(message)s',
122
+ '%(log_color)s%(levelname)s:%(name_last)s:%(message)s',
109
123
  log_colors={
110
124
  "DEBUG": "light_black",
111
125
  "WARNING": "yellow",
@@ -2,6 +2,8 @@
2
2
  import asyncio
3
3
  import json
4
4
  import logging
5
+ import random
6
+ import string
5
7
 
6
8
  from typing import Any
7
9
  from urllib.parse import ParseResult
@@ -24,7 +26,9 @@ class MqttClient:
24
26
  self.config = app_context.config.mqtt
25
27
  self.event_broker = app_context.event_broker
26
28
 
29
+ unique_client_id_postfix = ''.join(random.choices(string.ascii_lowercase + string.digits, k=6))
27
30
  self.client = mqtt.Client(
31
+ client_id=f"dbus2mqtt-client-{unique_client_id_postfix}",
28
32
  protocol=mqtt.MQTTv5,
29
33
  callback_api_version=CallbackAPIVersion.VERSION2
30
34
  )
@@ -42,10 +46,10 @@ class MqttClient:
42
46
 
43
47
  def connect(self):
44
48
 
45
- # mqtt_client.on_message = lambda client, userdata, message: asyncio.create_task(mqtt_on_message(client, userdata, message))
46
49
  self.client.connect_async(
47
50
  host=self.config.host,
48
- port=self.config.port
51
+ port=self.config.port,
52
+ clean_start=mqtt.MQTT_CLEAN_START_FIRST_ONLY
49
53
  )
50
54
 
51
55
  async def mqtt_publish_queue_processor_task(self):
@@ -98,19 +102,22 @@ class MqttClient:
98
102
  logger.info(f"on_connect: Connected to {self.config.host}:{self.config.port}")
99
103
  # Subscribing in on_connect() means that if we lose the connection and
100
104
  # reconnect then subscriptions will be renewed.
105
+ # TODO: Determine topics based on config
101
106
  client.subscribe("dbus2mqtt/#", options=SubscribeOptions(noLocal=True))
102
107
 
103
108
  self.loop.call_soon_threadsafe(self.connected_event.set)
104
109
 
105
110
  def on_message(self, client: mqtt.Client, userdata: Any, msg: mqtt.MQTTMessage):
106
111
 
112
+ # TODO: Skip messages being sent by other dbus2mqtt clients
113
+
107
114
  payload = msg.payload.decode()
108
115
  if msg.retain:
109
116
  logger.info(f"on_message: skipping msg with retain=True, topic={msg.topic}, payload={payload}")
110
117
  return
111
118
 
112
119
  try:
113
- json_payload = json.loads(payload)
120
+ json_payload = json.loads(payload) if payload else {}
114
121
  logger.debug(f"on_message: msg.topic={msg.topic}, msg.payload={json.dumps(json_payload)}")
115
122
  self.event_broker.on_mqtt_receive(MqttMessage(msg.topic, json_payload))
116
123
  except json.JSONDecodeError as e:
@@ -32,7 +32,7 @@ class DbusContext:
32
32
  # Pylance will mentiod this line is unreachable. It is not as jinja2 can pass in any type
33
33
  raise ValueError("method_args must be a list")
34
34
 
35
- proxy_object = self.dbus_client.get_proxy_object(bus_name, path)
35
+ proxy_object = self.dbus_client.get_subscribed_proxy_object(bus_name, path)
36
36
  if not proxy_object:
37
37
  raise ValueError(f"No matching subscription found for bus_name: {bus_name}, path: {path}")
38
38
 
@@ -42,7 +42,7 @@ class DbusContext:
42
42
 
43
43
  async def async_dbus_property_get_fn(self, bus_name: str, path: str, interface: str, property:str, default_unsupported: Any = None):
44
44
 
45
- proxy_object = self.dbus_client.get_proxy_object(bus_name, path)
45
+ proxy_object = self.dbus_client.get_subscribed_proxy_object(bus_name, path)
46
46
  if not proxy_object:
47
47
  raise ValueError(f"No matching subscription found for bus_name: {bus_name}, path: {path}")
48
48
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dbus2mqtt
3
- Version: 0.3.1
3
+ Version: 0.4.1
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
@@ -53,7 +53,7 @@ Initial testing has focused on MPRIS integration. A table of tested MPRIS player
53
53
 
54
54
  ## Getting started with dbus2mqtt
55
55
 
56
- Create a `config.yaml` file with the contents shown below. This configuration will expose all bus properties from the `org.mpris.MediaPlayer2.Player` interface to MQTT on the `dbus2mqtt/org.mpris.MediaPlayer2/state` topic. Have a look at [docs/examples](docs/examples.md) for more examples
56
+ Create a `config.yaml` file with the contents shown below. This configuration will expose all bus properties from the `org.mpris.MediaPlayer2.Player` interface to MQTT on the `dbus2mqtt/org.mpris.MediaPlayer2/state` topic. Have a look at [docs/examples](https://github.com/jwnmulder/dbus2mqtt/blob/main/docs/examples.md) for more examples
57
57
 
58
58
  ```yaml
59
59
  dbus:
@@ -68,7 +68,7 @@ dbus:
68
68
  flows:
69
69
  - name: "Publish MPRIS state"
70
70
  triggers:
71
- - type: bus_name_added
71
+ - type: object_added
72
72
  - type: schedule
73
73
  interval: {seconds: 5}
74
74
  actions:
@@ -111,8 +111,8 @@ cp docs/examples/home_assistant_media_player.yaml $HOME/.config/dbus2mqtt/config
111
111
  cp .env.example $HOME/.config/dbus2mqtt/.env
112
112
 
113
113
  # run image and automatically start on reboot
114
- docker pull jwnmulder/dbus2mqtt
115
- docker run --detach --name dbus2mqtt \
114
+ sudo docker pull jwnmulder/dbus2mqtt
115
+ sudo docker run --detach --name dbus2mqtt \
116
116
  --volume "$HOME"/.config/dbus2mqtt:"$HOME"/.config/dbus2mqtt \
117
117
  --volume /run/user:/run/user \
118
118
  --env DBUS_SESSION_BUS_ADDRESS="$DBUS_SESSION_BUS_ADDRESS" \
@@ -173,21 +173,31 @@ dbus:
173
173
 
174
174
  This configuration will expose 2 methods. Triggering methods can be done by publishing json messages to the `dbus2mqtt/org.mpris.MediaPlayer2/command` MQTT topic. Arguments can be passed along in `args`.
175
175
 
176
- Note that methods are called on **all** bus_names matching the configured pattern
176
+ Some examples that call methods on **all** bus_names matching the configured pattern
177
177
 
178
178
  ```json
179
179
  {
180
- "method" : "Play",
180
+ "method": "Play",
181
181
  }
182
182
  ```
183
183
 
184
184
  ```json
185
185
  {
186
- "method" : "OpenUri",
186
+ "method": "OpenUri",
187
187
  "args": []
188
188
  }
189
189
  ```
190
190
 
191
+ To specifically target objects the properties `bus_name` and/or `path` can be used. Both properties support wildcards
192
+
193
+ ```json
194
+ {
195
+ "method": "Play",
196
+ "bus_name": "*.firefox",
197
+ "path": "/org/mpris/MediaPlayer2"
198
+ }
199
+ ```
200
+
191
201
  ### Exposing dbus signals
192
202
 
193
203
  Publishing signals to MQTT topics works by subscribing to the relevant signal and using flows for publishing
@@ -0,0 +1,23 @@
1
+ dbus2mqtt/__init__.py,sha256=VunubKEH4_lne9Ttd2YRpyXjZMIAzyD2eiJ2sfvvTFU,362
2
+ dbus2mqtt/__main__.py,sha256=NAoa3nwgBSQI22eWzzRx61SIDThDwXmUofWWZU3_4-Q,71
3
+ dbus2mqtt/event_broker.py,sha256=Hp5yurhP8FkAO-y0l2grygHxR2e37ZQ7QScjcQDA2UU,1334
4
+ dbus2mqtt/main.py,sha256=Kr2LRVxWcPDtNwCj8Eqz9TxtGLAVrV4q0nizKh1pLXc,4539
5
+ dbus2mqtt/config/__init__.py,sha256=LXQg2cZ_vMvhAl7_cC6G3gxCaLCq9uaTfZqw7OEXkPQ,5104
6
+ dbus2mqtt/config/jsonarparse.py,sha256=VJGFeyQJcOE6bRXlSRr3FClvN_HnmiIlEGmOgNM0oCc,1214
7
+ dbus2mqtt/dbus/dbus_client.py,sha256=zWz9V0lbGzbb3AifqWrwkOaC9OdZtQbfHhkSSJfXMi8,39690
8
+ dbus2mqtt/dbus/dbus_types.py,sha256=NmPD9um499e49Pk8DWH4IrIPQh1BinHYQgoXllCNiDw,777
9
+ dbus2mqtt/dbus/dbus_util.py,sha256=h-1Y8Mvz9bj9X7mPZ8LghkvXDrujdJHK0__AOW373hE,697
10
+ dbus2mqtt/dbus/introspection_patches/mpris_playerctl.py,sha256=q93d_Yp93u3Y-9q0dRdKW5hrij9GK3CFqKhUWVE8uw4,5883
11
+ dbus2mqtt/dbus/introspection_patches/mpris_vlc.py,sha256=Cf-o-05W6gUoKpcYR7n0dRi-CrbeASPTwkyEzZGnU3Y,4241
12
+ dbus2mqtt/flow/__init__.py,sha256=tAL-CjXQHq_tGTKctIdOZ5teVKBtcJs6Astq_RdruV8,1540
13
+ dbus2mqtt/flow/flow_processor.py,sha256=-fJ5JPFcFqz1RokKaqjdHoU-EPg5McAERKYFwIkMzgU,8749
14
+ dbus2mqtt/flow/actions/context_set.py,sha256=dIT39MJJVb0wuRI_ZM3ssnXYfa-iyB4o_UZD-1BZL2g,1087
15
+ dbus2mqtt/flow/actions/mqtt_publish.py,sha256=psNkTvaR3JZwAwpM4AqiZTDnA5UQX9r4CUZ1LA7iRW4,2366
16
+ dbus2mqtt/mqtt/mqtt_client.py,sha256=R0ZNUmOr8Lg8s2TuUcjH3BvEPPlNK731tzO0tNVvqqs,5167
17
+ dbus2mqtt/template/dbus_template_functions.py,sha256=UEoXK2PqDKF6jR4vTFHQwq58f5APnOJr7B1_I1zW8yM,2449
18
+ dbus2mqtt/template/templating.py,sha256=ZLp1A8PFAs_-Bndx4yGqyppaDfh8marHlK7P3bFInu4,4144
19
+ dbus2mqtt-0.4.1.dist-info/METADATA,sha256=LR9PxxTxJ6TcxHpa8YKg9E6uWRDWYRBbpQ5-o5QGTxQ,8114
20
+ dbus2mqtt-0.4.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
21
+ dbus2mqtt-0.4.1.dist-info/entry_points.txt,sha256=pmmacoHCsvTTUB5dIPaY4i0H9gX7BQlpd3rBU-Jbv3A,50
22
+ dbus2mqtt-0.4.1.dist-info/licenses/LICENSE,sha256=a4bIEgyA9rrnAfUN90CgbgZ6BQIFHeABkk0JihiBaxM,1074
23
+ dbus2mqtt-0.4.1.dist-info/RECORD,,
@@ -1,23 +0,0 @@
1
- dbus2mqtt/__init__.py,sha256=VunubKEH4_lne9Ttd2YRpyXjZMIAzyD2eiJ2sfvvTFU,362
2
- dbus2mqtt/__main__.py,sha256=NAoa3nwgBSQI22eWzzRx61SIDThDwXmUofWWZU3_4-Q,71
3
- dbus2mqtt/event_broker.py,sha256=WNup2Xywt2MYs1yDyKAytApJn_YOPnxQag3kOkOajX0,1844
4
- dbus2mqtt/main.py,sha256=pHsRbjjvQSAOWhmfazixKteAdfrB-YnC4LQAZovdkEQ,3863
5
- dbus2mqtt/config/__init__.py,sha256=lx94zQsejGMRf90h594jId_CKXY0CyL7n6hk3lwAVvE,4307
6
- dbus2mqtt/config/jsonarparse.py,sha256=VJGFeyQJcOE6bRXlSRr3FClvN_HnmiIlEGmOgNM0oCc,1214
7
- dbus2mqtt/dbus/dbus_client.py,sha256=LAP6QkjPvDHIXOKncHiNYrTnVEV2NRYc1Mymzp-miMY,23217
8
- dbus2mqtt/dbus/dbus_types.py,sha256=EejiLlh3ALAnB4OFvNRL4ILBbxSKgFNNwifBrfap1Gc,494
9
- dbus2mqtt/dbus/dbus_util.py,sha256=Q50Tr1qjqZHpVirzvT9gXYwiCLwPe6BpgVmAcrqdHKE,569
10
- dbus2mqtt/dbus/introspection_patches/mpris_playerctl.py,sha256=q93d_Yp93u3Y-9q0dRdKW5hrij9GK3CFqKhUWVE8uw4,5883
11
- dbus2mqtt/dbus/introspection_patches/mpris_vlc.py,sha256=Cf-o-05W6gUoKpcYR7n0dRi-CrbeASPTwkyEzZGnU3Y,4241
12
- dbus2mqtt/flow/__init__.py,sha256=tAL-CjXQHq_tGTKctIdOZ5teVKBtcJs6Astq_RdruV8,1540
13
- dbus2mqtt/flow/flow_processor.py,sha256=TR30RpN0DoKWgx3Il-wyIzGwRqTjXyEUlqar3S3E3SI,8215
14
- dbus2mqtt/flow/actions/context_set.py,sha256=dIT39MJJVb0wuRI_ZM3ssnXYfa-iyB4o_UZD-1BZL2g,1087
15
- dbus2mqtt/flow/actions/mqtt_publish.py,sha256=psNkTvaR3JZwAwpM4AqiZTDnA5UQX9r4CUZ1LA7iRW4,2366
16
- dbus2mqtt/mqtt/mqtt_client.py,sha256=9Y0AEuquq4gEQ8j9JD1wauU22wSHZFSyQBNr905lwxA,4899
17
- dbus2mqtt/template/dbus_template_functions.py,sha256=0WXH-X3Si5D8iKP1WrSK9XmbKcaTGQo92SJsfHG0JEE,2427
18
- dbus2mqtt/template/templating.py,sha256=ZLp1A8PFAs_-Bndx4yGqyppaDfh8marHlK7P3bFInu4,4144
19
- dbus2mqtt-0.3.1.dist-info/METADATA,sha256=5xbhQusP8EUrvvMuN6rK2MUWBNKMgWOu1XkfADaGSd8,7830
20
- dbus2mqtt-0.3.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
21
- dbus2mqtt-0.3.1.dist-info/entry_points.txt,sha256=pmmacoHCsvTTUB5dIPaY4i0H9gX7BQlpd3rBU-Jbv3A,50
22
- dbus2mqtt-0.3.1.dist-info/licenses/LICENSE,sha256=a4bIEgyA9rrnAfUN90CgbgZ6BQIFHeABkk0JihiBaxM,1074
23
- dbus2mqtt-0.3.1.dist-info/RECORD,,