Inital check_z_actor added + refactoring

This commit is contained in:
Dirk Alders 2024-07-14 18:17:50 +02:00
parent 51c0b9eaa9
commit 5a9b7a1847
6 changed files with 116 additions and 88 deletions

1
check_z_actor Symbolic link
View File

@ -0,0 +1 @@
check_z_heartbeat

View File

@ -3,11 +3,12 @@
import argparse import argparse
import nagios import nagios
import os
import time import time
from z_server import config from z_server import config
from z_server import tcp_socket from z_server import tcp_socket
from z_server.z_protocol import server as client_prot from z_server.z_protocol import server as client_prot
from z_server.z_protocol import DID_FOLLOWS_SETPOINT, DID_BATTERY_LEVEL, DID_HEARTBEAT, DID_LINKQUALITY from z_server.z_protocol import DIDS
from z_server import socket_protocol from z_server import socket_protocol
import sys import sys
@ -32,19 +33,14 @@ if __name__ == '__main__':
"fun": args.fun "fun": args.fun
} }
# #
if sys.argv[0].endswith('check_z_heartbeat'):
sp.send(socket_protocol.SID_READ_REQUEST, DID_HEARTBEAT, data) did = os.path.basename(sys.argv[0])[8:]
sp_data = sp.receive(socket_protocol.SID_READ_RESPONSE, DID_HEARTBEAT).get_data() #
elif sys.argv[0].endswith('check_z_battery'): if did not in DIDS:
sp.send(socket_protocol.SID_READ_REQUEST, DID_BATTERY_LEVEL, data) print("Unknown data id %s. You might add it in z_server.z_protocol." % did)
sp_data = sp.receive(socket_protocol.SID_READ_RESPONSE, DID_BATTERY_LEVEL).get_data()
elif sys.argv[0].endswith('check_z_linkquality'):
sp.send(socket_protocol.SID_READ_REQUEST, DID_LINKQUALITY, data)
sp_data = sp.receive(socket_protocol.SID_READ_RESPONSE, DID_LINKQUALITY).get_data()
elif sys.argv[0].endswith('check_z_follow'):
sp.send(socket_protocol.SID_READ_REQUEST, DID_FOLLOWS_SETPOINT, data)
sp_data = sp.receive(socket_protocol.SID_READ_RESPONSE, DID_FOLLOWS_SETPOINT).get_data()
else:
sys.stderr.write('No action for command called "%s"\n' % sys.argv[0])
sys.exit(100) sys.exit(100)
nagios.Nagios().exit(**sp_data) else:
sp.send(socket_protocol.SID_READ_REQUEST, did, data)
sp_data = sp.receive(socket_protocol.SID_READ_RESPONSE, did).get_data() or {
"status": 101, "msg": "No answer from device for \"%s\". You might want to add it in z_server.devices" % did}
nagios.Nagios().exit(**sp_data)

View File

@ -1 +1 @@
check_z_follow check_z_heartbeat

View File

