This project polls SolarEdge inverters over Modbus, combines the readings with SolarEdge cloud data, evaluates system health, and pushes notifications via Pushover/Healthchecks. The CLI also supports simulated runs for testing and a SQLite-backed state/retention layer. This can be useful to get quick notification if an inverter or optimizer has a fault.
- Modbus health checks: Reads configured inverters, evaluates per-inverter rules plus peer comparisons, and reports alerts.
- SolarEdge API integration: Pulls status/optimizer counts from the cloud when enabled, enriching alerts and summaries.
- Weather context (optional): Fetches Open-Meteo irradiance/temp/cloud cover to show per-inverter expected output alongside real readings and applies weather-aware alert suppression (irradiance floor + precip gate).
- Daylight-aware polling: A daylight policy decides whether to skip Modbus/cloud calls at night and when summaries should run.
- Simulation mode: Use
[simulation]config sections orsimulate --scenario NAMEto test alert logic with synthetic data and timestamps. - SQLite history: Per-run snapshots, optimizer counts, and site summaries are stored in
~/.solaredge_monitor_state.db(or the path you specify). - Retention/maintenance: Configurable pruning and a
maintain-dbCLI command keep the database from growing indefinitely.
Edit solaredge_monitor.conf to define your environment:
[daylight]: Timezone plus optional coordinates/sunrise/sunset windows.[modbus]&[inverter:NAME]: Global Modbus settings and per-inverter host/port/unit.[pushover],[healthchecks]: Enable flags and credentials for each notifier.[health]: Thresholds for peer comparison, low PAC/Vdc checks, etc. PAC/peer thresholds are configured as % of AC capacity (e.g.,low_pac_threshold = 0.5β 0.5% of capacity). Includesconsecutive_health_alerts(require N consecutive bad checks before alerting; the Healthchecks failure ping follows the same gate) andconsecutive_recovery_samples(require N healthy checks before sending recovery), reminder controlsidentical_alert_gate_minutesandrepeat_alert_interval_minutesfor persistent identical faults,min_alert_sun_el_deg(suppress low-PAC/Vdc/status alerts when sun elevation is below this angle),alert_irradiance_floor_wm2(suppresses PAC/sleep/low-Vdc alerts when either GHI or POA is at or below this value β using the minimum of the two prevents stale hourly GHI from masking near-sunset low-light conditions), and weather gates (precip_weather_codes,precip_cloud_cover_pct) that suppress PAC alerts when itβs 100% cloudy with precipitation.[solaredge_api]: Enable flag, API key/site ID, and optional night skipping.[weather]: Optional Open-Meteo settings (enable flag, coordinates or fallback to[daylight], tilt/azimuth/albedo, array kW DC, AC capacity, derate, NOCT, temp coefficient) to show expected per-inverter output vs. weather and optionally append JSONL rows (log_path) for tuning.[logging]: Console log level/quiet/debug module overrides plus optional structured JSONL logging (structured_enabled+structured_path). Setlog_pathto write a self-rotating log file independent of stdout redirect;log_max_bytes(default 10 MB) andlog_backup_count(default 5) control rotation. Nighttime skip messages and routine "no alerts" lines are logged at DEBUG and will not appear in the file at INFO level.[state]: Path to the SQLite database (~/.solaredge_monitor_state.dbby default).[simulation]and[simulation:scenario]: Lists of inverters plus per-field overrides (PAC/Vdc/total_wh/optimizers). Includesimulated_timeto force a specific timestamp.[retention]:snapshot_days,summary_days, andvacuum_after_prunecontrol howmaintain-dbprunes the DB.
See CHANGELOG.md for recent changes and defaults.
Run from the repo root:
python -m solaredge_monitor.main --config solaredge_monitor.conf health: One-shot real run (default).python -m solaredge_monitor.main --config ... simulate --scenario fault: Run using[simulation:fault]data.python -m solaredge_monitor.main --config ... notify-test --mode fault: Send test alerts.python -m solaredge_monitor.main --config ... maintain-db: Prune historical data per[retention]. Override with--snapshot-days,--summary-days,--no-vacuumas needed.
Use --debug for verbose logs, --json to print Modbus snapshots as JSON, and --quiet to suppress stdout output.
If [logging] structured_enabled = true, each run appends a JSON object to structured_path with:
timestamp,daylight_phase,daylight_context(is_daylight, grace flags, sunrise/sunset timestamps, skip_modbus/cloud, production_day_over)inverter_snapshots(per inverter: pac_w, vdc_v, idc_a, total_wh, status/vendor_status, serial/model, timestamp)weather_snapshot(timestamp, source_series_time used from feed, cloud_cover_pct, temp_c, wind_mps, ghi_wm2, dni_wm2, diffuse_wm2, weather_code, sun_azimuth_deg, sun_elevation_deg, provider, source_latitude/longitude, error)weather_expectations(per inverter: expected_ac_kw, expected_dc_kw, poa_wm2, cos_incidence, module_temp_c_est, temp_factor, array/ac capacity, derate, tilt/azimuth, albedo, NOCT, temp_coeff_per_c)residuals(per inverter: pac_w, expected_ac_w, residual_w, ratio)health(system_ok plus per-inverter inverter_ok/reason/reading)alerts(alerts generated this run)cloud_inventory(SolarEdge API inverter details, with raw payload)optimizer_counts(optimizer counts keyed by serial)