From 446370092d769a9030f7a1019ea6bddf804a055d Mon Sep 17 00:00:00 2001 From: Mike Degatano Date: Tue, 18 Jan 2022 18:13:00 -0500 Subject: [PATCH] Add option for `last_seen` --- amr2mqtt/DOCS.md | 6 +++++ amr2mqtt/config.yaml | 1 + amr2mqtt/rootfs/amr2mqtt/amr2mqtt.py | 29 ++++++++++++++++++++- amr2mqtt/rootfs/amr2mqtt/settings.py | 4 +++ amr2mqtt/rootfs/etc/services.d/amr2mqtt/run | 3 +++ 5 files changed, 42 insertions(+), 1 deletion(-) diff --git a/amr2mqtt/DOCS.md b/amr2mqtt/DOCS.md index f7ac77a..d429a81 100644 --- a/amr2mqtt/DOCS.md +++ b/amr2mqtt/DOCS.md @@ -212,6 +212,12 @@ Client ID to use when connecting to the MQTT broker. By default, the topics of all MQTT messages begins with `amr2mqtt/{meter_ID}`. If you set this option then the topics will begin with `{mqtt.base_topic}/{meter_id}`. +### Option: `last_seen` + +Add `last_seen` field to each message with the current time in the specified format. +Options are: `ISO_8601`, `ISO_8601_local`, and `epoch`. Disabled if omitted. Useful +for detecting issues when meter normally reports in on a consistent interval. + ### Option: `home_assistant_discovery_enabled` Set to `false` to disable the add-on from sending discovery messages for the diff --git a/amr2mqtt/config.yaml b/amr2mqtt/config.yaml index cca6071..b44c21a 100644 --- a/amr2mqtt/config.yaml +++ b/amr2mqtt/config.yaml @@ -43,3 +43,4 @@ schema: log_level: list(trace|debug|info|notice|warning|error|fatal)? home_assistant_discovery_enabled: bool? home_assistant_discovery_prefix: match(^[^+#]{1,65535}$)? + last_seen: list(ISO_8601|ISO_8601_local|epoch)? diff --git a/amr2mqtt/rootfs/amr2mqtt/amr2mqtt.py b/amr2mqtt/rootfs/amr2mqtt/amr2mqtt.py index 86c2d0f..76eafd6 100644 --- a/amr2mqtt/rootfs/amr2mqtt/amr2mqtt.py +++ b/amr2mqtt/rootfs/amr2mqtt/amr2mqtt.py @@ -5,7 +5,7 @@ is a watched one, processes its reading using settings first. """ -from datetime import timedelta +from datetime import timedelta, datetime, timezone import logging import subprocess import signal @@ -13,6 +13,7 @@ import time import json import re +import math import paho.mqtt.client as mqtt import settings from dateutil import parser @@ -29,6 +30,7 @@ IDM_CONSUMPTION_FIELD = "LastConsumptionCount" NETIDM_CONSUMPTION_FIELD = "LastConsumptionNet" SCMPLUS_ID_FIELD = "EndpointID" +LAST_SEEN_ATTR = "'last_seen': value_json.last_seen" ALL_IDM = [ "Preamble", "PacketLength", @@ -185,6 +187,8 @@ def create_mqtt_client(): def create_interval_sensor(meter_id, meter, device_name, device_id): """Create discovery message for interval consumption sensor.""" + last_seen_attr = f"{LAST_SEEN_ATTR}," if settings.LAST_SEEN_ENABLED else "" + return set_consumption_details( payload={ "enabled_by_default": True, @@ -196,6 +200,7 @@ def create_interval_sensor(meter_id, meter, device_name, device_id): "{{ {" f"'{INTERVAL_FIELD}': value_json.{INTERVAL_FIELD}," f"'{INTERVAL_START_FIELD}': value_json.{INTERVAL_START_FIELD}," + f"{last_seen_attr}" f"'last_reset': value_json.{INTERVAL_START_FIELD}" "} | tojson }}" ), @@ -236,6 +241,11 @@ def create_sensor(attribute, device_name, device_id, enabled=True, category=None if category: sensor["entity_category"] = category + if settings.LAST_SEEN_ENABLED: + sensor[ + "json_attributes_template" + ] = f"{{{{ {{ {LAST_SEEN_ATTR} }} | tojson }}}}" + return sensor @@ -440,6 +450,23 @@ def main_loop(): else: continue + # Add last seen if in use + if settings.LAST_SEEN_ENABLED: + if settings.LAST_SEEN_FORMAT == "ISO_8601": + last_seen = ( + datetime.now().replace(microsecond=0).astimezone().isoformat() + ) + elif settings.LAST_SEEN_FORMAT == "ISO_8601_local": + last_seen = ( + datetime.utcnow() + .replace(microsecond=0, tzinfo=timezone.utc) + .isoformat() + ) + else: + last_seen = math.floor(time.time()) + + amr_message["last_seen"] = last_seen + # If in debugging mode, add the protocol to the message if settings.WATCHED_PROTOCOLS == "all": amr_message["Protocol"] = msg_type diff --git a/amr2mqtt/rootfs/amr2mqtt/settings.py b/amr2mqtt/rootfs/amr2mqtt/settings.py index 2d6edd4..6a8c35c 100644 --- a/amr2mqtt/rootfs/amr2mqtt/settings.py +++ b/amr2mqtt/rootfs/amr2mqtt/settings.py @@ -49,6 +49,10 @@ def make_meters_map(meters, meter): MQTT_BASE_TOPIC = base_topic if bool(base_topic) else "amr2mqtt" MQTT_AVAILABILTY_TOPIC = f"{MQTT_BASE_TOPIC}/bridge/state" +# Using last seen +LAST_SEEN_FORMAT = os.environ.get("LAST_SEEN") +LAST_SEEN_ENABLED = LAST_SEEN_FORMAT != "disable" + # Set up logging EV_TO_LOG_LEVEL = { "DEBUG": logging.DEBUG, diff --git a/amr2mqtt/rootfs/etc/services.d/amr2mqtt/run b/amr2mqtt/rootfs/etc/services.d/amr2mqtt/run index e7a0458..91a6740 100644 --- a/amr2mqtt/rootfs/etc/services.d/amr2mqtt/run +++ b/amr2mqtt/rootfs/etc/services.d/amr2mqtt/run @@ -52,6 +52,9 @@ elif bashio::config.exists 'home_assistant_discovery_prefix'; then export "HA_DISCOVERY_TOPIC=$(bashio::config 'home_assistant_discovery_prefix')" fi +# --- OTHER SETTINGS --- +export "LAST_SEEN=$(bashio::config 'last_seen' 'disable')" + # --- SET LOG LEVEL --- case "$(bashio::config 'log_level')" in \ trace) ;& \