Perusvalvonta (RuuviTag + puhelin, SmartShunt + VictronConnect) näyttää reaaliaikaiset arvot. Edistynyt valvonta tuo:
---
| Osa | Perus vs Edistynyt | Edistynyt ominaisuus |
| Anturit | RuuviTag, SmartShunt | RuuviTag Pro 3in1 + ulkoiset anturit (lämpötila, kosteus, paine, VKL, CO2, liike) |
| Gateway | Puhelin / Cerbo GX | Raspberry Pi 4 + YDWG-02 (MQTT) + Signal K Server + MQTT Broker |
| Tietokanta | Ei (vain realtime) | InfluxDB 2.x / TimescaleDB (TSDB), retention policies, continuous queries |
| Visualisointi | Puhelin-appi / VictronConnect | Grafana (dashboardit, alarmit, provisioning), Grafana Cloud |
| Alarmit | Puhelin-notifikaatiot | Alertmanager + ntfy/Telegram/Email/SMS + eskalointi (eskalointiketjut) |
| ML/Analytics | Ei | Anomaliasarjat (Isolation Forest, ARIMA, Prophet), trendilineaarinen regressio |
| Automaatio | Ei | Node-RED / Home Assistant / Signal K Automation -> toiminta-arvot -> alarmi -> toiminto |
---
| Osanumero | Tuote | OEM-numero | Hinta | |
|---|---|---|---|---|
| RUV-001 | OEM-osa | |||
| VIC-SSHUNT | OEM-osa | |||
| YD-YDWG02 | OEM-osa |
| Ratkaisu | Anturit | Gateway | Tietokanta | Visualisointi | Alarmit | ML/Analytics | Hinta | Vaikeus |
| DIY Perus | 3× RuuviTag + SmartShunt | Puhelin (BT) | Ei (realtime) | Ruuvi Station / VictronConnect | Puhelin-notifikaatiot | Ei | 250 € | Helppo |
| DIY Edistynyt | 5× RuuviTag + SmartShunt + YDWG-02 | Pi 4 + Mosquitto + InfluxDB + Grafana + Signal K | InfluxDB (TSDB) | Grafana (dashboardit, alarmit) | Alertmanager + ntfy/Telegram/Email | Perus (threshold, rate-of-change) | 550 € | Keskivaikea |
| DIY Edistynyt + ML | Sama + lisäantureita | Sama + ML Pipeline (Python/Flux) | InfluxDB + TimescaleDB | Grafana + ML Dashboard | Alertmanager + Eskalointi | Anomalia (Isolation Forest), Ennuste (Prophet) | 600 € | Vaikea |
| Valmis (Cerbo GX + VRM) | RuuviTag + SmartShunt + YDWG-02 | Cerbo GX + VRM Portal | VRM Portal (30 d) / InfluxDB (valinnainen) | VRM Portal / Grafana Cloud | VRM Portal + Push-notifikaatiot | Ei (VRM Advanced: perus) | 1200 € | Helppo |
| Ammattilainen (Grafana Cloud + ML) | RuuviTag + SmartShunt + YDWG-02 + Cerbo GX | Cerbo GX + Grafana Agent | Grafana Cloud (Managed TSDB) | Grafana Cloud | Grafana Cloud Alerting + IRM | Grafana ML / Prophet / Custom | 1200 € + 50 €/kk | Keskivaikea |
---
| Tarve | Suositus |
| Opiskelu/Proof-of-Concept | RuuviTagit + Puhelin (Ruuvi Station) -> CSV-export -> Python/Excel analyysi |
| DIY Edistynyt (Kotiteko) | Pi 4 + RuuviTagit + SmartShunt + YDWG-02 -> Mosquitto + InfluxDB + Grafana + Signal K + Alertmanager |
| Produktio/Produktio-valmis | Cerbo GX + RuuviTagit + SmartShunt + YDWG-02 -> VRM Portal + Grafana Cloud + Alertmanager |
| Ammattilainen/Laivojen valvonta | Cerbo GX + RuuviTagit + YDWG-02 + Cerbo GX MQTT -> Grafana Cloud + ML Pipeline (AWS/GCP/Azure) |
`yaml
# docker-compose.yml (laajennettu)
version: '3.8'
services:
influxdb:
image: influxdb:2.7
ports: ["8086:8086"]
volumes: ["./influxdb:/var/lib/influxdb"]
environment:
influxdb-history:
image: influxdb:2.7
volumes: ["./influxdb-history:/var/lib/influxdb"]
environment:
`
Retention Policies (InfluxDB 2.x Bucket-pohjaiset):
| Bucket | Retentio | Resoluutio | Käyttötarkoitus |
realtime | 7 d | 1 Hz / 10 s | Reaaliaikaiset dashboardit, alarmit |
hourly | 90 d | 1 min (downsampled) | Trendi-analytiikka, viikoittaiset raportit |
daily | 3650 d (10 a) | 1 h (downsampled) | Vuosittaiset raportit,趋势分析, ML-treeni |
Continuous Queries (Flux tasks) - Downsampling:
`flux
// Hourly downsampling task
option task = {name: "downsample_1h", every: 1h}
from(bucket: "realtime")
|> range(start: -1h)
|> aggregateWindow(every: 1m, fn: mean, createEmpty: false)
|> to(bucket: "hourly", org: "boat")
`
Menetelmät:
| Menetelmä | Tyyppi | Soveltuvuus | Vaativuus |
| Threshold / Rate-of-Change | Tilastollinen | Yksinkertaiset rajat (lämpö > 95°C, paine < 1 bar) | Helppo |
| Rate-of-Change / Derivative | Tilastollinen | Aikaisempi varoitus (lämpö nousu > 5°C/min) | Helppo |
| Z-Score / Modified Z-Score | Tilastollinen | Poikkeamat histooriasta (lämpö > 3σ) | Helppo |
| Isolation Forest (sklearn) | ML (Unsupervised) | Monimuuttujaiset anomaliat, ei tarvitse labeleita | Keskivaikea |
| ARIMA / SARIMA (statsmodels) | ML (Time Series) | Aikasarja-ennuste, kausiluonto | Keskivaikea |
| Prophet (Facebook) | ML (Time Series) | Kausiluonto, holiday effects, puuttuvat arvot | Helppo |
| LSTM/GRU (PyTorch/TensorFlow) | Deep Learning | Monimutkaiset kuvio, multivariaatti | Vaikea |
Suositus aloittelijoille: Aloita Threshold + Rate-of-Change + Z-Score -> siirry Prophet ennusteisiin -> vasta sitten Isolation Forest anomaliasarjaan.
#### 3.1 Threshold + Rate-of-Change (Grafana Alerting)
`yaml
# Grafana Alert Rule (YAML provisioning)
apiVersion: 1
groups:
rules:
expr: |
max_over_time(boat_coolant_temp[5m]) > 95
for: 2m
labels:
severity: critical
annotations:
summary: "Moottorin vesilämpötila korkea (> 95°C)"
expr: |
derivative(boat_coolant_temp[5m]) > 5
for: 1m
labels:
severity: warning
annotations:
summary: "Vesilämpötila nousee nopeasti (> 5°C/min)"
`
#### 3.2 Prophet-ennuste (Python script, ajo cronilla tunnin välein)
`python
# predict_battery_soc.py
import pandas as pd
from prophet import Prophet
from influxdb_client import InfluxDBClient
import os
# Hae data InfluxDB:stä (viime 7 vrk)
client = InfluxDBClient(url="http://influxdb:8086", token=os.getenv("INFLUX_TOKEN"), org="boat")
query = 'from(bucket:"realtime") |> range(start: -7d) |> filter(fn: (r) => r._measurement == "battery_soc")'
df = client.query_api().query_data_frame(query)
# Valmistele Prophet-malli
df = df[['_time', '_value']].rename(columns={'_time': 'ds', '_value': 'y'})
df['ds'] = pd.to_datetime(df['ds']).dt.tz_localize(None)
m = Prophet(daily_seasonality=True, weekly_seasonality=True, changepoint_prior_scale=0.05)
m.fit(df)
# Ennusta 7 päivää eteenpäin
future = m.make_future_dataframe(periods=168, freq='H') # 7 vrk x 24 h
forecast = m.predict(future)
# Tallenna ennuste InfluxDB:hen (bucket: forecasts)
# Tarkista: jos yhat_lower < 20% -> alarmi "Akkukapasiteetti alle 20% 48h sisällä"
`
`python
# anomaly_detection.py
import pandas as pd
import numpy as np
from sklearn.ensemble import IsolationForest
from influxdb_client import InfluxDBClient
import os
# Hae multi-muuttujadata (lämpö, paine, RPM, jännite, virta)
client = InfluxDBClient(url="http://influxdb:8086", token=os.getenv("INFLUX_TOKEN"), org="boat")
query = '''
from(bucket:"realtime")
|> range(start: -7d)
|> filter(fn: (r) => r._measurement =~ /engine_|battery_|environment_/)
|> pivot(rowKey:"_time", columnKey: "_field", valueColumn: "_value")
'''
df = client.query_api().query_data_frame(query)
# Valmistele features
features = ['coolant_temp', 'oil_pressure', 'rpm', 'battery_voltage', 'battery_current', 'fuel_rate']
X = df[features].dropna()
# Isolation Forest (contamination=0.01 -> ~1% anomaliat)
iso_forest = IsolationForest(contamination=0.01, random_state=42, n_estimators=200)
df['anomaly_score'] = iso_forest.decision_function(X)
df['is_anomaly'] = iso_forest.predict(X) == -1
# Tallenna anomaliat InfluxDB:hen
anomalies = df[df['is_anomaly']]
# Kirjoita InfluxDB:hen (measurement: anomalies)
`
`yaml
# grafana/provisioning/dashboards/dashboard-engine-monitoring.yml
apiVersion: 1
providers:
orgId: 1
folder: 'Engine'
type: file
disableDeletion: false
updateIntervalSeconds: 10
allowUiUpdates: true
options:
path: /etc/grafana/provisioning/dashboards/engine
---
# dashboards/engine-overview.json (JSON dashboard)
{
"title": "Engine Overview",
"panels": [
{"title": "RPM", "type": "timeseries", "targets": [{"expr": "engine_rpm", "legendFormat": "RPM"}]},
{"title": "Coolant Temp", "type": "gauge", "targets": [{"expr": "coolant_temp", "legendFormat": "°C"}], "fieldConfig": {"defaults": {"thresholds": {"mode": "absolute", "steps": [{"value": null, "color": "green"}, {"value": 90, "color": "yellow"}, {"value": 95, "color": "red"}]}}}},
{"title": "Oil Pressure", "type": "gauge", "targets": [{"expr": "oil_pressure", "legendFormat": "bar"}]},
{"title": "Fuel Rate vs Speed", "type": "xy", "targets": [{"expr": "fuel_rate", "legendFormat": "L/h"}, {"expr": "speed_knots", "legendFormat": "kn"}]},
{"title": "Battery SOC", "type": "gauge", "targets": [{"expr": "battery_soc", "legendFormat": "%"}]},
{"title": "Anomaly Score", "type": "timeseries", "targets": [{"expr": "anomaly_score", "legendFormat": "Score"}], "thresholds": [{"value": -0.5, "color": "red"}]}
]
}
`
`yaml
# alertmanager.yml
global:
resolve_timeout: 5m
route:
group_by: ['alertname', 'severity']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
receiver: 'default'
routes:
severity: critical
receiver: 'critical-alerts'
continue: true
severity: warning
receiver: 'warning-alerts'
receivers:
webhook_configs:
http_config:
basic_auth:
username: 'user'
password: 'pass'
webhook_configs:
http_config:
basic_auth:
username: 'bot'
password: '<TOKEN>'
telegram_configs:
chat_id: <CHAT_ID>
message: '{{ range .Alerts }}🚨 CRITICAL: {{ .Annotations.summary }}{{ end }}'
webhook_configs:
chat_id: <CHAT_ID>
inhibit_rules:
severity: 'critical'
target_match:
severity: 'warning'
equal: ['alertname', 'instance']
`
| Taso | Ehto | Toiminto | Aika |
| Taso 1 (Info) | Lämpö > 85°C | ntfy/Telegram "Info" | Heti |
| Taso 2 (Warning) | Lämpö > 90°C > 5 min | Telegram + Email | 5 min |
| Taso 3 (Critical) | Lämpö > 95°C > 2 min | Telegram + Email + SMS (Twilio) + Puhelin (Twilio Voice) | 2 min |
| Taso 4 (Eskaloitu) | Ei vastattu 15 min | Puhelin seuraavalle vastuulliselle + SMS kaikille | 15 min |
---
| Ratkaisu | Laitteisto | Ohjelmisto | Hinta (n.) | Ylläpito/vko | ML/Analytics |
| DIY Perus | 3× RuuviTag + SmartShunt | Pi + Mosquitto + InfluxDB + Grafana | 350 € | 1–2 h | Threshold, Z-Score |
| DIY Edistynyt | 5× RuuviTag + SmartShunt + YDWG-02 | Pi + InfluxDB + Grafana + Signal K + Alertmanager + ntfy/Telegram | 550 € | 0.5 h | Threshold, Rate-of-Change, Z-Score, Prophet |
| DIY + ML | Sama + lisäantureita | Sama + Python ML Pipeline (Prophet, Isolation Forest) | 600 € | 1 h | Prophet, Isolation Forest, ARIMA |
| Valmis (Cerbo GX + VRM + Grafana Cloud) | Cerbo GX + RuuviTagit + YDWG-02 + SmartShunt | VRM Portal + Grafana Cloud + Alerting | 1200 € + 50 €/kk | 0.1 h | Grafana Cloud ML (beta), Prophet |
| Ammattilainen (Grafana Cloud + ML Pipeline) | Cerbo GX + RuuviTagit + YDWG-02 + Custom sensors | Grafana Cloud + Managed Alerting + IRM + ML Pipeline (AWS/GCP) | 1200 € + 200 €/kk | 0.05 h | Custom ML (SageMaker/Vertex AI), Prophet, Isolation Forest |
---
Miksi InfluxDB eikä PostgreSQL/MySQL aika-sarjadatan tallennukseen?
Miksi Prophet ja ei ARIMA/LSTM?
daily_seasonality=True)Miksi Isolation Forest anomaliasarjaan?
Miten "False Positive" -alarmit vältyvät?
for: 5m -> alarmi vain jos ehto kestää 5 minMiksi Prophet ennuste 7 päivää eteenpäin ja ei pidempään?
Miten "Battery SOC Prediction" (Prophet) toimii?
ds (aika), y (SOC %)daily_seasonality=True (päivittäinen sykli), weekly_seasonality=Trueyhat (ennuste), yhat_lower/yhat_upper (luottamusväli)yhat_lower < 20% missään pisteessä -> "Akku alle 20% 48h sisällä"---
---
Mallikohtaisen käyttöohjeen saat moottorin valmistajan sivuilta:
Laaja valikoima erikoisosia. Toimitus Suomeen 5-7 arkipäivää. SVB Marine