@ -3,6 +3,7 @@ import logging
import mqtt import mqtt
import nagios import nagios
import time import time
from z_protocol import DID_ACTOR, DID_BATTERY_LEVEL, DID_FOLLOWS_SETPOINT, DID_HEARTBEAT, DID_LINKQUALITY
try: try:
from config import APP_NAME as ROOT_LOGGER_NAME from config import APP_NAME as ROOT_LOGGER_NAME
@ -12,14 +13,13 @@ logger = logging.getLogger(ROOT_LOGGER_NAME).getChild(__name__)
class base(object): class base(object):
MONITORING_HEARTBEAT = "heartbeat" KEY_BATTERY = 'battery'
MONITORING_BATTERY = "battery" KEY_CURRENT_VALUE = None
MONITORING_FOLLOW_SETPOINT = "follow_setpoint" KEY_LINKQUALITY = 'linkquality'
MONITORING_LINKQUALITY = "linkquality" KEY_SETPOINT = None
# #
FOLLOW_REQUEST_WARNING = 5 # Seconds, till warning comes up, if device does not follow the command FOLLOW_REQUEST_WARNING = 5 # Seconds, till warning comes up, if device does not follow the command
FOLLOW_REQUEST_ERROR = 60 # Seconds, till error comes up, if device does not follow the command FOLLOW_REQUEST_ERROR = 60 # Seconds, till error comes up, if device does not follow the command
FOLLOW_KEY = None
# #
BATTERY_LVL_WARNING = 15 BATTERY_LVL_WARNING = 15
BATTERY_LVL_ERROR = 5 BATTERY_LVL_ERROR = 5
@ -42,9 +42,6 @@ class base(object):
# #
self.__target_storage__ = {} self.__target_storage__ = {}
self.__state_storage__ = {} self.__state_storage__ = {}
#
self.battery = None
self.linkquality = None
def __rx__(self, client, userdata, message): def __rx__(self, client, userdata, message):
try: try:
@ -54,28 +51,22 @@ class base(object):
else: else:
if type(payload) is dict: if type(payload) is dict:
# #
# Device values
#
if message.topic == self.topic:
for key in [self.KEY_BATTERY, self.KEY_CURRENT_VALUE, self.KEY_LINKQUALITY, self.KEY_SETPOINT]:
if key in payload:
self.state(key, payload[key])
#
# Device setpoint
#
if message.topic == self.topic + '/set' and self.KEY_SETPOINT in payload:
self.target(self.KEY_SETPOINT, payload[self.KEY_SETPOINT])
#
# heartbeat # heartbeat
# #
if message.topic == self.topic: if message.topic == self.topic:
self.last_device_msg = time.time() self.last_device_msg = time.time()
#
# follow setpoint
#
if self.FOLLOW_KEY is not None and self.FOLLOW_KEY in payload:
if message.topic == self.topic + '/set':
self.target(self.FOLLOW_KEY, payload[self.FOLLOW_KEY])
if message.topic == self.topic:
self.state(self.FOLLOW_KEY, payload[self.FOLLOW_KEY])
#
# battery level
#
if self.MONITORING_BATTERY in payload and message.topic == self.topic:
self.battery = payload[self.MONITORING_BATTERY]
#
# linkquality
#
if self.MONITORING_LINKQUALITY in payload and message.topic == self.topic:
self.linkquality = payload[self.MONITORING_LINKQUALITY]
def target(self, key, value): def target(self, key, value):
tm_t, value_t = self.__target_storage__.get(key, (0, None)) tm_t, value_t = self.__target_storage__.get(key, (0, None))
@ -89,74 +80,81 @@ class base(object):
def status(self, key): def status(self, key):
# #
# ACTOR
#
if key == DID_ACTOR:
return self.__nagios_return__(DID_ACTOR, nagios.Nagios.WARNING, "Not available for this device")
#
# HEARTBEAT # HEARTBEAT
# #
if key == self.MONITORING_HEARTBEAT: elif key == DID_HEARTBEAT:
if self.last_device_msg is None: if self.last_device_msg is None:
return self.__nagios_return__(self.MONITORING_HEARTBEAT, nagios.Nagios.UNKNOWN, "Device exists, but no data received") return self.__nagios_return__(DID_HEARTBEAT, nagios.Nagios.UNKNOWN, "Device exists, but no data received")
else: else:
dt = time.time() - self.last_device_msg dt = time.time() - self.last_device_msg
dt_disp = dt / 60 / 60 dt_disp = dt / 60 / 60
if dt > self.LAST_MSG_ERROR: if dt > self.LAST_MSG_ERROR:
return self.__nagios_return__(self.MONITORING_HEARTBEAT, nagios.Nagios.ERROR, "Last message %.1fh ago" % dt_disp) return self.__nagios_return__(DID_HEARTBEAT, nagios.Nagios.ERROR, "Last message %.1fh ago" % dt_disp)
elif dt > self.LAST_MSG_WARNING: elif dt > self.LAST_MSG_WARNING:
return self.__nagios_return__(self.MONITORING_HEARTBEAT, nagios.Nagios.WARNING, "Last message %.1fh ago" % dt_disp) return self.__nagios_return__(DID_HEARTBEAT, nagios.Nagios.WARNING, "Last message %.1fh ago" % dt_disp)
else: else:
return self.__nagios_return__(self.MONITORING_HEARTBEAT, nagios.Nagios.OK, "Last message %.1fh ago" % dt_disp) return self.__nagios_return__(DID_HEARTBEAT, nagios.Nagios.OK, "Last message %.1fh ago" % dt_disp)
# #
# FOLLOW SETPOINT # FOLLOW SETPOINT
# #
elif key == self.MONITORING_FOLLOW_SETPOINT: elif key == DID_FOLLOWS_SETPOINT:
if self.FOLLOW_KEY is None: if self.KEY_SETPOINT is None:
return self.__nagios_return__(self.MONITORING_FOLLOW_SETPOINT, nagios.Nagios.UNKNOWN, "Device exist, but does not follow any setpoint.", force=True) return self.__nagios_return__(DID_FOLLOWS_SETPOINT, nagios.Nagios.UNKNOWN, "Device exist, but does not follow any setpoint.", force=True)
tm_s, value_s = self.__state_storage__.get(self.FOLLOW_KEY, (0, None)) tm_s, value_s = self.__state_storage__.get(self.KEY_SETPOINT, (0, None))
try: try:
tm_t, value_t = self.__target_storage__[self.FOLLOW_KEY] tm_t, value_t = self.__target_storage__[self.KEY_SETPOINT]
except KeyError: except KeyError:
if value_s is not None: if value_s is not None:
return self.__nagios_return__(self.MONITORING_FOLLOW_SETPOINT, nagios.Nagios.OK, "Current temperature setpoint %.1f°C, but never received a setpoint. That might be okay." % value_s) return self.__nagios_return__(DID_FOLLOWS_SETPOINT, nagios.Nagios.OK, "Current temperature setpoint %.1f°C, but never received a setpoint. That might be okay." % value_s)
return self.__nagios_return__(self.MONITORING_FOLLOW_SETPOINT, nagios.Nagios.UNKNOWN, "Device exists, but no data received") return self.__nagios_return__(DID_FOLLOWS_SETPOINT, nagios.Nagios.UNKNOWN, "Device exists, but no data received")
else: else:
tm = time.time() tm = time.time()
dt = tm - tm_t dt = tm - tm_t
if value_t != value_s and dt > self.FOLLOW_REQUEST_ERROR: if value_t != value_s and dt > self.FOLLOW_REQUEST_ERROR:
return self.__nagios_return__(self.MONITORING_FOLLOW_SETPOINT, nagios.Nagios.ERROR, "Requested setpoint %.1f°C unequal valve setpoint %.1f°C since %.1fmin" % (value_t, value_s, (time.time()-tm_s)/60)) return self.__nagios_return__(DID_FOLLOWS_SETPOINT, nagios.Nagios.ERROR, "Requested setpoint %.1f°C unequal valve setpoint %.1f°C since %.1fmin" % (value_t, value_s, (time.time()-tm_s)/60))
elif value_t != value_s and dt > self.FOLLOW_REQUEST_WARNING: elif value_t != value_s and dt > self.FOLLOW_REQUEST_WARNING:
return self.__nagios_return__(self.MONITORING_FOLLOW_SETPOINT, nagios.Nagios.WARNING, "Requested setpoint %.1f°C unequal valve setpoint %.1f°C since %.1fmin" % (value_t, value_s, (time.time()-tm_s))) return self.__nagios_return__(DID_FOLLOWS_SETPOINT, nagios.Nagios.WARNING, "Requested setpoint %.1f°C unequal valve setpoint %.1f°C since %.1fmin" % (value_t, value_s, (time.time()-tm_s)))
return self.__nagios_return__(self.MONITORING_FOLLOW_SETPOINT, nagios.Nagios.OK, "Requested setpoint equal valve setpoint %.1f°C" % value_s) return self.__nagios_return__(DID_FOLLOWS_SETPOINT, nagios.Nagios.OK, "Requested setpoint equal valve setpoint %.1f°C" % value_s)
# #
# BATTERY # BATTERY
# #
elif key == self.MONITORING_BATTERY: elif key == DID_BATTERY_LEVEL:
if self.battery is None: battery_lvl = self.__state_storage__.get(self.KEY_BATTERY, (0, None))[1]
return self.__nagios_return__(self.MONITORING_BATTERY, nagios.Nagios.UNKNOWN, "Device exists, but no data received or unknown monitoring") if battery_lvl is None:
elif self.battery <= self.BATTERY_LVL_ERROR: return self.__nagios_return__(DID_BATTERY_LEVEL, nagios.Nagios.UNKNOWN, "Device exists, but no data received or unknown monitoring")
return self.__nagios_return__(self.MONITORING_BATTERY, nagios.Nagios.ERROR, "Battery level critical low (%.1f%%)" % self.battery) elif battery_lvl <= self.BATTERY_LVL_ERROR:
elif self.battery <= self.BATTERY_LVL_WARNING: return self.__nagios_return__(DID_BATTERY_LEVEL, nagios.Nagios.ERROR, "Battery level critical low (%.1f%%)" % battery_lvl)
return self.__nagios_return__(self.MONITORING_BATTERY, nagios.Nagios.WARNING, "Battery level low (%.1f%%)" % self.battery) elif battery_lvl <= self.BATTERY_LVL_WARNING:
return self.__nagios_return__(DID_BATTERY_LEVEL, nagios.Nagios.WARNING, "Battery level low (%.1f%%)" % battery_lvl)
else: else:
return self.__nagios_return__(self.MONITORING_BATTERY, nagios.Nagios.OK, "Battery okay (%.1f%%)" % self.battery) return self.__nagios_return__(DID_BATTERY_LEVEL, nagios.Nagios.OK, "Battery okay (%.1f%%)" % battery_lvl)
# #
# LINKQUALITY # LINKQUALITY
# #
elif key == self.MONITORING_LINKQUALITY: elif key == DID_LINKQUALITY:
if self.linkquality is None: linkquality = self.__state_storage__.get(self.KEY_LINKQUALITY, (0, None))[1]
return self.__nagios_return__(self.MONITORING_LINKQUALITY, nagios.Nagios.UNKNOWN, "Device exists, but no data received or unknown monitoring") if linkquality is None:
elif self.linkquality <= self.LINKQUALITY_ERROR: return self.__nagios_return__(DID_LINKQUALITY, nagios.Nagios.UNKNOWN, "Device exists, but no data received or unknown monitoring")
return self.__nagios_return__(self.MONITORING_LINKQUALITY, nagios.Nagios.ERROR, "Linkquality critical low (%d)" % self.linkquality) elif linkquality <= self.LINKQUALITY_ERROR:
elif self.linkquality <= self.LINKQUALITY_WARNING: return self.__nagios_return__(DID_LINKQUALITY, nagios.Nagios.ERROR, "Linkquality critical low (%d)" % linkquality)
return self.__nagios_return__(self.MONITORING_LINKQUALITY, nagios.Nagios.WARNING, "Linkquality level low (%d)" % self.linkquality) elif linkquality <= self.LINKQUALITY_WARNING:
return self.__nagios_return__(DID_LINKQUALITY, nagios.Nagios.WARNING, "Linkquality level low (%d)" % linkquality)
else: else:
return self.__nagios_return__(self.MONITORING_LINKQUALITY, nagios.Nagios.OK, "Linkquality okay (%d)" % self.linkquality) return self.__nagios_return__(DID_LINKQUALITY, nagios.Nagios.OK, "Linkquality okay (%d)" % linkquality)
def __nagios_return__(self, monitoring_name, status, msg, force=False): def __nagios_return__(self, did, status, msg, force=False):
tm = time.time() tm = time.time()
if monitoring_name not in self.__unknown_tm__: if did not in self.__unknown_tm__:
self.__unknown_tm__[monitoring_name] = None self.__unknown_tm__[did] = None
if status == nagios.Nagios.UNKNOWN and not force: if status == nagios.Nagios.UNKNOWN and not force:
if self.__unknown_tm__[monitoring_name] is None: if self.__unknown_tm__[did] is None:
self.__unknown_tm__[monitoring_name] = tm self.__unknown_tm__[did] = tm
dt = tm - self.__unknown_tm__[monitoring_name] dt = tm - self.__unknown_tm__[did]
if dt >= self.LAST_MSG_ERROR: if dt >= self.LAST_MSG_ERROR:
status = nagios.Nagios.UNKNOWN status = nagios.Nagios.UNKNOWN
elif dt >= self.LAST_MSG_WARNING: elif dt >= self.LAST_MSG_WARNING:
@ -165,7 +163,7 @@ class base(object):
status = nagios.Nagios.OK status = nagios.Nagios.OK
msg += " - since %.1fh" % (dt / 3600) msg += " - since %.1fh" % (dt / 3600)
else: else:
self.__unknown_tm__[monitoring_name] = None self.__unknown_tm__[did] = None
return {"status": status, "msg": msg} return {"status": status, "msg": msg}
@ -202,7 +200,33 @@ class livarno_sw_br_ct(base):
class brennenstuhl_heatingvalve(base): class brennenstuhl_heatingvalve(base):
BATTERY_LVL_WARNING = 4 BATTERY_LVL_WARNING = 4
BATTERY_LVL_ERROR = 3 BATTERY_LVL_ERROR = 3
FOLLOW_KEY = "current_heating_setpoint" #
ACTOR_WARN_OFFSET = 1.5
ACTOR_ERR_OFFSET = 2.5
#
KEY_SETPOINT = "current_heating_setpoint"
KEY_CURRENT_VALUE = "local_temperature"
def status(self, key):
#
# ACTOR
#
if key == DID_ACTOR:
tm_s, value_s = self.__state_storage__.get(self.KEY_SETPOINT, (0, None))
tm_c, value_c = self.__state_storage__.get(self.KEY_CURRENT_VALUE, (0, None))
#
if value_s is None or value_c is None:
return self.__nagios_return__(DID_ACTOR, nagios.Nagios.UNKNOWN, "Device exists, but no data received")
elif value_s <= 5:
return self.__nagios_return__(DID_ACTOR, nagios.Nagios.OK, "No monitoring in Summer Mode")
elif value_c > value_s + self.ACTOR_ERR_OFFSET:
return self.__nagios_return__(DID_ACTOR, nagios.Nagios.ERROR, "Current Temperature much to high %.1f°C > %.1f°C" % (value_c, value_s))
elif value_c > value_s + self.ACTOR_WARN_OFFSET:
return self.__nagios_return__(DID_ACTOR, nagios.Nagios.WARNING, "Current Temperature to high %.1f°C > %.1f°C" % (value_c, value_s))
else:
return self.__nagios_return__(DID_ACTOR, nagios.Nagios.OK, "Current Temperature okay %.1f°C > %.1f°C" % (value_c, value_s))
else:
return super().status(key)
class silvercrest_powerplug(base): class silvercrest_powerplug(base):

@ -1 +1 @@
Subproject commit 328d3471a748472695a61193becdda76c7eefe69 Subproject commit 14e56ccdbf6594f699b4afcfb4acafe9b899e914

View File

@ -2,10 +2,19 @@ import nagios
import socket_protocol import socket_protocol
# from devdi.topic import topic_by_props # from devdi.topic import topic_by_props
DID_FOLLOWS_SETPOINT = 'follow_setpoint' DID_ACTOR = 'actor'
DID_BATTERY_LEVEL = 'battery' DID_BATTERY_LEVEL = 'battery'
DID_FOLLOWS_SETPOINT = 'follow'
DID_HEARTBEAT = 'heartbeat' DID_HEARTBEAT = 'heartbeat'
DID_LINKQUALITY = 'linkquality' DID_LINKQUALITY = 'linkquality'
#
DIDS = (
DID_ACTOR,
DID_BATTERY_LEVEL,
DID_FOLLOWS_SETPOINT,
DID_HEARTBEAT,
DID_LINKQUALITY
)
class server(socket_protocol.pure_json_protocol): class server(socket_protocol.pure_json_protocol):
@ -15,10 +24,8 @@ class server(socket_protocol.pure_json_protocol):
socket_protocol.pure_json_protocol.__init__(self, *args, **kwargs) socket_protocol.pure_json_protocol.__init__(self, *args, **kwargs)
# #
if not self.__comm_inst__.IS_CLIENT: if not self.__comm_inst__.IS_CLIENT:
self.register_callback(socket_protocol.SID_READ_REQUEST, DID_FOLLOWS_SETPOINT, self.device_status) for did in DIDS:
self.register_callback(socket_protocol.SID_READ_REQUEST, DID_BATTERY_LEVEL, self.device_status) self.register_callback(socket_protocol.SID_READ_REQUEST, did, self.device_status)
self.register_callback(socket_protocol.SID_READ_REQUEST, DID_LINKQUALITY, self.device_status)
self.register_callback(socket_protocol.SID_READ_REQUEST, DID_HEARTBEAT, self.device_status)
def device_status(self, msg): def device_status(self, msg):
if msg.get_status() == socket_protocol.STATUS_OKAY: if msg.get_status() == socket_protocol.STATUS_OKAY: