Skip to content

Commit

Permalink
.
Browse files Browse the repository at this point in the history
  • Loading branch information
spacemanspiff2007 committed Apr 11, 2024
1 parent 4e74d52 commit e985209
Show file tree
Hide file tree
Showing 9 changed files with 74 additions and 50 deletions.
9 changes: 6 additions & 3 deletions src/sml2mqtt/config/mqtt.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,11 @@ class MqttConnection(BaseModel):


class MqttConfig(BaseModel):
connection: MqttConnection = Field(default_factory=MqttConnection)
topic: MqttTopicStr = Field('sml2mqtt', alias='topic prefix')
defaults: MqttDefaultPublishConfig = Field(default_factory=MqttDefaultPublishConfig)
connection: MqttConnection = Field(
default_factory=MqttConnection)
topic: StrippedStr = Field(
'sml2mqtt', alias='topic prefix', description='Prefix for all topics. Set to empty string to disable')
defaults: MqttDefaultPublishConfig = Field(
default_factory=MqttDefaultPublishConfig)
last_will: OptionalMqttPublishConfig = Field(
default_factory=lambda: OptionalMqttPublishConfig(topic='status'), alias='last will')
4 changes: 4 additions & 0 deletions src/sml2mqtt/mqtt/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,9 @@ class TopicFragmentExpectedError(Exception):
pass


class MqttTopicEmpty(Exception):
pass


class MqttConfigValuesMissingError(Exception):
pass
14 changes: 12 additions & 2 deletions src/sml2mqtt/mqtt/mqtt_obj.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from sml2mqtt.config import OptionalMqttPublishConfig
from sml2mqtt.mqtt import publish

from .errors import MqttConfigValuesMissingError, TopicFragmentExpectedError
from .errors import MqttConfigValuesMissingError, MqttTopicEmpty, TopicFragmentExpectedError


pub_func: Callable[[str, int | float | str, int, bool], Any] = publish
Expand Down Expand Up @@ -77,7 +77,17 @@ def _merge_values(self) -> 'MqttObj':
else:
if not self.cfg.topic_fragment:
raise TopicFragmentExpectedError()
self.topic = f'{self.parent.topic}/{self.cfg.topic_fragment}'

# The topmost topic may be empty
parts = []
if self.parent.topic:
parts.append(self.parent.topic)
if self.cfg.topic_fragment:
parts.append(self.cfg.topic_fragment)
self.topic = '/'.join(parts)

if not self.topic:
raise MqttTopicEmpty()

