Edistynyt langaton valvonta - ennakoiva analytiikka, anomaliasarjat, ML-mallit

Tiivistelmä

Miksi edistynyt langaton valvonta?

Perusvalvonta (RuuviTag + puhelin, SmartShunt + VictronConnect) näyttää reaaliaikaiset arvot. Edistynyt valvonta tuo:

---

Edistynyt valvonnan osat

OsaPerus vs EdistynytEdistynyt ominaisuus
AnturitRuuviTag, SmartShuntRuuviTag Pro 3in1 + ulkoiset anturit (lämpötila, kosteus, paine, VKL, CO2, liike)
GatewayPuhelin / Cerbo GXRaspberry Pi 4 + YDWG-02 (MQTT) + Signal K Server + MQTT Broker
TietokantaEi (vain realtime)InfluxDB 2.x / TimescaleDB (TSDB), retention policies, continuous queries
VisualisointiPuhelin-appi / VictronConnectGrafana (dashboardit, alarmit, provisioning), Grafana Cloud
AlarmitPuhelin-notifikaatiotAlertmanager + ntfy/Telegram/Email/SMS + eskalointi (eskalointiketjut)
ML/AnalyticsEiAnomaliasarjat (Isolation Forest, ARIMA, Prophet), trendilineaarinen regressio
AutomaatioEiNode-RED / Home Assistant / Signal K Automation -> toiminta-arvot -> alarmi -> toiminto

---

OsanumeroTuoteOEM-numeroHinta
RUV-001OEM-osa
VIC-SSHUNTOEM-osa
YD-YDWG02OEM-osa

Edistynyt valvonta - laitteistovertailu

RatkaisuAnturitGatewayTietokantaVisualisointiAlarmitML/AnalyticsHintaVaikeus
DIY Perus3× RuuviTag + SmartShuntPuhelin (BT)Ei (realtime)Ruuvi Station / VictronConnectPuhelin-notifikaatiotEi250 €Helppo
DIY Edistynyt5× RuuviTag + SmartShunt + YDWG-02Pi 4 + Mosquitto + InfluxDB + Grafana + Signal KInfluxDB (TSDB)Grafana (dashboardit, alarmit)Alertmanager + ntfy/Telegram/EmailPerus (threshold, rate-of-change)550 €Keskivaikea
DIY Edistynyt + MLSama + lisäantureitaSama + ML Pipeline (Python/Flux)InfluxDB + TimescaleDBGrafana + ML DashboardAlertmanager + EskalointiAnomalia (Isolation Forest), Ennuste (Prophet)600 €Vaikea
Valmis (Cerbo GX + VRM)RuuviTag + SmartShunt + YDWG-02Cerbo GX + VRM PortalVRM Portal (30 d) / InfluxDB (valinnainen)VRM Portal / Grafana CloudVRM Portal + Push-notifikaatiotEi (VRM Advanced: perus)1200 €Helppo
Ammattilainen (Grafana Cloud + ML)RuuviTag + SmartShunt + YDWG-02 + Cerbo GXCerbo GX + Grafana AgentGrafana Cloud (Managed TSDB)Grafana CloudGrafana Cloud Alerting + IRMGrafana ML / Prophet / Custom1200 € + 50 €/kkKeskivaikea

---

Edistynyt valvonnan rakentaminen (DIY + ML)

1. Arkkitehtuurin valinta

TarveSuositus
Opiskelu/Proof-of-ConceptRuuviTagit + 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-valmisCerbo GX + RuuviTagit + SmartShunt + YDWG-02 -> VRM Portal + Grafana Cloud + Alertmanager
Ammattilainen/Laivojen valvontaCerbo GX + RuuviTagit + YDWG-02 + Cerbo GX MQTT -> Grafana Cloud + ML Pipeline (AWS/GCP/Azure)

2. Tietokannan rakentaminen (InfluxDB 2.x + Retention Policies)

`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):

BucketRetentioResoluutioKäyttötarkoitus
realtime7 d1 Hz / 10 sReaaliaikaiset dashboardit, alarmit
hourly90 d1 min (downsampled)Trendi-analytiikka, viikoittaiset raportit
daily3650 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")

`

3. Anomaliasarjat (Anomaly Detection)

Menetelmät:

