From 53fc6cbb7f3a2c3b52974c1fecf889f0e0a3be8f Mon Sep 17 00:00:00 2001 From: Kevin Petremann Date: Fri, 30 Jun 2023 18:41:03 +0200 Subject: [PATCH 1/4] feat: add hubitat support --- mqtt_exporter/main.py | 28 ++++++++++++++++++++++++++ mqtt_exporter/settings.py | 1 + tests/functional/test_parse_message.py | 12 +++++++++++ 3 files changed, 41 insertions(+) diff --git a/mqtt_exporter/main.py b/mqtt_exporter/main.py index 3a50dc4..b94f8c0 100644 --- a/mqtt_exporter/main.py +++ b/mqtt_exporter/main.py @@ -251,6 +251,24 @@ def _normalize_esphome_format(topic, payload): return topic, payload_dict +def _normalize_hubitat_format(topic, payload): + """Normalize hubitat format. + + Example: + hubitat/hub1/some room/temperature/value + """ + breakpoint() + + info = topic.split("/") + + if len(info) < 3: + return topic, payload + + topic = f"{info[0].lower()}_{info[1].lower()}_{info[2].lower()}" + payload_dict = {info[-2]: payload} + return topic, payload_dict + + def _is_esphome_topic(topic): for prefix in settings.ESPHOME_TOPIC_PREFIXES: if prefix and topic.startswith(prefix): @@ -259,6 +277,14 @@ def _is_esphome_topic(topic): return False +def _is_esphome_topic(topic): + for prefix in settings.HUBITAT_TOPIC_PREFIXES: + if prefix and topic.startswith(prefix): + return True + + return False + + def _parse_message(raw_topic, raw_payload): """Parse topic and payload to have exposable information.""" # parse MQTT payload @@ -273,6 +299,8 @@ def _parse_message(raw_topic, raw_payload): if raw_topic.startswith(settings.ZWAVE_TOPIC_PREFIX): topic, payload = _normalize_zwave2mqtt_format(raw_topic, payload) + elif _is_esphome_topic(raw_topic): + topic, payload = _normalize_hubitat_format(raw_topic, payload) elif _is_esphome_topic(raw_topic): topic, payload = _normalize_esphome_format(raw_topic, payload) elif not isinstance(payload, dict): diff --git a/mqtt_exporter/settings.py b/mqtt_exporter/settings.py index 44fed8f..3cae1c6 100644 --- a/mqtt_exporter/settings.py +++ b/mqtt_exporter/settings.py @@ -7,6 +7,7 @@ IGNORED_TOPICS = os.getenv("MQTT_IGNORED_TOPICS", "").split(",") ZWAVE_TOPIC_PREFIX = os.getenv("ZWAVE_TOPIC_PREFIX", "zwave/") ESPHOME_TOPIC_PREFIXES = os.getenv("ESPHOME_TOPIC_PREFIXES", "").split(",") +HUBITAT_TOPIC_PREFIXES = os.getenv("HUBITAT_TOPIC_PREFIXES", "hubitat/").split(",") ZIGBEE2MQTT_AVAILABILITY = os.getenv("ZIGBEE2MQTT_AVAILABILITY", "False") == "True" LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO") diff --git a/tests/functional/test_parse_message.py b/tests/functional/test_parse_message.py index 8d4f8a5..43a72ea 100644 --- a/tests/functional/test_parse_message.py +++ b/tests/functional/test_parse_message.py @@ -163,3 +163,15 @@ def test__parse_message__esphome_style(): assert parsed_topic == "esphome_indoor" assert parsed_payload == {"temperature": 22.0} + + +def test__parse_message__hubitat_style(): + # hubitat/[hubname]/[device name]/[attribute name]/value + + topic = "hubitat/hub1/some_room/temperature/value" + payload = "20.0" + + parsed_topic, parsed_payload = _parse_message(topic, payload) + + assert parsed_topic == "hubitat_hub1_some_room" + assert parsed_payload == 20.0 From aa3eb983348aca3f220f96b9624131f9fada2ba4 Mon Sep 17 00:00:00 2001 From: Kevin Petremann Date: Fri, 30 Jun 2023 18:55:37 +0200 Subject: [PATCH 2/4] fix: remove breakpoint + update docstrings --- mqtt_exporter/main.py | 2 -- tests/functional/test_parse_message.py | 11 +++++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/mqtt_exporter/main.py b/mqtt_exporter/main.py index b94f8c0..d9e7c09 100644 --- a/mqtt_exporter/main.py +++ b/mqtt_exporter/main.py @@ -257,8 +257,6 @@ def _normalize_hubitat_format(topic, payload): Example: hubitat/hub1/some room/temperature/value """ - breakpoint() - info = topic.split("/") if len(info) < 3: diff --git a/tests/functional/test_parse_message.py b/tests/functional/test_parse_message.py index 43a72ea..93e9c30 100644 --- a/tests/functional/test_parse_message.py +++ b/tests/functional/test_parse_message.py @@ -143,7 +143,7 @@ def test_parse_message__zwave_js__payload_not_dict(): def test__parse_message__esphome_style(): - """Test message parsing with espthome style. + """Test message parsing with esphome style. Same format for SONOFF sensors. """ @@ -166,12 +166,15 @@ def test__parse_message__esphome_style(): def test__parse_message__hubitat_style(): - # hubitat/[hubname]/[device name]/[attribute name]/value + """Test message parsing with Hubitat style. - topic = "hubitat/hub1/some_room/temperature/value" + It looks like: hubitat/[hubname]/[device name]/attributes/[attribute name]/value + """ + + topic = "hubitat/hub1/some_room/attributes/temperature/value" payload = "20.0" parsed_topic, parsed_payload = _parse_message(topic, payload) assert parsed_topic == "hubitat_hub1_some_room" - assert parsed_payload == 20.0 + assert parsed_payload == {"temperature": 20.0} From 072a78894bdea98ea9c8e24913efb71d2047ed71 Mon Sep 17 00:00:00 2001 From: Kevin Petremann Date: Fri, 30 Jun 2023 19:00:47 +0200 Subject: [PATCH 3/4] fix(tests): fix extra blank line after docstring --- tests/functional/test_parse_message.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/functional/test_parse_message.py b/tests/functional/test_parse_message.py index 93e9c30..312e9d2 100644 --- a/tests/functional/test_parse_message.py +++ b/tests/functional/test_parse_message.py @@ -170,7 +170,6 @@ def test__parse_message__hubitat_style(): It looks like: hubitat/[hubname]/[device name]/attributes/[attribute name]/value """ - topic = "hubitat/hub1/some_room/attributes/temperature/value" payload = "20.0" From 1e0240c21668b15f1dbd8c0e83ec79b5c18b26fb Mon Sep 17 00:00:00 2001 From: Kevin Petremann Date: Fri, 30 Jun 2023 19:03:56 +0200 Subject: [PATCH 4/4] fix: esphome parsing broken because of bad copy/paste --- mqtt_exporter/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mqtt_exporter/main.py b/mqtt_exporter/main.py index d9e7c09..80a7014 100644 --- a/mqtt_exporter/main.py +++ b/mqtt_exporter/main.py @@ -275,7 +275,7 @@ def _is_esphome_topic(topic): return False -def _is_esphome_topic(topic): +def _is_hubitat_topic(topic): for prefix in settings.HUBITAT_TOPIC_PREFIXES: if prefix and topic.startswith(prefix): return True @@ -297,7 +297,7 @@ def _parse_message(raw_topic, raw_payload): if raw_topic.startswith(settings.ZWAVE_TOPIC_PREFIX): topic, payload = _normalize_zwave2mqtt_format(raw_topic, payload) - elif _is_esphome_topic(raw_topic): + elif _is_hubitat_topic(raw_topic): topic, payload = _normalize_hubitat_format(raw_topic, payload) elif _is_esphome_topic(raw_topic): topic, payload = _normalize_esphome_format(raw_topic, payload)