141 lines
5.2 KiB
Markdown
141 lines
5.2 KiB
Markdown
# 2026-05-01 — fix 5-minute spikes on AC-output power time-series
|
||
|
||
## Symptom
|
||
|
||
On both inverters' apparent-power and active-power Influx series, a tall
|
||
rectangular spike to **exactly 6000 VA / 6000 W** appeared every ~5 minutes.
|
||
The spike was simultaneous on both units even though they are not paralleled
|
||
on AC output (and on this rig the AC outputs aren't even tied to a common
|
||
load), which ruled out any real-load mechanism.
|
||
|
||
90-min sample (idle unit 2, baseline ~47 VA / ~0 W):
|
||
|
||
| metric | spike value | spike count | inter-spike gap |
|
||
|-----------------------|---------------|-------------|-----------------|
|
||
| `VA` | **6000** (only) | 36 / 30 min | pairs ~3–5s, 298s between pairs |
|
||
| `W` | **6000** (only) | 12 / 30 min | same pattern |
|
||
|
||
Unit 1 spiked at `:37:12 / :42:15 / :47:17 / …`, unit 2 at `:37:44 / :42:46 / …`.
|
||
Each cycle is exactly 5 min; the two daemons sit ~32 s out of phase, so on
|
||
charts binned > 1 min they look simultaneous.
|
||
|
||
## Root cause
|
||
|
||
`6000` is the LVX6048's **nameplate** apparent / active power. Two PI18
|
||
commands return that field:
|
||
|
||
- `GS` (every 5 s): live measurement
|
||
- `PIRI` (every 300 s): nameplate / configured rating
|
||
|
||
In `powermon-patches/pi18.py` both fields share the same `description`
|
||
string (`"AC Output Apparent Power"`, `"AC Output Active Power"`).
|
||
Powermon's `outputformats/hass.py` slugifies `description` into the HA
|
||
entity_id with **no per-command namespace**, so both publish to:
|
||
|
||
```
|
||
homeassistant/sensor/lvx6048_X_ac_output_apparent_power/state
|
||
homeassistant/sensor/lvx6048_X_ac_output_active_power/state
|
||
```
|
||
|
||
Every 300 s when PIRI fires, the entity is written with `6000` for one
|
||
publish; the next GS (≤5 s later) restores the live value. HA's recorder
|
||
captures both → Influx records a 6000-valued sample tagged to the live
|
||
entity. Hence the periodic rectangular spike.
|
||
|
||
The same collision exists for several other PIRI fields whose descriptions
|
||
duplicate live GS fields:
|
||
|
||
- `AC Input Voltage`
|
||
- `AC Input Current` *(not in GS, but shadows the live current series via
|
||
PIRI's nameplate input rating)*
|
||
- `AC Output Voltage`
|
||
- `AC Output Frequency`
|
||
- `AC Output Current`
|
||
- `Battery Voltage`
|
||
|
||
Same artifact, just less visible because nameplate values for those are
|
||
close to live values during steady-state operation.
|
||
|
||
## Fix
|
||
|
||
Add `excl_filter` to the `PIRI` command block in both powermon configs
|
||
(matches the existing pattern used on `GS` for dead/dummy fields). PIRI's
|
||
job in this stack is to publish *configured* thresholds — bulk/float
|
||
voltages, charging-current ceilings, source priorities, etc. The fields
|
||
that duplicate GS measurements provide no value and only corrupt the
|
||
recorder series.
|
||
|
||
```yaml
|
||
- command: PIRI
|
||
trigger:
|
||
every: 300
|
||
outputs:
|
||
- type: mqtt
|
||
topic: powermon/lvx6048_X/PIRI
|
||
format:
|
||
type: hass
|
||
discovery_prefix: homeassistant
|
||
entity_id_prefix: lvx6048_X
|
||
excl_filter: '^(ac_input_voltage|ac_input_current|ac_output_voltage|ac_output_frequency|ac_output_current|ac_output_apparent_power|ac_output_active_power|battery_voltage)$'
|
||
```
|
||
|
||
Applied to both `config/powermon/powermon.yaml` and `…/powermon2.yaml`,
|
||
and mirrored to the live `~/.config/powermon/` deploys.
|
||
|
||
## Net effect
|
||
|
||
| Metric | Before | After |
|
||
|-----------------------------------------|----------|-------|
|
||
| `VA` series spurious 6000 spikes / 5 min| 2/inverter| 0 |
|
||
| `W` series spurious 6000 spikes / 5 min| 2/inverter| 0 |
|
||
| PIRI fields published per inverter | 26 | 18 |
|
||
| PIRI fields kept (battery/charge/priority configs) | — | all retained |
|
||
|
||
PIRI configuration entities (battery thresholds, MCHGC ceilings, output
|
||
priority, etc.) are unchanged — they continue to update every 300 s on
|
||
their own entity_ids.
|
||
|
||
## Files touched
|
||
|
||
```
|
||
M LVX6048/config/powermon/powermon.yaml (excl_filter on PIRI)
|
||
M LVX6048/config/powermon/powermon2.yaml (same)
|
||
A LVX6048/2026-05-01.md (this file)
|
||
```
|
||
|
||
## How to verify
|
||
|
||
```bash
|
||
sudo systemctl restart powermon.service powermon2.service
|
||
|
||
# Watch one PIRI cycle (≤5 min) — apparent power should NOT publish a 6000:
|
||
mosquitto_sub -h 10.0.0.41 -u mqtt -P <pass> \
|
||
-t 'homeassistant/sensor/lvx6048_+_ac_output_apparent_power/state' -W 360
|
||
|
||
# Or query Influx after one full cycle:
|
||
influx -host 10.0.0.41 -username homeassistant -password <pass> \
|
||
-database homeassistant -execute "
|
||
SELECT count(\"value\") FROM \"VA\"
|
||
WHERE (\"entity_id\" = 'lvx6048_lvx6048_1_ac_output_apparent_power'
|
||
OR \"entity_id\" = 'lvx6048_lvx6048_2_ac_output_apparent_power')
|
||
AND \"value\" = 6000
|
||
AND time > now() - 30m"
|
||
# Expect: count → 0 once the next two PIRI cycles have passed without spikes.
|
||
```
|
||
|
||
## Rollback
|
||
|
||
```bash
|
||
git -C ~/solar checkout HEAD~1 -- LVX6048/config/powermon/
|
||
cp ~/solar/LVX6048/config/powermon/powermon{,2}.yaml ~/.config/powermon/
|
||
# (re-edit ~/.config/powermon/*.yaml to restore real MQTT_PASSWORD)
|
||
sudo systemctl restart powermon.service powermon2.service
|
||
```
|
||
|
||
## Upstream-fix candidate
|
||
|
||
Cleaner (but invasive) alternative would patch `outputformats/hass.py` to
|
||
namespace entity_ids by command (e.g., `_settings_` infix for PIRI). Not
|
||
worth the patch maintenance — the `excl_filter` is one line per command
|
||
and survives powermon upgrades.
|