collector.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. """AS7341 värvianduri koguja: MQTT -> ClickHouse (uus67.varvus).
  2. Tellib MQTT-teemat (vaikimisi varvus/spectral), kus ESPHome saadab
  3. JSON-i kanalitega f1..f8, clear, nir (+ gain). Iga sonum = uks rida.
  4. Lisaks arvutatakse ligikaudne värvus (CIE XYZ -> sRGB, vt color.py).
  5. Tellimus tehakse on_connect-is, et see taastuks ka parast brokeri
  6. taaskäivitust / ühenduse katkemist (clean session).
  7. """
  8. from __future__ import annotations
  9. import json
  10. import os
  11. from datetime import datetime
  12. from zoneinfo import ZoneInfo
  13. import paho.mqtt.client as mqtt
  14. import requests
  15. import color
  16. MQTT_HOST = os.environ.get("MQTT_HOST", "mosquitto")
  17. MQTT_PORT = int(os.environ.get("MQTT_PORT", "1883"))
  18. MQTT_USER = os.environ.get("MQTT_USER", "")
  19. MQTT_PASS = os.environ.get("MQTT_PASS", "")
  20. MQTT_TOPIC = os.environ.get("MQTT_TOPIC", "varvus/spectral")
  21. MQTT_TLS = os.environ.get("MQTT_TLS", "false").strip().lower() in ("1", "true", "yes", "on")
  22. CH_URL = os.environ.get("CH_URL", "http://clickhouse:8123").rstrip("/")
  23. CH_DB = os.environ.get("CH_DB", "uus67")
  24. CH_TABLE = os.environ.get("CH_TABLE", "varvus")
  25. CH_USER = os.environ.get("CH_USER", "zigbee")
  26. CH_PASS = os.environ.get("CH_PASS", "")
  27. TZ = ZoneInfo("Europe/Tallinn")
  28. FIELDS = ("f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "clear", "nir")
  29. def insert(row: dict) -> None:
  30. resp = requests.post(
  31. f"{CH_URL}/",
  32. params={
  33. "database": CH_DB,
  34. "query": f"INSERT INTO {CH_DB}.{CH_TABLE} FORMAT JSONEachRow",
  35. },
  36. data=json.dumps(row, ensure_ascii=False) + "\n",
  37. auth=(CH_USER, CH_PASS),
  38. timeout=10,
  39. )
  40. resp.raise_for_status()
  41. def on_connect(client, userdata, flags, reason_code, properties=None) -> None:
  42. if reason_code == 0:
  43. client.subscribe(MQTT_TOPIC, qos=0)
  44. print(f"MQTT ühendatud, tellitud {MQTT_TOPIC}", flush=True)
  45. else:
  46. print(f"MQTT ühenduse viga: {reason_code}", flush=True)
  47. def on_message(client, userdata, msg) -> None:
  48. try:
  49. payload = json.loads(msg.payload.decode())
  50. except Exception as exc:
  51. print(f"JSON viga: {exc}", flush=True)
  52. return
  53. row: dict = {
  54. "ts": datetime.now(TZ).strftime("%Y-%m-%d %H:%M:%S"),
  55. "device": "varvusensor",
  56. }
  57. channels: dict[str, float] = {}
  58. for field in FIELDS:
  59. value = payload.get(field)
  60. if value is not None:
  61. channels[field] = float(value)
  62. row[field] = float(value)
  63. gain = payload.get("gain")
  64. if gain is not None:
  65. row["gain"] = int(gain)
  66. row.update(color.analyze(channels))
  67. try:
  68. insert(row)
  69. print(
  70. f"salvestatud: {row['rgb_hex']} x={row['x_chrom']} y={row['y_chrom']} "
  71. f"f5={row.get('f5')} f6={row.get('f6')}",
  72. flush=True,
  73. )
  74. except Exception as exc:
  75. print(f"ClickHouse viga: {exc}", flush=True)
  76. def main() -> None:
  77. client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
  78. if MQTT_TLS:
  79. client.tls_set()
  80. if MQTT_USER:
  81. client.username_pw_set(MQTT_USER, MQTT_PASS)
  82. client.on_connect = on_connect
  83. client.on_message = on_message
  84. client.connect(MQTT_HOST, MQTT_PORT, 60)
  85. print(f"Koguja käivitub, broker {MQTT_HOST}:{MQTT_PORT} (TLS={MQTT_TLS})", flush=True)
  86. client.loop_forever()
  87. if __name__ == "__main__":
  88. main()