From 4d2208f9618ed10b22c44b8cea15ddd418abea52 Mon Sep 17 00:00:00 2001
From: anima
Date: Sat, 4 Oct 2025 09:42:11 +0200
Subject: [PATCH] inital version with mqtt
---
checks/check_airq.py | 72 +++++++++++++++++++++----------------
requirements/_recommend.txt | 7 ++--
requirements/airq.txt | 2 +-
3 files changed, 48 insertions(+), 33 deletions(-)
diff --git a/checks/check_airq.py b/checks/check_airq.py
index 95b0c10..5cb80e4 100755
--- a/checks/check_airq.py
+++ b/checks/check_airq.py
@@ -3,12 +3,13 @@
"""dependencys:
- pip3 install nagiosplugin
- pip3 install argparse
+- pip3 install paho-mqtt
- pip3 install git+https://github.com/heinemml/CO2Meter
or
- pip3 install git+https://git.ao-it.net/python/CO2Meter
"""
-__version__ = '0.4.0'
+__version__ = '0.5.0'
__author__ = 'anima'
# imports
@@ -19,7 +20,6 @@ from time import sleep
from os import path
import re
import subprocess
-import socket
import threading
import nagiosplugin
@@ -108,9 +108,12 @@ class AirQServer(AirQLocal):
logging.debug(f'start AirQ in server mode')
thread_data = threading.Thread(target=self.get_local_data_loop, group=None)
thread_server = threading.Thread(target=self.run_server, group=None)
+
if self.get_usb_dev():
thread_data.start()
+ sleep(5)
thread_server.start()
+ self.threads.append(thread_data)
self.threads.append(thread_server)
def stop_treads(self):
@@ -123,41 +126,50 @@ class AirQServer(AirQLocal):
self.get_local_data()
def run_server(self):
- s = socket.socket()
- s.bind(('', self.port))
- s.listen(1)
+ import paho.mqtt.client as mqtt
+ client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="AirQServer")
+ client.connect("localhost", self.port)
logging.debug(f'run AirQ server on port {self.port}')
- try:
- while True:
- conn, addr = s.accept()
- data = {"co2": self.co2, "temp": self.temp}
- logging.debug(f'connection from {addr}, send {data=}')
- conn.send(str(json.dumps(data)).encode())
- conn.close()
- except KeyboardInterrupt:
- logging.debug(f'stop AirQ server')
- s.close()
+
+ while True:
+ sleep(10)
+ logging.debug(f'set {self.temp=}, {self.co2=}')
+ client.publish("airq/temp", self.temp, retain=True)
+ client.publish("airq/co2", self.co2, retain=True)
class AirQClient(AirQBase):
- def __init__(self, server: str = 'localhost', port: int = 4554):
+ def __init__(self, server: str = 'localhost', port: int = 4554, mode = None):
super().__init__()
self.server = server
self.port = port
logging.debug(f'start AirQ in client mode')
+ self.received = {}
+ self.mode = mode
self.run_client()
-
+
+ def on_message(self, client, userdata, msg):
+ self.received[msg.topic] = msg.payload.decode()
+ logging.debug(f"get {msg.topic=} with {self.received[msg.topic]=}")
+ client.disconnect() # end with first response
+
+
def run_client(self):
- s = socket.socket()
- s.connect((self.server, self.port))
- logging.debug(f'connected to {self.server=} on {self.port=}')
- data = json.loads(s.recv(1024).decode())
- logging.debug(f'server response: {data=}')
- s.close()
- if 'co2' in data.keys():
- self.co2 = data['co2']
- if 'temp' in data.keys():
- self.temp = data['temp']
+ import paho.mqtt.client as mqtt
+
+ client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="AirQClient")
+ client.on_message = self.on_message
+
+ client.connect(self.server, self.port)
+ client.subscribe(f"airq/{self.mode}")
+
+ client.loop_start()
+ sleep(1)
+ client.loop_stop()
+ if self.mode == 'co2':
+ self.co2 = self.received[f"airq/{self.mode}"]
+ elif self.mode == 'temp':
+ self.temp = self.received[f"airq/{self.mode}"]
class AirQCO2Resource(nagiosplugin.Resource):
@@ -237,17 +249,17 @@ def main():
if args.verbose >= 3:
logging.getLogger().setLevel(logging.DEBUG)
+ # dice which check will be run bases on check_mode
if args.check_mode != 'server':
if args.airq_mode == 'local':
airq = AirQLocal(device=args.airq_device)
elif args.airq_mode == 'client':
- airq = AirQClient(server=args.airq_server, port=args.airq_port)
+ airq = AirQClient(server=args.airq_server, port=int(args.airq_port), mode=args.check_mode)
else:
logging.error('Unknown airq mode')
exit()
check = None
- # dice which check will be run bases on check_mode
match args.check_mode:
case 'co2':
check = nagiosplugin.Check(
@@ -263,7 +275,7 @@ def main():
check.name = "Temperature"
case 'server':
try:
- airq = AirQServer(port=args.airq_port, device=args.airq_device)
+ airq = AirQServer(port=int(args.airq_port), device=args.airq_device)
except KeyboardInterrupt:
airq.stop_treads()
case _:
diff --git a/requirements/_recommend.txt b/requirements/_recommend.txt
index f16ece0..3311642 100644
--- a/requirements/_recommend.txt
+++ b/requirements/_recommend.txt
@@ -1,8 +1,11 @@
## for all checks
nagiosplugin
-## for api checks
+## for api checks & notifications
requests
## for snmp checks
-easysnmp
\ No newline at end of file
+easysnmp
+
+## for mqtt checks
+paho-mqtt
\ No newline at end of file
diff --git a/requirements/airq.txt b/requirements/airq.txt
index 33a8038..bb35889 100644
--- a/requirements/airq.txt
+++ b/requirements/airq.txt
@@ -1,2 +1,2 @@
## for airq
-pip3 install git+https://github.com/heinemml/CO2Meter
\ No newline at end of file
+git+https://github.com/heinemml/CO2Meter
\ No newline at end of file