aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordakkar <dakkar@thenautilus.net>2024-07-07 15:36:09 +0000
committerdakkar <dakkar@thenautilus.net>2024-07-07 15:38:59 +0000
commitb9121a113e50e81f09b01c0f95bf3fa1010feb56 (patch)
treee3e677a9c36eb5c5178b1fd36769a7495363d67d
downloadats-therm-b9121a113e50e81f09b01c0f95bf3fa1010feb56.tar.gz
ats-therm-b9121a113e50e81f09b01c0f95bf3fa1010feb56.tar.bz2
ats-therm-b9121a113e50e81f09b01c0f95bf3fa1010feb56.zip
start
-rw-r--r--.gitignore5
-rw-r--r--README.md9
-rw-r--r--requirements.txt3
-rwxr-xr-xscan.py71
-rwxr-xr-xtherm.openrc19
5 files changed, 107 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..3724229
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+*~
+/venv/
+/*.out
+/*.err
+/*.pid
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..05ef966
--- /dev/null
+++ b/README.md
@@ -0,0 +1,9 @@
+# Install
+
+```bash
+python -m venv ./venv
+. ./venv/bin/activate
+pip install -r requirements.txt
+```
+
+see also https://github.com/pvvx/ATC_MiThermometer
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..39ec0de
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,3 @@
+atc-mi-interface
+asyncio
+asyncio_simple_http_server
diff --git a/scan.py b/scan.py
new file mode 100755
index 0000000..673718d
--- /dev/null
+++ b/scan.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env python
+import asyncio
+from asyncio_simple_http_server import HttpServer, uri_mapping, HttpHeaders, HttpResponse
+from datetime import datetime, timezone
+from bleak import BleakScanner
+from functools import partial
+from atc_mi_interface import general_format, atc_mi_advertising_format
+
+fields=['temperature','humidity','battery_level','battery_v']
+
+def write_out_prometheus(collected):
+ f = open("metrics", "w", encoding="utf-8")
+ for field in fields:
+ print("# HELP therm_{0} {0}\n# TYPE therm_{0} gauge".format(field),file=f)
+ for mac in collected:
+ print("therm_{0}{{mac=\"{1}\"}} {2:f}".format(field,mac,collected[mac][field][0]),file=f)
+
+class Prom:
+ collected = {}
+
+ @uri_mapping('/metrics')
+ def expose(self) -> HttpResponse:
+ output=""
+ for field in fields:
+ output = output + "# HELP therm_{0} {0}\n# TYPE therm_{0} gauge\n".format(field)
+ for mac in self.collected:
+ output = output + "therm_{0}{{mac=\"{1}\"}} {2:f}\n".format(
+ field, mac, self.collected[mac][field][0]
+ )
+
+ headers = HttpHeaders()
+ headers.set('Content-type', 'text/plain; version=0.0.4; charset=utf-8; escaping=values')
+ return HttpResponse(200, headers, output.encode('utf-8'))
+
+async def main():
+ stop_event = asyncio.Event()
+ http_server = HttpServer()
+
+ handler=Prom()
+ http_server.add_handler(handler)
+
+ async def detection_callback(device, advertisement_data):
+ format_label, adv_data = atc_mi_advertising_format(advertisement_data)
+ if not adv_data:
+ return
+ mac_address = bytes.fromhex(device.address.replace(":", ""))
+ atc_mi_data = general_format.parse(
+ adv_data,
+ mac_address=mac_address,
+ bindkey=None,
+ )
+
+ data={
+ "timestamp": datetime.now(timezone.utc).isoformat(),
+ "temperature": atc_mi_data.search_all("^temperature"),
+ "humidity": atc_mi_data.search_all("^humidity"),
+ "battery_level": atc_mi_data.search_all("^battery_level"),
+ "battery_v": atc_mi_data.search_all("^battery_v"),
+ "MAC": atc_mi_data.search_all("^MAC$"),
+ }
+ handler.collected[data["MAC"][0]]=data
+
+ await http_server.start('10.111.0.66',9003)
+
+ async with BleakScanner(
+ detection_callback=partial(detection_callback)
+ ) as scanner:
+ await http_server.serve_forever()
+ print("Stopped")
+
+asyncio.run(main())
diff --git a/therm.openrc b/therm.openrc
new file mode 100755
index 0000000..7aa3d36
--- /dev/null
+++ b/therm.openrc
@@ -0,0 +1,19 @@
+#!/sbin/openrc-run
+
+thisdir="$(dirname "$(readlink -f "$1")")"
+
+description="XIAOMI Mijia prometheus exporter"
+directory="$thisdir"
+command="/usr/bin/env VIRTUAL_ENV='${thisdir}/venv' PATH='${thisdir}/venv/bin:/bin:/usr/bin' ./scan.py"
+pidfile="${thisdir}/ats-therm.pid"
+command_background=true
+command_user=dakkar
+output_log="${thisdir}/scan.out"
+error_log="${thisdir}/scan.err"
+name="ats-therm"
+procname="python"
+
+depend() {
+ need localmount net
+ after bootmisc
+}