# effective QOS
self.qos = self.cfg.qos
Expand Down
2 changes: 1 addition & 1 deletion tests/config/test_default.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def test_default():
port: 1883
user: ''
password: ''
topic prefix: sml2mqtt
topic prefix: sml2mqtt # Prefix for all topics. Set to empty string to disable
defaults:
qos: 0 # Default value for QoS if no other QoS value in the config entry is set
retain: false # Default value for retain if no other retain value in the config entry is set
Expand Down
38 changes: 19 additions & 19 deletions tests/sml_device/frames/test_frame_1.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ async def test_frame_no_match_obis_id(no_mqtt, caplog, monkeypatch, sml_frame_1,
-> b'760500531efa620062007263010176010105001bb4fe0b0a0149534b0005020de272620165001bb32e620163a71400760500531efb620062007263070177010b0a0149534b0005020de2070100620affff72620165001bb32e757707010060320101010101010449534b0177070100600100ff010101010b0a0149534b0005020de20177070100010800ff65001c010401621e52ff650026bea90177070100020800ff0101621e52ff62000177070100100700ff0101621b52005301100101016350ba00760500531efc6200620072630201710163ba1900'
Exception <class 'sml2mqtt.errors.ObisIdForConfigurationMappingNotFoundError'>: ""
ERROR
/device_name/status: ERROR (QOS: 0, retain: False)'''
device_name/status: ERROR (QOS: 0, retain: False)'''


@pytest.mark.ignore_log_warnings()
Expand All @@ -50,21 +50,21 @@ async def test_frame_no_config(no_mqtt, caplog, monkeypatch, sml_frame_1, arg_an
<SmlValue>
obis : 010060320101
topic: /0a0149534b0005020de2/010060320101
topic: 0a0149534b0005020de2/010060320101
operations:
- On Change Filter
- Refresh Action: 2 minutes
<SmlValue>
obis : 0100600100ff
topic: /0a0149534b0005020de2/0100600100ff
topic: 0a0149534b0005020de2/0100600100ff
operations:
- On Change Filter
- Refresh Action: 2 minutes
<SmlValue>
obis : 0100010800ff
topic: /0a0149534b0005020de2/0100010800ff
topic: 0a0149534b0005020de2/0100010800ff
operations:
- Zero Meter Filter
- Factor: 0.001
Expand All @@ -73,7 +73,7 @@ async def test_frame_no_config(no_mqtt, caplog, monkeypatch, sml_frame_1, arg_an
<SmlValue>
obis : 0100020800ff
topic: /0a0149534b0005020de2/0100020800ff
topic: 0a0149534b0005020de2/0100020800ff
operations:
- Zero Meter Filter
- Factor: 0.001
Expand All @@ -82,20 +82,20 @@ async def test_frame_no_config(no_mqtt, caplog, monkeypatch, sml_frame_1, arg_an
<SmlValue>
obis : 0100100700ff
topic: /0a0149534b0005020de2/0100100700ff
topic: 0a0149534b0005020de2/0100100700ff
operations:
- On Change Filter
- Refresh Action: 2 minutes
/0a0149534b0005020de2/010060320101: ISK (QOS: 0, retain: False)
/0a0149534b0005020de2/0100600100ff: 0a0149534b0005020de2 (QOS: 0, retain: False)
/0a0149534b0005020de2/0100010800ff: 253.91770000000002 (QOS: 0, retain: False)
/0a0149534b0005020de2/0100100700ff: 272 (QOS: 0, retain: False)
0a0149534b0005020de2/010060320101: ISK (QOS: 0, retain: False)
0a0149534b0005020de2/0100600100ff: 0a0149534b0005020de2 (QOS: 0, retain: False)
0a0149534b0005020de2/0100010800ff: 253.91770000000002 (QOS: 0, retain: False)
0a0149534b0005020de2/0100100700ff: 272 (QOS: 0, retain: False)
OK
/0a0149534b0005020de2/status: OK (QOS: 0, retain: False)
0a0149534b0005020de2/status: OK (QOS: 0, retain: False)
SHUTDOWN
/0a0149534b0005020de2/status: SHUTDOWN (QOS: 0, retain: False)'''
0a0149534b0005020de2/status: SHUTDOWN (QOS: 0, retain: False)'''


async def test_frame_with_config(no_mqtt, caplog, monkeypatch, sml_frame_1, arg_analyze, sml_frame_1_analyze):
Expand Down Expand Up @@ -123,7 +123,7 @@ async def test_frame_with_config(no_mqtt, caplog, monkeypatch, sml_frame_1, arg_
<SmlValue>
obis : 0100010800ff
topic: /0a0149534b0005020de2/0100010800ff
topic: 0a0149534b0005020de2/0100010800ff
operations:
- Zero Meter Filter
- Factor: 0.001
Expand All @@ -132,7 +132,7 @@ async def test_frame_with_config(no_mqtt, caplog, monkeypatch, sml_frame_1, arg_
<SmlValue>
obis : 0100020800ff
topic: /0a0149534b0005020de2/0100020800ff
topic: 0a0149534b0005020de2/0100020800ff
operations:
- Zero Meter Filter
- Factor: 0.001
Expand All @@ -141,15 +141,15 @@ async def test_frame_with_config(no_mqtt, caplog, monkeypatch, sml_frame_1, arg_
<SmlValue>
obis : 0100100700ff
topic: /0a0149534b0005020de2/0100100700ff
topic: 0a0149534b0005020de2/0100100700ff
operations:
- On Change Filter
- Refresh Action: 2 minutes
/0a0149534b0005020de2/0100010800ff: 253.91770000000002 (QOS: 0, retain: False)
/0a0149534b0005020de2/0100100700ff: 272 (QOS: 0, retain: False)
0a0149534b0005020de2/0100010800ff: 253.91770000000002 (QOS: 0, retain: False)
0a0149534b0005020de2/0100100700ff: 272 (QOS: 0, retain: False)
OK
/0a0149534b0005020de2/status: OK (QOS: 0, retain: False)
0a0149534b0005020de2/status: OK (QOS: 0, retain: False)
SHUTDOWN
/0a0149534b0005020de2/status: SHUTDOWN (QOS: 0, retain: False)'''
0a0149534b0005020de2/status: SHUTDOWN (QOS: 0, retain: False)'''
2 changes: 1 addition & 1 deletion tests/sml_device/frames/test_frame_2.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@ async def test_frame_no_match_obis_id(no_mqtt, caplog, monkeypatch, sml_frame_2,
-> b'7605065850a66200620072630101760107ffffffffffff05021d70370b0a014c475a0003403b4972620165021d7707016326de007605065850a762006200726307017707ffffffffffff0b0a014c475a0003403b49070100620affff72620165021d770775770701006032010101010101044c475a0177070100600100ff010101010b0a014c475a0003403b490177070100010800ff65001c010472620165021d7707621e52ff690000000003152c450177070100020800ff0172620165021d7707621e52ff6900000000000000000177070100100700ff0101621b52005900000000000000fb010101637264007605065850a862006200726302017101631c8c00'
Exception <class 'sml2mqtt.errors.ObisIdForConfigurationMappingNotFoundError'>: ""
ERROR
/device_name/status: ERROR (QOS: 0, retain: False)'''
device_name/status: ERROR (QOS: 0, retain: False)'''
40 changes: 20 additions & 20 deletions tests/sml_device/test_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,17 @@ async def test_device_analyze(no_mqtt, caplog, sml_data_1, arg_analyze, sml_data
msg = "\n".join(x.msg for x in filter(lambda x: x.name == 'sml.mqtt.pub', caplog.records))

assert '\n' + msg == """
/00000000000000000000/0100000009ff: 00000000000000000000 (QOS: 0, retain: False)
/00000000000000000000/0100010800ff: 450.09189911 (QOS: 0, retain: False)
/00000000000000000000/0100010801ff: 449.07489911 (QOS: 0, retain: False)
/00000000000000000000/0100010802ff: 1.0170000000000001 (QOS: 0, retain: False)
/00000000000000000000/0100020800ff: 2.198 (QOS: 0, retain: False)
/00000000000000000000/0100100700ff: 352.89 (QOS: 0, retain: False)
/00000000000000000000/0100240700ff: 82.26 (QOS: 0, retain: False)
/00000000000000000000/0100380700ff: 27.06 (QOS: 0, retain: False)
/00000000000000000000/01004c0700ff: 243.57 (QOS: 0, retain: False)
/00000000000000000000/status: OK (QOS: 0, retain: False)
/00000000000000000000/status: SHUTDOWN (QOS: 0, retain: False)"""
00000000000000000000/0100000009ff: 00000000000000000000 (QOS: 0, retain: False)
00000000000000000000/0100010800ff: 450.09189911 (QOS: 0, retain: False)
00000000000000000000/0100010801ff: 449.07489911 (QOS: 0, retain: False)
00000000000000000000/0100010802ff: 1.0170000000000001 (QOS: 0, retain: False)
00000000000000000000/0100020800ff: 2.198 (QOS: 0, retain: False)
00000000000000000000/0100100700ff: 352.89 (QOS: 0, retain: False)
00000000000000000000/0100240700ff: 82.26 (QOS: 0, retain: False)
00000000000000000000/0100380700ff: 27.06 (QOS: 0, retain: False)
00000000000000000000/01004c0700ff: 243.57 (QOS: 0, retain: False)
00000000000000000000/status: OK (QOS: 0, retain: False)
00000000000000000000/status: SHUTDOWN (QOS: 0, retain: False)"""

msg = "\n".join(x.msg for x in filter(lambda x: x.name == 'sml.device_name', caplog.records))

Expand All @@ -49,14 +49,14 @@ async def test_device_analyze(no_mqtt, caplog, sml_data_1, arg_analyze, sml_data
<SmlValue>
obis : 0100000009ff
topic: /00000000000000000000/0100000009ff
topic: 00000000000000000000/0100000009ff
operations:
- On Change Filter
- Refresh Action: 2 minutes
<SmlValue>
obis : 0100010800ff
topic: /00000000000000000000/0100010800ff
topic: 00000000000000000000/0100010800ff
operations:
- Zero Meter Filter
- Factor: 0.001
Expand All @@ -65,7 +65,7 @@ async def test_device_analyze(no_mqtt, caplog, sml_data_1, arg_analyze, sml_data
<SmlValue>
obis : 0100010801ff
topic: /00000000000000000000/0100010801ff
topic: 00000000000000000000/0100010801ff
operations:
- Zero Meter Filter
- Factor: 0.001
Expand All @@ -74,7 +74,7 @@ async def test_device_analyze(no_mqtt, caplog, sml_data_1, arg_analyze, sml_data
<SmlValue>
obis : 0100010802ff
topic: /00000000000000000000/0100010802ff
topic: 00000000000000000000/0100010802ff
operations:
- Zero Meter Filter
- Factor: 0.001
Expand All @@ -83,7 +83,7 @@ async def test_device_analyze(no_mqtt, caplog, sml_data_1, arg_analyze, sml_data
<SmlValue>
obis : 0100020800ff
topic: /00000000000000000000/0100020800ff
topic: 00000000000000000000/0100020800ff
operations:
- Zero Meter Filter
- Factor: 0.001
Expand All @@ -92,28 +92,28 @@ async def test_device_analyze(no_mqtt, caplog, sml_data_1, arg_analyze, sml_data
<SmlValue>
obis : 0100100700ff
topic: /00000000000000000000/0100100700ff
topic: 00000000000000000000/0100100700ff
operations:
- On Change Filter
- Refresh Action: 2 minutes
<SmlValue>
obis : 0100240700ff
topic: /00000000000000000000/0100240700ff
topic: 00000000000000000000/0100240700ff
operations:
- On Change Filter
- Refresh Action: 2 minutes
<SmlValue>
obis : 0100380700ff
topic: /00000000000000000000/0100380700ff
topic: 00000000000000000000/0100380700ff
operations:
- On Change Filter
- Refresh Action: 2 minutes
<SmlValue>
obis : 01004c0700ff
topic: /00000000000000000000/01004c0700ff
topic: 00000000000000000000/01004c0700ff
operations:
- On Change Filter
- Refresh Action: 2 minutes
Expand Down
8 changes: 4 additions & 4 deletions tests/sml_values/test_values.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@


def test_values(sml_frame_1_values: SmlFrameValues, no_mqtt):
mqtt = MqttObj(qos=0, retain=False)
mqtt = MqttObj(topic_fragment='test', qos=0, retain=False).update()

v = SmlValues()
v.set_skipped('010060320101', '0100600100ff', '0100020800ff')
Expand All @@ -30,21 +30,21 @@ def test_values(sml_frame_1_values: SmlFrameValues, no_mqtt):
# The change filter prevents a republish
for _ in range(10):
v.process_frame(sml_frame_1_values)
assert no_mqtt == [('/energy', 253917.7, 0, False), ('/power', 272, 0, False)]
assert no_mqtt == [('test/energy', 253917.7, 0, False), ('test/power', 272, 0, False)]

# test description
check_description(v, [
'Skipped: 0100020800ff, 0100600100ff, 010060320101',
'',
'<SmlValue>',
' obis : 0100010800ff',
' topic: /energy',
' topic: test/energy',
' operations:',
' - On Change Filter',
'',
'<SmlValue>',
' obis : 0100100700ff',
' topic: /power',
' topic: test/power',
' operations:',
' - On Change Filter',
'',
Expand Down
7 changes: 7 additions & 0 deletions tests/test_mqtt_obj.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ def test_topmost(monkeypatch):
assert parent.retain is True


def test_prefix_empty(monkeypatch):
parent = MqttObj('', 2, True).update()
child = parent.create_child('child')

assert (child.topic, child.qos, child.retain) == ('child', 2, True)


def test_child_change(monkeypatch):
parent = MqttObj('base', 2, True).update()
child = parent.create_child('child')
Expand Down

0 comments on commit e985209

Please sign in to comment.