p1.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. #!/usr/bin/env python3
  2. import itertools
  3. import json
  4. from cmk.agent_based.v2 import (
  5. AgentSection,
  6. CheckPlugin,
  7. Metric,
  8. Result,
  9. Service,
  10. State,
  11. check_levels,
  12. render,
  13. )
  14. # JSON parsing
  15. def parse_p1(string_table):
  16. flat = list(itertools.chain.from_iterable(string_table))
  17. raw = "".join(flat)
  18. try:
  19. data = json.loads(raw)
  20. except json.JSONDecodeError:
  21. return None
  22. if not isinstance(data, dict):
  23. return None
  24. return data
  25. agent_section_p1 = AgentSection(
  26. name="p1",
  27. parse_function=parse_p1,
  28. )
  29. # P1 tariff
  30. def discover_p1_tariff(section):
  31. if section is not None and "active_tariff" in section:
  32. yield Service()
  33. def check_p1_tariff(section):
  34. tariff = section.get("active_tariff")
  35. if tariff is None:
  36. yield Result(
  37. state=State.UNKNOWN,
  38. summary="Active tariff is not available",
  39. )
  40. return
  41. yield Result(
  42. state=State.OK,
  43. summary=f"Tariff: {tariff}",
  44. )
  45. check_plugin_p1_tariff = CheckPlugin(
  46. name="p1_tariff",
  47. sections=["p1"],
  48. service_name="P1 Tariff",
  49. discovery_function=discover_p1_tariff,
  50. check_function=check_p1_tariff,
  51. )
  52. # Power
  53. POWER_ITEMS = {
  54. "Total": "active_power_w",
  55. "L1": "active_power_l1_w",
  56. "L2": "active_power_l2_w",
  57. "L3": "active_power_l3_w",
  58. }
  59. def discover_p1_power(section):
  60. for item, key in POWER_ITEMS.items():
  61. if key in section:
  62. yield Service(item=item)
  63. def check_p1_power(item, section):
  64. key = POWER_ITEMS.get(item)
  65. if key is None or key not in section:
  66. yield Result(
  67. state=State.UNKNOWN,
  68. summary="Power value is not available",
  69. )
  70. return
  71. value = float(section[key])
  72. yield Result(
  73. state=State.OK,
  74. summary=f"{value:.0f} W",
  75. )
  76. yield Metric(
  77. name="p1_power_w",
  78. value=value,
  79. boundaries=(0, None),
  80. )
  81. check_plugin_p1_power = CheckPlugin(
  82. name="p1_power",
  83. sections=["p1"],
  84. service_name="P1 Power %s",
  85. discovery_function=discover_p1_power,
  86. check_function=check_p1_power,
  87. )
  88. # Voltage
  89. VOLTAGE_ITEMS = {
  90. "L1": "active_voltage_l1_v",
  91. "L2": "active_voltage_l2_v",
  92. "L3": "active_voltage_l3_v",
  93. }
  94. def discover_p1_voltage(section):
  95. for item, key in VOLTAGE_ITEMS.items():
  96. if key in section:
  97. yield Service(item=item)
  98. def check_p1_voltage(item, params, section):
  99. key = VOLTAGE_ITEMS.get(item)
  100. if key is None or key not in section:
  101. yield Result(
  102. state=State.UNKNOWN,
  103. summary="Voltage value is not available",
  104. )
  105. return
  106. value = float(section[key])
  107. yield from check_levels(
  108. value,
  109. levels_upper=params["levels"],
  110. metric_name="p1_voltage_v",
  111. label="Voltage",
  112. render_func=lambda v: f"{v:.1f} V",
  113. boundaries=(0, 300),
  114. )
  115. check_plugin_p1_voltage = CheckPlugin(
  116. name="p1_voltage",
  117. sections=["p1"],
  118. service_name="P1 Voltage %s",
  119. discovery_function=discover_p1_voltage,
  120. check_function=check_p1_voltage,
  121. check_default_parameters={
  122. "levels": ("fixed", (252.0, 253.0)),
  123. },
  124. check_ruleset_name="p1_voltage",
  125. )
  126. # Current
  127. CURRENT_ITEMS = {
  128. "Total": "active_current_a",
  129. "L1": "active_current_l1_a",
  130. "L2": "active_current_l2_a",
  131. "L3": "active_current_l3_a",
  132. }
  133. def discover_p1_current(section):
  134. for item, key in CURRENT_ITEMS.items():
  135. if key in section:
  136. yield Service(item=item)
  137. def check_p1_current(item, section):
  138. key = CURRENT_ITEMS.get(item)
  139. if key is None or key not in section:
  140. yield Result(
  141. state=State.UNKNOWN,
  142. summary="Current value is not available",
  143. )
  144. return
  145. value = float(section[key])
  146. yield Result(
  147. state=State.OK,
  148. summary=f"{value:.3f} A",
  149. )
  150. yield Metric(
  151. name="p1_current_a",
  152. value=value,
  153. boundaries=(0, None),
  154. )
  155. check_plugin_p1_current = CheckPlugin(
  156. name="p1_current",
  157. sections=["p1"],
  158. service_name="P1 Current %s",
  159. discovery_function=discover_p1_current,
  160. check_function=check_p1_current,
  161. )
  162. # Energy import / export
  163. ENERGY_ITEMS = {
  164. "Import": {
  165. "total": "total_power_import_kwh",
  166. "t1": "total_power_import_t1_kwh",
  167. "t2": "total_power_import_t2_kwh",
  168. },
  169. "Export": {
  170. "total": "total_power_export_kwh",
  171. "t1": "total_power_export_t1_kwh",
  172. "t2": "total_power_export_t2_kwh",
  173. },
  174. }
  175. def discover_p1_energy(section):
  176. for item, keys in ENERGY_ITEMS.items():
  177. if any(key in section for key in keys.values()):
  178. yield Service(item=item)
  179. def check_p1_energy(item, section):
  180. keys = ENERGY_ITEMS.get(item)
  181. if keys is None:
  182. yield Result(
  183. state=State.UNKNOWN,
  184. summary="Unknown energy type",
  185. )
  186. return
  187. found = False
  188. for metric_name, key in (
  189. ("p1_energy_total_kwh", keys["total"]),
  190. ("p1_energy_t1_kwh", keys["t1"]),
  191. ("p1_energy_t2_kwh", keys["t2"]),
  192. ):
  193. if key not in section:
  194. continue
  195. found = True
  196. yield Metric(
  197. name=metric_name,
  198. value=float(section[key]),
  199. boundaries=(0, None),
  200. )
  201. if not found:
  202. yield Result(
  203. state=State.UNKNOWN,
  204. summary=f"{item} energy values are not available",
  205. )
  206. return
  207. yield Result(
  208. state=State.OK,
  209. summary=f"{item} energy data available",
  210. )
  211. check_plugin_p1_energy = CheckPlugin(
  212. name="p1_energy",
  213. sections=["p1"],
  214. service_name="P1 Energy %s",
  215. discovery_function=discover_p1_energy,
  216. check_function=check_p1_energy,
  217. )
  218. # Gas
  219. def discover_p1_gas(section):
  220. if "total_gas_m3" in section:
  221. yield Service()
  222. def check_p1_gas(section):
  223. value = float(section["total_gas_m3"])
  224. yield Result(
  225. state=State.OK,
  226. summary=f"{value:.2f} m³",
  227. )
  228. yield Metric(
  229. name="p1_gas_m3",
  230. value=value,
  231. boundaries=(0, None),
  232. )
  233. check_plugin_p1_gas = CheckPlugin(
  234. name="p1_gas",
  235. sections=["p1"],
  236. service_name="P1 Gas",
  237. discovery_function=discover_p1_gas,
  238. check_function=check_p1_gas,
  239. )
  240. # Power quality
  241. POWER_QUALITY_KEYS = {
  242. "Voltage sag L1": "voltage_sag_l1_count",
  243. "Voltage sag L2": "voltage_sag_l2_count",
  244. "Voltage sag L3": "voltage_sag_l3_count",
  245. "Voltage swell L1": "voltage_swell_l1_count",
  246. "Voltage swell L2": "voltage_swell_l2_count",
  247. "Voltage swell L3": "voltage_swell_l3_count",
  248. "Any power failure": "any_power_fail_count",
  249. "Long power failure": "long_power_fail_count",
  250. }
  251. def discover_p1_power_quality(section):
  252. if any(key in section for key in POWER_QUALITY_KEYS.values()):
  253. yield Service()
  254. def check_p1_power_quality(section):
  255. found = 0
  256. for metric_name, key in POWER_QUALITY_KEYS.items():
  257. if key not in section:
  258. continue
  259. found += 1
  260. metric_id = (
  261. metric_name.lower()
  262. .replace(" ", "_")
  263. )
  264. yield Metric(
  265. name=f"p1_{metric_id}",
  266. value=float(section[key]),
  267. boundaries=(0, None),
  268. )
  269. if found:
  270. yield Result(
  271. state=State.OK,
  272. summary=f"{found} power-quality counters available",
  273. )
  274. else:
  275. yield Result(
  276. state=State.UNKNOWN,
  277. summary="No power-quality counters available",
  278. )
  279. check_plugin_p1_power_quality = CheckPlugin(
  280. name="p1_power_quality",
  281. sections=["p1"],
  282. service_name="P1 Power Quality",
  283. discovery_function=discover_p1_power_quality,
  284. check_function=check_p1_power_quality,
  285. )