|
@@ -3,6 +3,7 @@ import logging
|
3
|
3
|
import mqtt
|
4
|
4
|
import nagios
|
5
|
5
|
import time
|
|
6
|
+from z_protocol import DID_ACTOR, DID_BATTERY_LEVEL, DID_FOLLOWS_SETPOINT, DID_HEARTBEAT, DID_LINKQUALITY
|
6
|
7
|
|
7
|
8
|
try:
|
8
|
9
|
from config import APP_NAME as ROOT_LOGGER_NAME
|
|
@@ -12,14 +13,13 @@ logger = logging.getLogger(ROOT_LOGGER_NAME).getChild(__name__)
|
12
|
13
|
|
13
|
14
|
|
14
|
15
|
class base(object):
|
15
|
|
- MONITORING_HEARTBEAT = "heartbeat"
|
16
|
|
- MONITORING_BATTERY = "battery"
|
17
|
|
- MONITORING_FOLLOW_SETPOINT = "follow_setpoint"
|
18
|
|
- MONITORING_LINKQUALITY = "linkquality"
|
|
16
|
+ KEY_BATTERY = 'battery'
|
|
17
|
+ KEY_CURRENT_VALUE = None
|
|
18
|
+ KEY_LINKQUALITY = 'linkquality'
|
|
19
|
+ KEY_SETPOINT = None
|
19
|
20
|
#
|
20
|
21
|
FOLLOW_REQUEST_WARNING = 5 # Seconds, till warning comes up, if device does not follow the command
|
21
|
22
|
FOLLOW_REQUEST_ERROR = 60 # Seconds, till error comes up, if device does not follow the command
|
22
|
|
- FOLLOW_KEY = None
|
23
|
23
|
#
|
24
|
24
|
BATTERY_LVL_WARNING = 15
|
25
|
25
|
BATTERY_LVL_ERROR = 5
|
|
@@ -42,9 +42,6 @@ class base(object):
|
42
|
42
|
#
|
43
|
43
|
self.__target_storage__ = {}
|
44
|
44
|
self.__state_storage__ = {}
|
45
|
|
- #
|
46
|
|
- self.battery = None
|
47
|
|
- self.linkquality = None
|
48
|
45
|
|
49
|
46
|
def __rx__(self, client, userdata, message):
|
50
|
47
|
try:
|
|
@@ -54,28 +51,22 @@ class base(object):
|
54
|
51
|
else:
|
55
|
52
|
if type(payload) is dict:
|
56
|
53
|
#
|
57
|
|
- # heartbeat
|
|
54
|
+ # Device values
|
58
|
55
|
#
|
59
|
56
|
if message.topic == self.topic:
|
60
|
|
- self.last_device_msg = time.time()
|
61
|
|
- #
|
62
|
|
- # follow setpoint
|
63
|
|
- #
|
64
|
|
- if self.FOLLOW_KEY is not None and self.FOLLOW_KEY in payload:
|
65
|
|
- if message.topic == self.topic + '/set':
|
66
|
|
- self.target(self.FOLLOW_KEY, payload[self.FOLLOW_KEY])
|
67
|
|
- if message.topic == self.topic:
|
68
|
|
- self.state(self.FOLLOW_KEY, payload[self.FOLLOW_KEY])
|
|
57
|
+ for key in [self.KEY_BATTERY, self.KEY_CURRENT_VALUE, self.KEY_LINKQUALITY, self.KEY_SETPOINT]:
|
|
58
|
+ if key in payload:
|
|
59
|
+ self.state(key, payload[key])
|
69
|
60
|
#
|
70
|
|
- # battery level
|
|
61
|
+ # Device setpoint
|
71
|
62
|
#
|
72
|
|
- if self.MONITORING_BATTERY in payload and message.topic == self.topic:
|
73
|
|
- self.battery = payload[self.MONITORING_BATTERY]
|
|
63
|
+ if message.topic == self.topic + '/set' and self.KEY_SETPOINT in payload:
|
|
64
|
+ self.target(self.KEY_SETPOINT, payload[self.KEY_SETPOINT])
|
74
|
65
|
#
|
75
|
|
- # linkquality
|
|
66
|
+ # heartbeat
|
76
|
67
|
#
|
77
|
|
- if self.MONITORING_LINKQUALITY in payload and message.topic == self.topic:
|
78
|
|
- self.linkquality = payload[self.MONITORING_LINKQUALITY]
|
|
68
|
+ if message.topic == self.topic:
|
|
69
|
+ self.last_device_msg = time.time()
|
79
|
70
|
|
80
|
71
|
def target(self, key, value):
|
81
|
72
|
tm_t, value_t = self.__target_storage__.get(key, (0, None))
|
|
@@ -89,74 +80,81 @@ class base(object):
|
89
|
80
|
|
90
|
81
|
def status(self, key):
|
91
|
82
|
#
|
|
83
|
+ # ACTOR
|
|
84
|
+ #
|
|
85
|
+ if key == DID_ACTOR:
|
|
86
|
+ return self.__nagios_return__(DID_ACTOR, nagios.Nagios.WARNING, "Not available for this device")
|
|
87
|
+ #
|
92
|
88
|
# HEARTBEAT
|
93
|
89
|
#
|
94
|
|
- if key == self.MONITORING_HEARTBEAT:
|
|
90
|
+ elif key == DID_HEARTBEAT:
|
95
|
91
|
if self.last_device_msg is None:
|
96
|
|
- return self.__nagios_return__(self.MONITORING_HEARTBEAT, nagios.Nagios.UNKNOWN, "Device exists, but no data received")
|
|
92
|
+ return self.__nagios_return__(DID_HEARTBEAT, nagios.Nagios.UNKNOWN, "Device exists, but no data received")
|
97
|
93
|
else:
|
98
|
94
|
dt = time.time() - self.last_device_msg
|
99
|
95
|
dt_disp = dt / 60 / 60
|
100
|
96
|
if dt > self.LAST_MSG_ERROR:
|
101
|
|
- return self.__nagios_return__(self.MONITORING_HEARTBEAT, nagios.Nagios.ERROR, "Last message %.1fh ago" % dt_disp)
|
|
97
|
+ return self.__nagios_return__(DID_HEARTBEAT, nagios.Nagios.ERROR, "Last message %.1fh ago" % dt_disp)
|
102
|
98
|
elif dt > self.LAST_MSG_WARNING:
|
103
|
|
- return self.__nagios_return__(self.MONITORING_HEARTBEAT, nagios.Nagios.WARNING, "Last message %.1fh ago" % dt_disp)
|
|
99
|
+ return self.__nagios_return__(DID_HEARTBEAT, nagios.Nagios.WARNING, "Last message %.1fh ago" % dt_disp)
|
104
|
100
|
else:
|
105
|
|
- return self.__nagios_return__(self.MONITORING_HEARTBEAT, nagios.Nagios.OK, "Last message %.1fh ago" % dt_disp)
|
|
101
|
+ return self.__nagios_return__(DID_HEARTBEAT, nagios.Nagios.OK, "Last message %.1fh ago" % dt_disp)
|
106
|
102
|
#
|
107
|
103
|
# FOLLOW SETPOINT
|
108
|
104
|
#
|
109
|
|
- elif key == self.MONITORING_FOLLOW_SETPOINT:
|
110
|
|
- if self.FOLLOW_KEY is None:
|
111
|
|
- return self.__nagios_return__(self.MONITORING_FOLLOW_SETPOINT, nagios.Nagios.UNKNOWN, "Device exist, but does not follow any setpoint.", force=True)
|
112
|
|
- tm_s, value_s = self.__state_storage__.get(self.FOLLOW_KEY, (0, None))
|
|
105
|
+ elif key == DID_FOLLOWS_SETPOINT:
|
|
106
|
+ if self.KEY_SETPOINT is None:
|
|
107
|
+ return self.__nagios_return__(DID_FOLLOWS_SETPOINT, nagios.Nagios.UNKNOWN, "Device exist, but does not follow any setpoint.", force=True)
|
|
108
|
+ tm_s, value_s = self.__state_storage__.get(self.KEY_SETPOINT, (0, None))
|
113
|
109
|
try:
|
114
|
|
- tm_t, value_t = self.__target_storage__[self.FOLLOW_KEY]
|
|
110
|
+ tm_t, value_t = self.__target_storage__[self.KEY_SETPOINT]
|
115
|
111
|
except KeyError:
|
116
|
112
|
if value_s is not None:
|
117
|
|
- 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)
|
118
|
|
- return self.__nagios_return__(self.MONITORING_FOLLOW_SETPOINT, nagios.Nagios.UNKNOWN, "Device exists, but no data received")
|
|
113
|
+ 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)
|
|
114
|
+ return self.__nagios_return__(DID_FOLLOWS_SETPOINT, nagios.Nagios.UNKNOWN, "Device exists, but no data received")
|
119
|
115
|
else:
|
120
|
116
|
tm = time.time()
|
121
|
117
|
dt = tm - tm_t
|
122
|
118
|
if value_t != value_s and dt > self.FOLLOW_REQUEST_ERROR:
|
123
|
|
- 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))
|
|
119
|
+ 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))
|
124
|
120
|
elif value_t != value_s and dt > self.FOLLOW_REQUEST_WARNING:
|
125
|
|
- 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)))
|
126
|
|
- return self.__nagios_return__(self.MONITORING_FOLLOW_SETPOINT, nagios.Nagios.OK, "Requested setpoint equal valve setpoint %.1f°C" % value_s)
|
|
121
|
+ 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)))
|
|
122
|
+ return self.__nagios_return__(DID_FOLLOWS_SETPOINT, nagios.Nagios.OK, "Requested setpoint equal valve setpoint %.1f°C" % value_s)
|
127
|
123
|
#
|
128
|
124
|
# BATTERY
|
129
|
125
|
#
|
130
|
|
- elif key == self.MONITORING_BATTERY:
|
131
|
|
- if self.battery is None:
|
132
|
|
- return self.__nagios_return__(self.MONITORING_BATTERY, nagios.Nagios.UNKNOWN, "Device exists, but no data received or unknown monitoring")
|
133
|
|
- elif self.battery <= self.BATTERY_LVL_ERROR:
|
134
|
|
- return self.__nagios_return__(self.MONITORING_BATTERY, nagios.Nagios.ERROR, "Battery level critical low (%.1f%%)" % self.battery)
|
135
|
|
- elif self.battery <= self.BATTERY_LVL_WARNING:
|
136
|
|
- return self.__nagios_return__(self.MONITORING_BATTERY, nagios.Nagios.WARNING, "Battery level low (%.1f%%)" % self.battery)
|
|
126
|
+ elif key == DID_BATTERY_LEVEL:
|
|
127
|
+ battery_lvl = self.__state_storage__.get(self.KEY_BATTERY, (0, None))[1]
|
|
128
|
+ if battery_lvl is None:
|
|
129
|
+ return self.__nagios_return__(DID_BATTERY_LEVEL, nagios.Nagios.UNKNOWN, "Device exists, but no data received or unknown monitoring")
|
|
130
|
+ elif battery_lvl <= self.BATTERY_LVL_ERROR:
|
|
131
|
+ return self.__nagios_return__(DID_BATTERY_LEVEL, nagios.Nagios.ERROR, "Battery level critical low (%.1f%%)" % battery_lvl)
|
|
132
|
+ elif battery_lvl <= self.BATTERY_LVL_WARNING:
|
|
133
|
+ return self.__nagios_return__(DID_BATTERY_LEVEL, nagios.Nagios.WARNING, "Battery level low (%.1f%%)" % battery_lvl)
|
137
|
134
|
else:
|
138
|
|
- return self.__nagios_return__(self.MONITORING_BATTERY, nagios.Nagios.OK, "Battery okay (%.1f%%)" % self.battery)
|
|
135
|
+ return self.__nagios_return__(DID_BATTERY_LEVEL, nagios.Nagios.OK, "Battery okay (%.1f%%)" % battery_lvl)
|
139
|
136
|
#
|
140
|
137
|
# LINKQUALITY
|
141
|
138
|
#
|
142
|
|
- elif key == self.MONITORING_LINKQUALITY:
|
143
|
|
- if self.linkquality is None:
|
144
|
|
- return self.__nagios_return__(self.MONITORING_LINKQUALITY, nagios.Nagios.UNKNOWN, "Device exists, but no data received or unknown monitoring")
|
145
|
|
- elif self.linkquality <= self.LINKQUALITY_ERROR:
|
146
|
|
- return self.__nagios_return__(self.MONITORING_LINKQUALITY, nagios.Nagios.ERROR, "Linkquality critical low (%d)" % self.linkquality)
|
147
|
|
- elif self.linkquality <= self.LINKQUALITY_WARNING:
|
148
|
|
- return self.__nagios_return__(self.MONITORING_LINKQUALITY, nagios.Nagios.WARNING, "Linkquality level low (%d)" % self.linkquality)
|
|
139
|
+ elif key == DID_LINKQUALITY:
|
|
140
|
+ linkquality = self.__state_storage__.get(self.KEY_LINKQUALITY, (0, None))[1]
|
|
141
|
+ if linkquality is None:
|
|
142
|
+ return self.__nagios_return__(DID_LINKQUALITY, nagios.Nagios.UNKNOWN, "Device exists, but no data received or unknown monitoring")
|
|
143
|
+ elif linkquality <= self.LINKQUALITY_ERROR:
|
|
144
|
+ return self.__nagios_return__(DID_LINKQUALITY, nagios.Nagios.ERROR, "Linkquality critical low (%d)" % linkquality)
|
|
145
|
+ elif linkquality <= self.LINKQUALITY_WARNING:
|
|
146
|
+ return self.__nagios_return__(DID_LINKQUALITY, nagios.Nagios.WARNING, "Linkquality level low (%d)" % linkquality)
|
149
|
147
|
else:
|
150
|
|
- return self.__nagios_return__(self.MONITORING_LINKQUALITY, nagios.Nagios.OK, "Linkquality okay (%d)" % self.linkquality)
|
|
148
|
+ return self.__nagios_return__(DID_LINKQUALITY, nagios.Nagios.OK, "Linkquality okay (%d)" % linkquality)
|
151
|
149
|
|
152
|
|
- def __nagios_return__(self, monitoring_name, status, msg, force=False):
|
|
150
|
+ def __nagios_return__(self, did, status, msg, force=False):
|
153
|
151
|
tm = time.time()
|
154
|
|
- if monitoring_name not in self.__unknown_tm__:
|
155
|
|
- self.__unknown_tm__[monitoring_name] = None
|
|
152
|
+ if did not in self.__unknown_tm__:
|
|
153
|
+ self.__unknown_tm__[did] = None
|
156
|
154
|
if status == nagios.Nagios.UNKNOWN and not force:
|
157
|
|
- if self.__unknown_tm__[monitoring_name] is None:
|
158
|
|
- self.__unknown_tm__[monitoring_name] = tm
|
159
|
|
- dt = tm - self.__unknown_tm__[monitoring_name]
|
|
155
|
+ if self.__unknown_tm__[did] is None:
|
|
156
|
+ self.__unknown_tm__[did] = tm
|
|
157
|
+ dt = tm - self.__unknown_tm__[did]
|
160
|
158
|
if dt >= self.LAST_MSG_ERROR:
|
161
|
159
|
status = nagios.Nagios.UNKNOWN
|
162
|
160
|
elif dt >= self.LAST_MSG_WARNING:
|
|
@@ -165,7 +163,7 @@ class base(object):
|
165
|
163
|
status = nagios.Nagios.OK
|
166
|
164
|
msg += " - since %.1fh" % (dt / 3600)
|
167
|
165
|
else:
|
168
|
|
- self.__unknown_tm__[monitoring_name] = None
|
|
166
|
+ self.__unknown_tm__[did] = None
|
169
|
167
|
return {"status": status, "msg": msg}
|
170
|
168
|
|
171
|
169
|
|
|
@@ -202,7 +200,33 @@ class livarno_sw_br_ct(base):
|
202
|
200
|
class brennenstuhl_heatingvalve(base):
|
203
|
201
|
BATTERY_LVL_WARNING = 4
|
204
|
202
|
BATTERY_LVL_ERROR = 3
|
205
|
|
- FOLLOW_KEY = "current_heating_setpoint"
|
|
203
|
+ #
|
|
204
|
+ ACTOR_WARN_OFFSET = 1.5
|
|
205
|
+ ACTOR_ERR_OFFSET = 2.5
|
|
206
|
+ #
|
|
207
|
+ KEY_SETPOINT = "current_heating_setpoint"
|
|
208
|
+ KEY_CURRENT_VALUE = "local_temperature"
|
|
209
|
+
|
|
210
|
+ def status(self, key):
|
|
211
|
+ #
|
|
212
|
+ # ACTOR
|
|
213
|
+ #
|
|
214
|
+ if key == DID_ACTOR:
|
|
215
|
+ tm_s, value_s = self.__state_storage__.get(self.KEY_SETPOINT, (0, None))
|
|
216
|
+ tm_c, value_c = self.__state_storage__.get(self.KEY_CURRENT_VALUE, (0, None))
|
|
217
|
+ #
|
|
218
|
+ if value_s is None or value_c is None:
|
|
219
|
+ return self.__nagios_return__(DID_ACTOR, nagios.Nagios.UNKNOWN, "Device exists, but no data received")
|
|
220
|
+ elif value_s <= 5:
|
|
221
|
+ return self.__nagios_return__(DID_ACTOR, nagios.Nagios.OK, "No monitoring in Summer Mode")
|
|
222
|
+ elif value_c > value_s + self.ACTOR_ERR_OFFSET:
|
|
223
|
+ return self.__nagios_return__(DID_ACTOR, nagios.Nagios.ERROR, "Current Temperature much to high %.1f°C > %.1f°C" % (value_c, value_s))
|
|
224
|
+ elif value_c > value_s + self.ACTOR_WARN_OFFSET:
|
|
225
|
+ return self.__nagios_return__(DID_ACTOR, nagios.Nagios.WARNING, "Current Temperature to high %.1f°C > %.1f°C" % (value_c, value_s))
|
|
226
|
+ else:
|
|
227
|
+ return self.__nagios_return__(DID_ACTOR, nagios.Nagios.OK, "Current Temperature okay %.1f°C > %.1f°C" % (value_c, value_s))
|
|
228
|
+ else:
|
|
229
|
+ return super().status(key)
|
206
|
230
|
|
207
|
231
|
|
208
|
232
|
class silvercrest_powerplug(base):
|