MenetelmäTyyppiSoveltuvuusVaativuus
Threshold / Rate-of-ChangeTilastollinenYksinkertaiset rajat (lämpö > 95°C, paine < 1 bar)Helppo
Rate-of-Change / DerivativeTilastollinenAikaisempi varoitus (lämpö nousu > 5°C/min)Helppo
Z-Score / Modified Z-ScoreTilastollinenPoikkeamat histooriasta (lämpö > 3σ)Helppo
Isolation Forest (sklearn)ML (Unsupervised)Monimuuttujaiset anomaliat, ei tarvitse labeleitaKeskivaikea
ARIMA / SARIMA (statsmodels)ML (Time Series)Aikasarja-ennuste, kausiluontoKeskivaikea
Prophet (Facebook)ML (Time Series)Kausiluonto, holiday effects, puuttuvat arvotHelppo
LSTM/GRU (PyTorch/TensorFlow)Deep LearningMonimutkaiset kuvio, multivariaattiVaikea

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ä"

`

4. Anomaliasarja Isolation Forest (Python script)

`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)

`

4. Grafana Dashboard - Provisioning (YAML)

`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"}]}

]

}

`

5. Alarmit ja Eskalointi (Alertmanager + ntfy/Telegram)

`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']

`

5. Eskalointi (Escalation)

TasoEhtoToimintoAika
Taso 1 (Info)Lämpö > 85°Cntfy/Telegram "Info"Heti
Taso 2 (Warning)Lämpö > 90°C > 5 minTelegram + Email5 min
Taso 3 (Critical)Lämpö > 95°C > 2 minTelegram + Email + SMS (Twilio) + Puhelin (Twilio Voice)2 min
Taso 4 (Eskaloitu)Ei vastattu 15 minPuhelin seuraavalle vastuulliselle + SMS kaikille15 min

---

Edistynyt valvonta - hintavertailu (2026)

RatkaisuLaitteistoOhjelmistoHinta (n.)Ylläpito/vkoML/Analytics
DIY Perus3× RuuviTag + SmartShuntPi + Mosquitto + InfluxDB + Grafana350 €1–2 hThreshold, Z-Score
DIY Edistynyt5× RuuviTag + SmartShunt + YDWG-02Pi + InfluxDB + Grafana + Signal K + Alertmanager + ntfy/Telegram550 €0.5 hThreshold, Rate-of-Change, Z-Score, Prophet
DIY + MLSama + lisäantureitaSama + Python ML Pipeline (Prophet, Isolation Forest)600 €1 hProphet, Isolation Forest, ARIMA
Valmis (Cerbo GX + VRM + Grafana Cloud)Cerbo GX + RuuviTagit + YDWG-02 + SmartShuntVRM Portal + Grafana Cloud + Alerting1200 € + 50 €/kk0.1 hGrafana Cloud ML (beta), Prophet
Ammattilainen (Grafana Cloud + ML Pipeline)Cerbo GX + RuuviTagit + YDWG-02 + Custom sensorsGrafana Cloud + Managed Alerting + IRM + ML Pipeline (AWS/GCP)1200 € + 200 €/kk0.05 hCustom ML (SageMaker/Vertex AI), Prophet, Isolation Forest

---

UKK

Miksi InfluxDB eikä PostgreSQL/MySQL aika-sarjadatan tallennukseen?

Miksi Prophet ja ei ARIMA/LSTM?

Miksi Isolation Forest anomaliasarjaan?

Miten "False Positive" -alarmit vältyvät?

  1. Cooldown / For: for: 5m -> alarmi vain jos ehto kestää 5 min
  2. Rate-of-Change: Etsii trendejä, ei yksittäisiä huippia
  3. Z-Score / Modified Z-Score: Robustempi kuin raw threshold
  4. Inhibit Rules (Alertmanager): Critical estää Warningin samalle alerille
  5. Eskalointi: Vain kriittiset -> SMS/puhelin, varoitukset -> Telegram/Email

Miksi Prophet ennuste 7 päivää eteenpäin ja ei pidempään?

Miten "Battery SOC Prediction" (Prophet) toimii?

  1. Hae viikon SOC-data (1 Hz -> 1 h resample) -> ds (aika), y (SOC %)
  2. Prophet-malli -> daily_seasonality=True (päivittäinen sykli), weekly_seasonality=True
  3. Ennusta 168 h (7 vrk) eteenpäin -> yhat (ennuste), yhat_lower/yhat_upper (luottamusväli)
  4. Alarmi: Jos yhat_lower < 20% missään pisteessä -> "Akku alle 20% 48h sisällä"

---

Liittyviä oppaita

---

Lähteet

Virallinen käyttöohje

Mallikohtaisen käyttöohjeen saat moottorin valmistajan sivuilta:

Laaja valikoima erikoisosia. Toimitus Suomeen 5-7 arkipäivää. SVB Marine