Nagios Plugins
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. import json
  2. import logging
  3. import mqtt
  4. import nagios
  5. import time
  6. try:
  7. from config import APP_NAME as ROOT_LOGGER_NAME
  8. except ImportError:
  9. ROOT_LOGGER_NAME = 'root'
  10. logger = logging.getLogger(ROOT_LOGGER_NAME).getChild(__name__)
  11. class base(object):
  12. FOLLOW_REQUEST_WARNING = 5 # Seconds, till warning comes up, if device does not follow the command
  13. FOLLOW_REQUEST_ERROR = 60 # Seconds, till error comes up, if device does not follow the command
  14. FOLLOW_KEYS = ["current_heating_setpoint", ]
  15. #
  16. BATTERY_LVL_WARNING = 15
  17. BATTERY_LVL_ERROR = 5
  18. #
  19. LAST_MSG_WARNING = 6 * 24 * 60 * 60
  20. LAST_MSG_ERROR = 24 * 24 * 60 * 60
  21. def __init__(self, mqtt_client: mqtt.mqtt_client, topic):
  22. self.topic = topic
  23. #
  24. mqtt_client.add_callback(topic, self.__rx__)
  25. mqtt_client.add_callback(topic + '/#', self.__rx__)
  26. #
  27. self.last_device_msg = None
  28. #
  29. self.__target_storage__ = {}
  30. self.__state_storage__ = {}
  31. #
  32. self.battery = None
  33. def __rx__(self, client, userdata, message):
  34. pass
  35. def target(self, key, value):
  36. tm_t, value_t = self.__target_storage__.get(key, (0, None))
  37. if value != value_t:
  38. self.__target_storage__[key] = time.time(), value
  39. logger.debug("Target value for device identified: %s: %s", key, repr(value))
  40. def state(self, key, value):
  41. self.__state_storage__[key] = time.time(), value
  42. logger.debug("Device state identified: %s: %s", key, repr(value))
  43. def status(self, key):
  44. #
  45. # HEARTBEAT
  46. #
  47. if key == "heartbeat":
  48. if self.last_device_msg is None:
  49. return {"status": nagios.Nagios.UNKNOWN, "msg": "Device exists, but no data received or unknown monitoring"}
  50. else:
  51. dt = time.time() - self.last_device_msg
  52. dt_disp = dt / 60 / 60
  53. if dt > self.LAST_MSG_ERROR:
  54. return {"status": nagios.Nagios.ERROR, "msg": "Last message %.1fh ago" % dt_disp}
  55. elif dt > self.LAST_MSG_WARNING:
  56. return {"status": nagios.Nagios.WARNING, "msg": "Last message %.1fh ago" % dt_disp}
  57. else:
  58. return {"status": nagios.Nagios.OK, "msg": "Last message %.1fh ago" % dt_disp}
  59. #
  60. # FOLLOW SETPOINT
  61. #
  62. elif key in self.FOLLOW_KEYS:
  63. tm_s, value_s = self.__state_storage__.get(key, (0, None))
  64. try:
  65. tm_t, value_t = self.__target_storage__[key]
  66. except KeyError:
  67. if value_s is not None:
  68. return {"status": nagios.Nagios.WARNING, "msg": "Current temperature setpoint %.1f°C (age=%.1fs), but never received a setpoint" % (value_s, time.time()-tm_s)}
  69. return {"status": nagios.Nagios.UNKNOWN, "msg": "Device exists, but no data received or unknown monitoring"}
  70. else:
  71. tm = time.time()
  72. dt = tm - tm_t
  73. if value_t != value_s and dt > self.FOLLOW_REQUEST_ERROR:
  74. return {"status": nagios.Nagios.ERROR, "msg": "Requested setpoint unequal valve setpoint since %.1f°C (age=%.1fs)" % (value_s, time.time()-tm_s)}
  75. elif value_t != value_s and dt > self.FOLLOW_REQUEST_WARNING:
  76. return {"status": nagios.Nagios.WARNING, "msg": "Requested setpoint unequal valve setpoint since %.1f°C (age=%.1fs)" % (value_s, time.time()-tm_s)}
  77. return {"status": nagios.Nagios.OK, "msg": "Requested setpoint equal valve setpoint %.1f°C (age=%.1fs)" % (value_s, time.time()-tm_s)}
  78. #
  79. # BATTERY
  80. #
  81. elif key == "battery":
  82. if self.battery is None:
  83. return {"status": nagios.Nagios.UNKNOWN, "msg": "Device exists, but no data received or unknown monitoring"}
  84. elif self.battery <= self.BATTERY_LVL_ERROR:
  85. return {"status": nagios.Nagios.ERROR, "msg": "Battery level critical low (%.1f%%)" % self.battery}
  86. elif self.battery <= self.BATTERY_LVL_WARNING:
  87. return {"status": nagios.Nagios.WARNING, "msg": "Battery level low (%.1f%%)" % self.battery}
  88. else:
  89. return {"status": nagios.Nagios.OK, "msg": "Battery okay (%.1f%%)" % self.battery}
  90. class group(object):
  91. def __init__(self, *args, **kwargs):
  92. pass
  93. class shelly_sw1(base):
  94. pass
  95. class tradfri_sw(base):
  96. pass
  97. class tradfri_sw_br(base):
  98. pass
  99. class tradfri_sw_br_ct(base):
  100. pass
  101. class tradfri_button(base):
  102. def __rx__(self, client, userdata, message):
  103. try:
  104. payload = json.loads(message.payload)
  105. except json.decoder.JSONDecodeError:
  106. logger.warning("JSON decode error %s", self.topic)
  107. else:
  108. #
  109. # heartbeat
  110. #
  111. if message.topic == self.topic:
  112. self.last_device_msg = time.time()
  113. #
  114. # battery level
  115. #
  116. if "battery" in payload and message.topic == self.topic:
  117. self.battery = payload["battery"]
  118. class livarno_sw_br_ct(base):
  119. pass
  120. class brennenstuhl_heatingvalve(base):
  121. BATTERY_LVL_WARNING = 4
  122. BATTERY_LVL_ERROR = 3
  123. def __rx__(self, client, userdata, message):
  124. try:
  125. payload = json.loads(message.payload)
  126. except json.decoder.JSONDecodeError:
  127. logger.warning("JSON decode error %s", self.topic)
  128. else:
  129. #
  130. # heartbeat
  131. #
  132. if message.topic == self.topic:
  133. self.last_device_msg = time.time()
  134. #
  135. # follow setpoint
  136. #
  137. if "current_heating_setpoint" in payload:
  138. if message.topic == self.topic + '/set':
  139. self.target("current_heating_setpoint", payload["current_heating_setpoint"])
  140. if message.topic == self.topic:
  141. self.state("current_heating_setpoint", payload["current_heating_setpoint"])
  142. #
  143. # battery level
  144. #
  145. if "battery" in payload and message.topic == self.topic:
  146. self.battery = payload["battery"]
  147. class silvercrest_powerplug(base):
  148. pass
  149. class silvercrest_motion_sensor(base):
  150. def __rx__(self, client, userdata, message):
  151. try:
  152. payload = json.loads(message.payload)
  153. except json.decoder.JSONDecodeError:
  154. logger.warning("JSON decode error %s", self.topic)
  155. else:
  156. #
  157. # heartbeat
  158. #
  159. if message.topic == self.topic:
  160. self.last_device_msg = time.time()
  161. #
  162. # battery level
  163. #
  164. if "battery" in payload and message.topic == self.topic:
  165. self.battery = payload["battery"]
  166. class my_powerplug(base):
  167. pass
  168. class audio_status(base):
  169. pass
  170. class remote(base):
  171. pass