The project collects and monitors data from the following home systems:
- Kostal Plenticore PV Inverter
- IDM Heatpump
- Airvisio (planned, Bedienungs- und Montageanleitung)
A Guile Scheme 3.0 daemon connects to each device via its API, collects metrics at 10-second intervals, and writes them to TimescaleDB.
The grafana/ folder contains dashboard configurations generated from the collected data.
- Guile 3.0
- Guile modules:
dbi,gcrypt,guile-json - libgcrypt (for AES-GCM encryption)
- PostgreSQL / TimescaleDB
make install # installs binary, modules, and systemd service
make uninstall # removes installed filesConfig is read from /etc/home-observe.cfg as a Scheme s-expression:
((plenticore
(host . "plenticore.fritz.box") ;; optional, default shown
(password . "your-password")
(connection . "host=... dbname=... user=... password=..."))
(idm
(host . "idm.fritz.box") ;; optional, default shown
(password . "your-auth-code")
(connection . "host=... dbname=... user=... password=...")))The config file is gitignored as it contains secrets.
Tables are created automatically on first run via CREATE TABLE IF NOT EXISTS with TimescaleDB hypertable extension.
CREATE TABLE IF NOT EXISTS plenticore (
time TIMESTAMPTZ NOT NULL,
home_p double precision not null,
home_p_pv double precision not null,
home_p_bat double precision not null,
home_p_grid double precision not null,
iv_state smallint not null,
iv_limit double precision not null,
iv_em_state smallint not null,
iv_digi_in bit(4) not null,
iv_p double precision not null,
iv_freq double precision not null,
iv_cosphi double precision not null,
iv_l1_u double precision not null,
iv_l1_i double precision not null,
iv_l1_p double precision not null,
iv_l2_u double precision not null,
iv_l2_i double precision not null,
iv_l2_p double precision not null,
iv_l3_u double precision not null,
iv_l3_i double precision not null,
iv_l3_p double precision not null,
pv1_u double precision not null,
pv1_i double precision not null,
pv1_p double precision not null,
pv2_u double precision not null,
pv2_i double precision not null,
pv2_p double precision not null,
bat_u double precision not null,
bat_i double precision not null,
bat_p double precision not null,
bat_soc smallint not null,
bat_cycles integer not null,
grid_p double precision not null
) WITH (timescaledb.hypertable);CREATE TABLE IF NOT EXISTS idm (
time TIMESTAMPTZ NOT NULL,
heatpump_active boolean not null,
heatpump_flow double precision not null,
heatpump_return double precision not null,
heatpump_source double precision not null,
heatpump_thermal_power double precision,
heatpump_perf_number double precision,
heating_active boolean not null,
heating_set double precision not null,
heating_actual double precision not null,
circulation_active boolean not null,
freshwater_top double precision not null,
freshwater_bottom double precision not null,
buffer double precision not null
outside double precision not null
) WITH (timescaledb.hypertable);[server]
domain = example.com
root_url = %(protocol)s://%(domain)s/grafana/
serve_from_sub_path = true# This is required to proxy Grafana Live WebSocket connections.
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
upstream grafana {
server localhost:3000;
}
location /grafana/ {
proxy_set_header Host $host;
proxy_pass http://grafana;
}
location /grafana/api/live/ {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_pass http://grafana;
}
