A simple Prometheus export that collect A/C target temperature & load power from Xiaomi Air Conditioning Companion.
It serves as a simple demo, you may expand it to other Mi devices & metrics. See python-miio's document.
A simple Prometheus export that collect A/C target temperature & load power from Xiaomi Air Conditioning Companion.
It serves as a simple demo, you may expand it to other Mi devices & metrics. See python-miio's document.
#!/usr/bin/env python3 | |
import os | |
from io import TextIOWrapper | |
from typing import Dict | |
from pathlib import Path | |
from http.server import HTTPServer, BaseHTTPRequestHandler | |
from miio.airconditioningcompanion import AirConditioningCompanion | |
HTTP_BIND = ('127.0.0.1', 8000) | |
AC_ADDR = '192.0.2.12' | |
def load_tokens() -> Dict[str, str]: | |
cred_dir = os.environ.get('CREDENTIALS_DIRECTORY', '.') | |
token_path = Path(cred_dir) / Path('tokens') | |
addrs_token = dict() | |
with token_path.open() as f: | |
for line in f: | |
line = line.strip() | |
if line.startswith('#') or '/' not in line: | |
continue | |
addr, token = line.rsplit('/', 1) | |
addrs_token[addr] = token | |
return addrs_token | |
class HTTPHandler(BaseHTTPRequestHandler): | |
def do_GET(self): | |
if self.path != '/metrics': | |
self.send_response(404) | |
self.send_header("Content-Type", "text/plain") | |
self.end_headers() | |
self.wfile.write(b"404 not found\n") | |
return | |
self.send_response(200) | |
self.send_header("Content-Type", "text/plain; charset=utf-8") | |
self.end_headers() | |
body = TextIOWrapper(self.wfile) | |
def metric(key, value, typ, help): | |
print(f"# HELP miio_{key} {help}", file=body) | |
print(f"# TYPE miio_{key} {typ}", file=body) | |
print(f"miio_{key} {value}", file=body) | |
print("", file=body) | |
status = self.server.ac.status() | |
if status.power: | |
metric("ac_targettemp", status.target_temperature, "gauge", "Target temperature") | |
metric("ac_loadpower", status.load_power, "gauge", "Current power load of the air conditioner") | |
body.flush() | |
body.detach() | |
def main(): | |
addr_tokens = load_tokens() | |
ac = AirConditioningCompanion(AC_ADDR, addr_tokens[AC_ADDR]) | |
with HTTPServer(HTTP_BIND, HTTPHandler) as httpd: | |
httpd.ac = ac | |
httpd.serve_forever() | |
if __name__ == '__main__': | |
main() |
[Unit] | |
Description=Xiaomi A/C Companion Prometheus exporter | |
[Service] | |
Type=simple | |
DynamicUser=yes | |
LoadCredential=tokens:/opt/mi_ac_exporter/tokens | |
WorkingDirectory=/opt/mi_ac_exporter | |
ExecStart=/opt/mi_ac_exporter/mi_ac_exporter.py | |
Environment=PYTHONUNBUFFERED=1 | |
NoNewPrivileges=true | |
PrivateTmp=true | |
PrivateDevices=true | |
ProtectSystem=strict | |
ProtectHome=true | |
ProtectKernelModules=true | |
ProtectControlGroups=true | |
[Install] | |
WantedBy=multi-user.target |
# <IP-Address>/<Token-in-HEX> | |
192.0.2.12/abcdefabcdef12345678901234567890 | |
192.0.2.15/12345678901234567890abcdefabcdef |