From a2d4306fa64910b9d1d49c481019a9e8e6e501c0 Mon Sep 17 00:00:00 2001 From: Dirk Alders Date: Sat, 16 Dec 2023 08:16:45 +0100 Subject: [PATCH] Zigbee heating valve heartbeat check implemented --- check_z_heat_vlv_follow | 7 +++++-- check_z_heat_vlv_heartbeat | 1 + z_server/devices/__init__.py | 40 +++++++++++++++++++++++++++++++++--- z_server/z_protocol.py | 2 ++ 4 files changed, 45 insertions(+), 5 deletions(-) create mode 120000 check_z_heat_vlv_heartbeat diff --git a/check_z_heat_vlv_follow b/check_z_heat_vlv_follow index 04f0d07..d23f49b 100755 --- a/check_z_heat_vlv_follow +++ b/check_z_heat_vlv_follow @@ -7,7 +7,7 @@ import time from z_server import config from z_server import tcp_socket from z_server.z_protocol import server as client_prot -from z_server.z_protocol import DID_FOLLOWS_HEATING_SETPOINT, DID_BATTERY_LEVEL +from z_server.z_protocol import DID_FOLLOWS_HEATING_SETPOINT, DID_BATTERY_LEVEL, DID_HEARTBEAT from z_server import socket_protocol import sys @@ -31,7 +31,10 @@ if __name__ == '__main__': "fun": "FUN_HEA" # <-- Const, because script is for heat_vlv only } # - if sys.argv[0].endswith('check_z_heat_vlv_follow'): + if sys.argv[0].endswith('check_z_heat_vlv_heartbeat'): + sp.send(socket_protocol.SID_READ_REQUEST, DID_HEARTBEAT, data) + sp_data = sp.receive(socket_protocol.SID_READ_RESPONSE, DID_HEARTBEAT).get_data() + elif sys.argv[0].endswith('check_z_heat_vlv_follow'): sp.send(socket_protocol.SID_READ_REQUEST, DID_FOLLOWS_HEATING_SETPOINT, data) sp_data = sp.receive(socket_protocol.SID_READ_RESPONSE, DID_FOLLOWS_HEATING_SETPOINT).get_data() elif sys.argv[0].endswith('check_z_heat_vlv_battery'): diff --git a/check_z_heat_vlv_heartbeat b/check_z_heat_vlv_heartbeat new file mode 120000 index 0000000..06aac91 --- /dev/null +++ b/check_z_heat_vlv_heartbeat @@ -0,0 +1 @@ +check_z_heat_vlv_follow \ No newline at end of file diff --git a/z_server/devices/__init__.py b/z_server/devices/__init__.py index 5c91314..93a7799 100644 --- a/z_server/devices/__init__.py +++ b/z_server/devices/__init__.py @@ -16,8 +16,11 @@ class base(object): FOLLOW_REQUEST_ERROR = 60 # Seconds, till error comes up, if device does not follow the command FOLLOW_KEYS = ["current_heating_setpoint", ] # - BATTERY_LVL_WARNING = 10 - BATTERY_LVL_ERROR = 5 + BATTERY_LVL_WARNING = 20 + BATTERY_LVL_ERROR = 10 + # + LAST_MSG_WARNING = 6 * 24 * 60 * 60 + LAST_MSG_ERROR = 24 * 24 * 60 * 60 def __init__(self, mqtt_client: mqtt.mqtt_client, topic): self.topic = topic @@ -25,6 +28,8 @@ class base(object): mqtt_client.add_callback(topic, self.__rx__) mqtt_client.add_callback(topic + '/#', self.__rx__) # + self.last_device_msg = None + # self.__target_storage__ = {} self.__state_storage__ = {} # @@ -45,9 +50,24 @@ class base(object): def status(self, key): # + # HEARTBEAT + # + if key == "heartbeat": + if self.last_device_msg is None: + return {"status": nagios.Nagios.UNKNOWN, "msg": "Device exists, but no data received or unknown monitoring"} + else: + dt = time.time() - self.last_device_msg + dt_disp = dt / 60 / 60 + if dt > self.LAST_MSG_ERROR: + return {"status": nagios.Nagios.ERROR, "msg": "Last message %.1fh ago" % dt_disp} + elif dt > self.LAST_MSG_WARNING: + return {"status": nagios.Nagios.WARNING, "msg": "Last message %.1fh ago" % dt_disp} + else: + return {"status": nagios.Nagios.OK, "msg": "Last message %.1fh ago" % dt_disp} + # # FOLLOW SETPOINT # - if key in self.FOLLOW_KEYS: + elif key in self.FOLLOW_KEYS: tm_s, value_s = self.__state_storage__.get(key, (0, None)) try: tm_t, value_t = self.__target_storage__[key] @@ -107,16 +127,30 @@ class livarno_sw_br_ct(base): class brennenstuhl_heatingvalve(base): + BATTERY_LVL_WARNING = 10 + BATTERY_LVL_ERROR = 5 + def __init__(self, mqtt_client: mqtt.mqtt_client, topic): base.__init__(self, mqtt_client, topic) def __rx__(self, client, userdata, message): payload = json.loads(message.payload) + # + # heartbeat + # + if message.topic == self.topic: + self.last_device_msg = time.time() + # + # follow setpoint + # if "current_heating_setpoint" in payload: if message.topic == self.topic + '/set': self.target("current_heating_setpoint", payload["current_heating_setpoint"]) if message.topic == self.topic: self.state("current_heating_setpoint", payload["current_heating_setpoint"]) + # + # battery level + # if "battery" in payload and message.topic == self.topic: self.battery = payload["battery"] diff --git a/z_server/z_protocol.py b/z_server/z_protocol.py index 37b5cd4..a2d9328 100644 --- a/z_server/z_protocol.py +++ b/z_server/z_protocol.py @@ -4,6 +4,7 @@ import socket_protocol DID_FOLLOWS_HEATING_SETPOINT = 'current_heating_setpoint' DID_BATTERY_LEVEL = 'battery' +DID_HEARTBEAT = 'heartbeat' class server(socket_protocol.pure_json_protocol): @@ -18,6 +19,7 @@ class server(socket_protocol.pure_json_protocol): if not self.__comm_inst__.IS_CLIENT: self.register_callback(socket_protocol.SID_READ_REQUEST, DID_FOLLOWS_HEATING_SETPOINT, self.device_status) self.register_callback(socket_protocol.SID_READ_REQUEST, DID_BATTERY_LEVEL, self.device_status) + self.register_callback(socket_protocol.SID_READ_REQUEST, DID_HEARTBEAT, self.device_status) def device_status(self, msg): if msg.get_status() == socket_protocol.STATUS_OKAY: