2023-12-12 12:44:34 +01:00
import json
import logging
import mqtt
import nagios
import time
try :
from config import APP_NAME as ROOT_LOGGER_NAME
except ImportError :
ROOT_LOGGER_NAME = ' root '
logger = logging . getLogger ( ROOT_LOGGER_NAME ) . getChild ( __name__ )
class base ( object ) :
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
2023-12-16 07:12:29 +01:00
FOLLOW_KEYS = [ " current_heating_setpoint " , ]
#
2023-12-19 07:12:56 +01:00
BATTERY_LVL_WARNING = 15
BATTERY_LVL_ERROR = 5
2023-12-16 08:16:45 +01:00
#
LAST_MSG_WARNING = 6 * 24 * 60 * 60
LAST_MSG_ERROR = 24 * 24 * 60 * 60
2023-12-12 12:44:34 +01:00
def __init__ ( self , mqtt_client : mqtt . mqtt_client , topic ) :
self . topic = topic
#
mqtt_client . add_callback ( topic , self . __rx__ )
mqtt_client . add_callback ( topic + ' /# ' , self . __rx__ )
#
2023-12-16 08:16:45 +01:00
self . last_device_msg = None
#
2023-12-12 12:44:34 +01:00
self . __target_storage__ = { }
self . __state_storage__ = { }
2023-12-16 07:12:29 +01:00
#
self . battery = None
2023-12-12 12:44:34 +01:00
def __rx__ ( self , client , userdata , message ) :
pass
def target ( self , key , value ) :
tm_t , value_t = self . __target_storage__ . get ( key , ( 0 , None ) )
if value != value_t :
self . __target_storage__ [ key ] = time . time ( ) , value
logger . debug ( " Target value for device identified: %s : %s " , key , repr ( value ) )
def state ( self , key , value ) :
2023-12-14 18:16:15 +01:00
self . __state_storage__ [ key ] = time . time ( ) , value
2023-12-12 12:44:34 +01:00
logger . debug ( " Device state identified: %s : %s " , key , repr ( value ) )
def status ( self , key ) :
2023-12-16 07:12:29 +01:00
#
2023-12-16 08:16:45 +01:00
# 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 %.1f h ago " % dt_disp }
elif dt > self . LAST_MSG_WARNING :
return { " status " : nagios . Nagios . WARNING , " msg " : " Last message %.1f h ago " % dt_disp }
else :
return { " status " : nagios . Nagios . OK , " msg " : " Last message %.1f h ago " % dt_disp }
#
2023-12-16 07:12:29 +01:00
# FOLLOW SETPOINT
#
2023-12-16 08:16:45 +01:00
elif key in self . FOLLOW_KEYS :
2023-12-16 07:12:29 +01:00
tm_s , value_s = self . __state_storage__ . get ( key , ( 0 , None ) )
try :
tm_t , value_t = self . __target_storage__ [ key ]
except KeyError :
if value_s is not None :
return { " status " : nagios . Nagios . WARNING , " msg " : " Current temperature setpoint %.1f °C (age= %.1f s), but never received a setpoint " % ( value_s , time . time ( ) - tm_s ) }
return { " status " : nagios . Nagios . UNKNOWN , " msg " : " Device exists, but no data received or unknown monitoring " }
else :
tm = time . time ( )
dt = tm - tm_t
if value_t != value_s and dt > self . FOLLOW_REQUEST_ERROR :
return { " status " : nagios . Nagios . ERROR , " msg " : " Requested setpoint unequal valve setpoint since %.1f °C (age= %.1f s) " % ( value_s , time . time ( ) - tm_s ) }
elif value_t != value_s and dt > self . FOLLOW_REQUEST_WARNING :
return { " status " : nagios . Nagios . WARNING , " msg " : " Requested setpoint unequal valve setpoint since %.1f °C (age= %.1f s) " % ( value_s , time . time ( ) - tm_s ) }
return { " status " : nagios . Nagios . OK , " msg " : " Requested setpoint equal valve setpoint %.1f °C (age= %.1f s) " % ( value_s , time . time ( ) - tm_s ) }
#
# BATTERY
#
elif key == " battery " :
if self . battery is None :
return { " status " : nagios . Nagios . UNKNOWN , " msg " : " Device exists, but no data received or unknown monitoring " }
2023-12-19 07:12:56 +01:00
elif self . battery < = self . BATTERY_LVL_ERROR :
2023-12-16 07:12:29 +01:00
return { " status " : nagios . Nagios . ERROR , " msg " : " Battery level critical low ( %.1f %% ) " % self . battery }
2023-12-19 07:12:56 +01:00
elif self . battery < = self . BATTERY_LVL_WARNING :
2023-12-16 07:12:29 +01:00
return { " status " : nagios . Nagios . WARNING , " msg " : " Battery level low ( %.1f %% ) " % self . battery }
else :
return { " status " : nagios . Nagios . OK , " msg " : " Battery okay ( %.1f %% ) " % self . battery }
2023-12-12 12:44:34 +01:00
class group ( object ) :
def __init__ ( self , * args , * * kwargs ) :
pass
class shelly_sw1 ( base ) :
pass
class tradfri_sw ( base ) :
pass
class tradfri_sw_br ( base ) :
pass
class tradfri_sw_br_ct ( base ) :
pass
class tradfri_button ( base ) :
2023-12-19 07:12:56 +01:00
def __rx__ ( self , client , userdata , message ) :
try :
payload = json . loads ( message . payload )
except json . decoder . JSONDecodeError :
logger . warning ( " JSON decode error %s " , self . topic )
else :
#
# heartbeat
#
if message . topic == self . topic :
self . last_device_msg = time . time ( )
#
# battery level
#
if " battery " in payload and message . topic == self . topic :
self . battery = payload [ " battery " ]
2023-12-12 12:44:34 +01:00
class livarno_sw_br_ct ( base ) :
pass
class brennenstuhl_heatingvalve ( base ) :
2023-12-19 07:12:56 +01:00
BATTERY_LVL_WARNING = 4
BATTERY_LVL_ERROR = 3
2023-12-12 12:44:34 +01:00
def __rx__ ( self , client , userdata , message ) :
2023-12-19 07:12:56 +01:00
try :
payload = json . loads ( message . payload )
except json . decoder . JSONDecodeError :
logger . warning ( " JSON decode error %s " , self . topic )
else :
#
# heartbeat
#
2023-12-15 19:58:54 +01:00
if message . topic == self . topic :
2023-12-19 07:12:56 +01:00
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 " ]
2023-12-12 12:44:34 +01:00
class silvercrest_powerplug ( base ) :
pass
class silvercrest_motion_sensor ( base ) :
2023-12-19 07:12:56 +01:00
def __rx__ ( self , client , userdata , message ) :
try :
payload = json . loads ( message . payload )
except json . decoder . JSONDecodeError :
logger . warning ( " JSON decode error %s " , self . topic )
else :
#
# heartbeat
#
if message . topic == self . topic :
self . last_device_msg = time . time ( )
#
# battery level
#
if " battery " in payload and message . topic == self . topic :
self . battery = payload [ " battery " ]
2023-12-12 12:44:34 +01:00
class my_powerplug ( base ) :
pass
class audio_status ( base ) :
pass
class remote ( base ) :
pass