Skip to content

Commit

Permalink
- Added MqttTopicInfo
Browse files Browse the repository at this point in the history
- Fixed listen only for mqtt
  • Loading branch information
spacemanspiff2007 committed Oct 28, 2024
1 parent e443d07 commit 628ceaa
Show file tree
Hide file tree
Showing 9 changed files with 120 additions and 107 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ repos:


- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.7.0
rev: v0.7.1
hooks:
- id: ruff
name: ruff unused imports
Expand Down
33 changes: 33 additions & 0 deletions docs/interface_mqtt.rst
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,39 @@ and it will also trigger for :class:`~HABApp.mqtt.events.MqttValueChangeEvent`.
:member-order: groupwise


Mqtt util
--------------------------------------

MqttTopicInfo
""""""""""""""""""""""""""""""""""""""

.. autoclass:: HABApp.mqtt.util.MqttTopicInfo
:members:
:inherited-members:
:member-order: groupwise

.. exec_code::
:hide_output:

# ------------ hide: start ------------
from rule_runner import SimpleRuleRunner
SimpleRuleRunner().set_up()

import HABApp
from unittest.mock import MagicMock
HABApp.mqtt.util.topic_info.publish = MagicMock()
# ------------ hide: stop -------------
from HABApp.mqtt.util import MqttTopicInfo

topic = MqttTopicInfo('my/output/only/topic')
topic.publish('new_value')

topic_qos = MqttTopicInfo('my/output/only/topic', qos=2)
topic_qos.publish('new_value')

topic_qos_retain = topic_qos.replace(retain=True)
topic_qos_retain.publish('new_value')


Example MQTT rule
--------------------------------------
Expand Down
8 changes: 8 additions & 0 deletions run/conf_testing/rules/test_mqtt.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from HABApp.core.events import ValueUpdateEventFilter
from HABApp.mqtt.events import MqttValueUpdateEventFilter
from HABApp.mqtt.items import MqttItem, MqttPairItem
from HABApp.mqtt.util import MqttTopicInfo


log = logging.getLogger('HABApp.MqttTestEvents')
Expand All @@ -30,6 +31,7 @@ def __init__(self) -> None:

self.add_test('MQTT item creation', self.test_mqtt_item_creation)
self.add_test('MQTT pair item', self.test_mqtt_pair_item)
self.add_test('MQTT topic info', self.test_mqtt_topic_info)

def test_mqtt_pair_item(self) -> None:
topic_read = 'test/topic_read'
Expand Down Expand Up @@ -88,5 +90,11 @@ async def trigger_reconnect(self) -> None:
connection.status._set_manual(ConnectionStatus.DISCONNECTED)
connection.advance_status_task.start_if_not_running()

def test_mqtt_topic_info(self) -> None:
t = MqttTopicInfo('test/event_topic')
with EventWaiter(t.topic, ValueUpdateEventFilter()) as waiter:
t.publish('asdf')
waiter.wait_for_event(value='asdf')


TestMQTTEvents()
2 changes: 1 addition & 1 deletion src/HABApp/__version__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@
# Development versions contain the DEV-COUNTER postfix:
# - 24.01.0.DEV-1

__version__ = '24.09.0.DEV-10'
__version__ = '24.09.0.DEV-11'
6 changes: 4 additions & 2 deletions src/HABApp/mqtt/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from . import events
from . import items
from . import events, items, util


# isort: split


import HABApp.mqtt.interface_async
import HABApp.mqtt.interface_sync

17 changes: 13 additions & 4 deletions src/HABApp/mqtt/connection/publish.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
from asyncio import Queue
from typing import Any

from pydantic import BaseModel

from HABApp.config import CONFIG
from HABApp.config.models.mqtt import QOS
Expand All @@ -13,6 +16,9 @@ def __init__(self) -> None:
super().__init__(task_name='MqttPublish')

async def mqtt_task(self) -> None:
if CONFIG.mqtt.general.listen_only:
return None

connection = self.plugin_connection
with connection.handle_exception(self.mqtt_task):
client = self.plugin_connection.context
Expand All @@ -36,7 +42,8 @@ async def mqtt_task(self) -> None:
async def on_connected(self) -> None:
global QUEUE

QUEUE = Queue()
if not CONFIG.mqtt.general.listen_only:
QUEUE = Queue()
await super().on_connected()

async def on_disconnected(self) -> None:
Expand All @@ -52,7 +59,7 @@ async def on_disconnected(self) -> None:
PUBLISH_HANDLER = PublishHandler()


def async_publish(topic: str | ItemRegistryItem, payload, qos: QOS | None = None,
def async_publish(topic: str | ItemRegistryItem, payload: Any, qos: QOS | None = None,
retain: bool | None = None) -> None:
"""
Publish a value under a certain topic.
Expand All @@ -70,14 +77,16 @@ def async_publish(topic: str | ItemRegistryItem, payload, qos: QOS | None = None
topic = topic.name

# convert these to string
if isinstance(payload, (dict, list, set, frozenset)):
if isinstance(payload, BaseModel):
payload = payload.model_dump_json()
elif isinstance(payload, (dict, list, set, frozenset)):
payload = dump_json(payload)

queue.put_nowait((topic, payload, qos, retain))
return None


def publish(topic: str | ItemRegistryItem, payload, qos: QOS | None = None, retain: bool | None = None) -> None:
def publish(topic: str | ItemRegistryItem, payload: Any, qos: QOS | None = None, retain: bool | None = None) -> None:
"""
Publish a value under a certain topic.
If qos and/or retain is not set the value from the configuration file will be used.
Expand Down
99 changes: 0 additions & 99 deletions src/HABApp/mqtt/mqtt_interface.py

This file was deleted.

1 change: 1 addition & 0 deletions src/HABApp/mqtt/util/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .topic_info import MqttTopicInfo
59 changes: 59 additions & 0 deletions src/HABApp/mqtt/util/topic_info.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from typing import Any, Final

from typing_extensions import Self

from HABApp.mqtt.interface_sync import publish


class MqttTopicInfo:
"""Allows to store the topic, qos and retain settings for a topic. These values can then be used to publish
"""
def __init__(self, topic: str, qos: int | None = None, retain: bool | None = None) -> None:
if not isinstance(topic, str):
raise TypeError()
if not topic:
raise ValueError()

self._topic: Final = topic
self._qos: Final = qos
self._retain: Final = retain

@property
def topic(self) -> str:
"""The topic"""
return self._topic

@property
def qos(self) -> int | None:
"""QOS"""
return self._qos

@property
def retain(self) -> bool | None:
"""Retain"""
return self._retain

def publish(self, payload: Any) -> None:
"""
Publish a payload
:param payload: MQTT Payload
"""

return publish(self._topic, payload, qos=self._qos, retain=self._retain)

def replace(self, topic: str | None = None, qos: int | None = None, retain: bool | None = None) -> Self:
"""
Replace the topic, qos and retain with the given values and return a new object.
:param topic: New topic (if provided)
:param qos: New qos (if provided)
:param retain: New retain (if provided)
:return: New object
"""

return self.__class__(
topic if topic is not None else self._topic,
qos if qos is not None else self._qos,
retain if retain is not None else self._retain
)

0 comments on commit 628ceaa

Please sign in to comment.