LOEMIND.md 15 KB

Dev-teenused (dev) – Docker kasutusjuhend

Kataloog: /opt/docker-compose/dev/

Arendus-/tutvumisteenused. Esimene teenus on ClickHouse (OLAP-andmebaas, mille eesmärk on Oracle-baaside ülemineku ettevalmistamine).

ClickHouse

Omadus Väärtus
Pilt clickhouse/clickhouse-server:26.9.14.10
Konteiner clickhouse
Püsivus alati aktiivne (ei ole enam experimental profiilis), restart: unless-stopped, mem_limit: 2g
HTTP API 8125 — 100.87.1.24:8125 (Tailscale) + 192.168.68.114:8125 (LAN); 8124 läbi clickstack-proxy
Native TCP 9004 — 100.87.1.24:9004 (Tailscale) + 192.168.68.114:9004 (LAN)
Kasutaja default (ja dev, zigbee)
Parool dev_clickhouse_2026 (default/dev); zigbee kasutaja parool on dev/.env failis
Andmed ./data/clickhouse (gitignore'd)
Config ./config/ → config.d (server); ./users.d/ → users.d (users + profiilid)
Võrk main_ai_network

Turvamärkus (2026-09-17, uuendatud 2026-10-17): pordid 8125/9004 ei ole 0.0.0.0 peal. Algselt ainult Tailscale'i aadressil 100.87.1.24; 2026-10-17 lisati ka LAN-IP 192.168.68.114 (DBeaver). Auth on kohustuslik.

LZ4/ZSTD (2026-10-17): ClickHouse 26.x vaikimisi network_compression_method=ZSTD murdis vanemad clickhouse-jdbc/DBeaver kliendid → "Invalid LZ4 magic byte" (bait 0x90 = ZSTD, klient ootab LZ4 0x82). Lahendus: ./users.d/zz-network-compression.xml seab profiilis default → network_compression_method=lz4. NB: profiilid kuuluvad users.d-sse, MITTE config.d-sse (config.xml-s pole <profiles>).

Web UI

ClickHouse'il on sisseehitatud veebiliides (/play — SQL playground):

http://100.87.1.24:8124/play

Kasutajanimi default, parool dev_clickhouse_2026.

Käsud

# Käivita / peata / taaskäivita
docker-compose -f /opt/docker-compose/dev/docker-compose.yml up -d
docker-compose -f /opt/docker-compose/dev/docker-compose.yml down
docker-compose -f /opt/docker-compose/dev/docker-compose.yml restart clickhouse

# Logid
docker-compose -f /opt/docker-compose/dev/docker-compose.yml logs -f clickhouse

# Kliendiga (konteineri sees)
docker exec -it clickhouse clickhouse-client --user default --password dev_clickhouse_2026

Zigbee andurite koguja (zigbee-collector)

Valvuri (valvur, Orange Pi Zero 3, 100.80.254.54) Zigbee2MQTT andurite andmed kogutakse ClickHouse'i. Arhitektuur: ohmu loeb (pull) — koguja jookseb ohmu peal, tellib valvuri MQTT-d ja kirjutab kohalikku ClickHouse'i. Valvurile ei lähe andmebaasi kredentiaale.

Omadus Väärtus
Kood ./zigbee-collector/ (collector.py, Dockerfile, requirements.txt)
Konteiner zigbee-collector (püsiv, restart: unless-stopped, mem_limit: 128m)
Konf/paroolid dev/.env (gitignore'itud, chmod 600)
MQTT allikas mqtt://100.80.254.54:1883
Temperatuuriandur SONOFF SNZB-02P (0x70d07efffea3e4f6, Temperatuur) → uus67.temperatuur
Kontaktandurid SONOFF SNZB-04PR2 ×4 (Välisuks, Rõdu, Kontori uks, Kontori aken) → uus67.ukseandur
Häired kõik andurid + süsteem → uus67.vead

Loogika:

  • Temperatuur (MQTT_TOPIC): mõõtmised kogutakse mälus täistunni kaupa ja kirjutatakse iga täistunni järel üks rida (temperature/humidity = tunni keskmine). Andur raporteerib u. iga 10 min → tunnis mitu mõõtmist. Kui tunnis mõõtmisi ei ole (andur kättesaamatu), kirjutatakse ikkagi rida eelmise teadaoleva väärtusega ja taidetud = true — nii ei teki aegreas auke. Viimane väärtus seemendatakse käivitusel andmebaasist.
  • Uksed (DOOR_TOPICS): salvestatakse ainult olekumuutused. Perioodilised ~2 h südamelöögid (sama contact) jäetakse vahele. Käivitusel seemendatakse viimane teadaolev olek andmebaasist; esimene nähtud olek salvestatakse baasreana.
  • Häired (CH_FAULT_TABLE): salvestatakse ainult muutused — iga häire kohta kaks sündmust (aktiveeritud / taastatud). Aktiivsed häired seemendatakse käivitusel andmebaasist, et restart ei dubleeriks.

Skeem

CREATE DATABASE IF NOT EXISTS uus67;

CREATE TABLE uus67.temperatuur (
    hour          DateTime('Europe/Tallinn'),
    device        LowCardinality(String),
    temperature   Nullable(Float32),   -- tunni keskmine
    humidity      Nullable(Float32),   -- tunni keskmine
    taidetud      Bool DEFAULT false   -- true = eelmise väärtusega täidetud tund
) ENGINE = MergeTree
PARTITION BY toYYYYMM(hour)
ORDER BY (device, hour);

Kontaktandurite tabel (ainult olekumuutused):

CREATE TABLE uus67.ukseandur (
    ts          DateTime('Europe/Tallinn'),
    device      LowCardinality(String),
    contact     Bool,                   -- toorväärtus Z2M-st
    olek        LowCardinality(String)  -- 'avatud' / 'suletud'
) ENGINE = MergeTree
PARTITION BY toYYYYMM(ts)
ORDER BY (device, ts);

Diagnostilised veerud (aku, pinge, signaal) on nendest tabelitest teadlikult eemaldatud — nende muutused on uus67.vead tabelis.

contact semantika (SNZB-04PR2): contact: true = suletud, contact: false = avatud. Kinnitatud Zigbee2MQTT HA-discovery'st (device_class: door, payload_on: false, payload_off: true).

Häirete tabel (ainult muutused):

CREATE TABLE uus67.vead (
    ts      DateTime('Europe/Tallinn'),
    device  LowCardinality(String),
    tyyp    LowCardinality(String),   -- low_battery | weak_signal | low_voltage | offline | mqtt_disconnected | bridge_offline
    olek    LowCardinality(String),   -- 'aktiveeritud' / 'taastatud'
    detail  String,                   -- nt "battery 15%", "linkquality 12"
    vaartus Nullable(Float64)
) ENGINE = MergeTree
PARTITION BY toYYYYMM(ts)
ORDER BY (device, ts);
Häire (tyyp) Tingimus Lävend (aktiveerub / taastub)
low_battery battery_low == true või battery madal ≤ 20% / ≥ 25%
weak_signal linkquality madal ≤ 20 / ≥ 30
low_voltage voltage madal (kontaktandurid) ≤ 2600 mV / ≥ 2700 mV
offline andurilt pole teadet temp 120 min / kontakt 240 min
mqtt_disconnected koguja MQTT-ühendus katkes (device=koguja) –
bridge_offline zigbee2mqtt/bridge/state = offline (device=zigbee2mqtt) –

Lävendid on üle kirjutatavad .env-is / keskkonnamuutujatega (BATTERY_LOW_THRESHOLD, LINKQUALITY_LOW_THRESHOLD, VOLTAGE_LOW_THRESHOLD, OFFLINE_TIMEOUT_TEMP_MIN, OFFLINE_TIMEOUT_CONTACT_MIN). tamper on teadlikult välja jäetud — SNZB-04PR2 raporteerib selle pidevalt true (tõenäoliselt pööratud), mis annaks valehäireid.

Käsud

# Koguja logid
docker logs -f zigbee-collector

# Viimased tunniread
docker exec clickhouse clickhouse-client --user default --password dev_clickhouse_2026 \
  --query "SELECT * FROM uus67.temperatuur ORDER BY hour DESC LIMIT 24"

# Viimased ukseoleku muutused
docker exec clickhouse clickhouse-client --user default --password dev_clickhouse_2026 \
  --query "SELECT * FROM uus67.ukseandur ORDER BY ts DESC LIMIT 24"

# Viimased häired (ainult muutused)
docker exec clickhouse clickhouse-client --user default --password dev_clickhouse_2026 \
  --query "SELECT * FROM uus67.vead ORDER BY ts DESC LIMIT 50"

# Koguja taaskäivitamine (nt .env muudatuse järel)
docker compose -f /opt/docker-compose/dev/docker-compose.yml up -d --build zigbee-collector

Valvuri MQTT turvakõvadus (2026-09-17)

  • mosquitto.conf: kaks listener'it — 127.0.0.1:1883 (kohalik Z2M) ja 100.80.254.54:1883 (Tailscale). LAN-ist MQTT-le ligi ei pääse.
  • Zigbee2MQTT seadmetel (Temperatuur + 4 kontaktandurit) on retain: true → koguja taaskäivitumisel saab kohe viimased väärtused (varem teated ei olnud retained).
  • Valvuri konfiguratsioonid on root-omanduses; muutmiseks on vaja sudo-t (varukoopiad: *.bak-20260917).

ClickStack (HyperDX) — observability UI

ClickStack = HyperDX UI + ClickHouse + OTel-kollektor (logid/traces/meetrikud).

Omadus Väärtus
Konteiner clickstack (hyperdx-all-in-one)
UI (otsing/dashboardid) http://100.87.1.24:8124/clickstack/search (läbi clickstack-proxy)
UI otse (varuvariant) http://100.87.1.24:18080/search
Kasutaja admin@odamus.com
Parool Dev_clickhouse_2026!
OTLP gRPC sisend 4317
OTLP HTTP sisend 4318
Andmed (incl. MongoDB) ./data/clickstack (gitignore'd)

Hooldus: all-in-one ei käivita MongoDB-d ise — seetõttu on command üle võetud clickstack-entry.sh-ga (käivitab mongod pordil 127.0.0.1, siis rakenduse). db laheneb konteineris 127.0.0.1-le (sisemine MongoDB).

Port 8124 = clickstack-proxy (nginx):

  • /clickstack/* → ClickStack UI (ClickHouse staatiline kest)
  • /__ENV.js, /api/*, /graphql → HyperDX backend
  • /, /play, /?query=... → ClickHouse (ehk DBeaver 8124-ga töötab edasi)
  • ClickHouse'i HTTP otse on nüüd pordil 8125 (8124 läbi proxy sama API-ga)

Migratsiooninäide: postgres → ClickHouse (paberkrohv)

2026-08-31 viidi paberkrohv andmebaas postgresist (100.87.1.24:5432) ClickHouse'isse — näide, kuidas hiljem Oracle-baase üle viia.

Tulemus (read ühtivad): sorptsioon 48193, sample_weight 2529, sample 1749, mixture 386, lot 10, res_users 6, test 7.

Tüübimapping

Postgres ClickHouse
integer Int32
numeric Float64 (testiks OK; täpsuse vajadusel Decimal)
timestamp (ilma tz) DateTime64(3)
character varying / text String
boolean Bool

Tabeli loomine (MergeTree — analüütiline mootor)

CREATE TABLE paberkrohv.sorptsioon (
    id Int32, weight Float64, lot Int32, sample Int32, rh_1 Int32, test_id Int32,
    datetime DateTime64(3), created_at DateTime64(3), created_by Int32
) ENGINE = MergeTree ORDER BY (sample, lot, datetime);

Andmete ülekanne (ClickHouse'i postgresql() tabelifunktsioon)

-- ClickHouse loeb otse postgresist, ilma vahefailita:
INSERT INTO paberkrohv.sorptsioon
SELECT * FROM postgresql('postgres_postgis:5432', 'paberkrohv', 'sorptsioon', 'ai_user', 'ai_secure_pass_2026');

Päring peab jooksma ClickHouse'i konteineri seest (võrk main_ai_network võimaldab postgres_postgis:5432). Postgres jääb puutumatuks — ClickHouse on koopia.

Käsud

docker exec -it clickhouse clickhouse-client --user default --password dev_clickhouse_2026 \
  --query "SELECT count() FROM paberkrohv.sorptsioon"

Märkused

  • Pordid valitud konfliktivabaks: 8125 (HTTP, Tailscale-only), 9004 (native, Tailscale-only), 8124 (proxy, clickstack). 8123 = Home Assistant, 9000 = portainer.
  • Oracle → ClickHouse: ClickHouse on veerupõhine OLAP; sobib analüüsi/aruandluse koormuste jaoks. Postgres-migratsioon on eeskujuks: postgresql() tabelifunktsioon lihtsustab oluliselt (Oracle'i jaoks tuleb vastav funktsioon/ODBC-vood eraldi uurida).

Välistemperatuur (weather-collector)

Open-Meteo API-st tunniandmed (temperatuur, niiskus, tuul, sademed) → ClickHouse uus67.valisilm. Eraldi konteiner weather-collector.

Omadus Väärtus
Kood ./weather-collector/ (collector.py, Dockerfile, requirements.txt)
Konteiner weather-collector (püsiv, restart: unless-stopped, mem_limit: 128m)
Allikas Open-Meteo (api.open-meteo.com, archive-api.open-meteo.com)
Asukoht LATITUDE / LONGITUDE (vaikimisi 58.87009, 22.9479)
Backfill BACKFILL_FROM (vaikimisi 2026-09-17); archive + forecast API
Intervall POLL_INTERVAL (vaikimisi 1800 s; jookseb iga tunni +5 min)
Tabel uus67.valisilm

Loogika: käivitusel backfill; edasi tunnipoll, mis uuendab hiljutisi tunde. Puuduvad tunnid täidetakse eelmise väärtusega (taidetud = true) — auke ei jää. Tabel on ReplacingMergeTree (ORDER BY hour), päringud kasutavad FINAL.

CREATE TABLE uus67.valisilm (
    hour        DateTime('Europe/Tallinn'),
    temperature Nullable(Float32),
    humidity    Nullable(Float32),
    wind        Nullable(Float32),
    rain        Nullable(Float32),
    taidetud    Bool DEFAULT false
) ENGINE = ReplacingMergeTree
PARTITION BY toYYYYMM(hour)
ORDER BY hour;

NB! .env-is on CH_TABLE=temperatuur (zigbee koguja jaoks). Välikoguja kasutab eraldi muutujat CH_WEATHER_TABLE (vaikimisi valisilm) — muidu kirjutaks .env väärtus valesse tabelisse.

docker logs -f weather-collector
docker exec clickhouse clickhouse-client --user default --password dev_clickhouse_2026 \
  --query "SELECT * FROM uus67.valisilm ORDER BY hour DESC LIMIT 24"

Nutikodu veebiliides (nutikodu-web)

Interaktiivne ajatelg uus67 skeemi zigbee andurite andmetele. FastAPI backend + üks staatiline leht (ECharts), eestikeelne, mobiilisõbralik, tume/hele teema. Graafikul kuvatakse ka välistemperatuur rohelise joonena (/api/valisilm).

Omadus Väärtus
Kood ./nutikodu-web/ (app.py, Dockerfile, static/, README.md)
Konteiner nutikodu-web (püsiv, restart: unless-stopped, mem_limit: 192m)
Võrgud main_ai_network (ClickHouse) + prod_net (prod_caddy)
Tailscale http://100.87.1.24:8095 · http://ohmu.tail20e23.ts.net:8095
Avalik https://nutikodu.odamus.com
ClickHouse http://clickhouse:8123, kasutaja zigbee (SELECT uus67.*)

Avaliku ligipääsu ahel (2026-09-17):

  1. DNS: DigitalOcean A-kirje nutikodu.odamus.com → 188.166.84.16.
  2. Edge Caddy (kanad/edge, /opt/edge/Caddyfile): nutikodu.odamus.com { reverse_proxy http://100.91.118.16:80 }. TLS automaatne (Let's Encrypt).
  3. Sisemine Caddy (ohmu prod_caddy, /opt/prod/Caddyfile): nutikodu.odamus.com:80 { reverse_proxy nutikodu-web:8095 }. (100.91.118.16 = ts-prod tailnet IP; prod_caddy töötab network_mode: container:ts-prod.)

NB! DNS-vahemälu: uue domeeni lisamisel tekib kohati negatiivne NXDOMAIN-vahemälu. Kui nutikodu.odamus.com ei lahendu, tühjenda:

# ohmu
sudo resolvectl flush-caches
# pihole (valvur, 192.168.2.50)
docker restart pihole

API: /api/meta, /api/temperatuur (hour/day), /api/ukseandur, /api/vead, /api/latest, /health. Vaata täpsemalt nutikodu-web/README.md.

Käsud:

docker logs -f nutikodu-web
curl -s https://nutikodu.odamus.com/health
docker compose -f /opt/docker-compose/dev/docker-compose.yml up -d --build nutikodu-web

Edasi: ukseanduri olekuribad ja häirete markerid ajateljel (/api/ukseandur, /api/vead on valmis); võimalik WEB_ACCESS_TOKEN avaliku lehe kaitseks.