diff --git a/.claude/skills/lib/grid-cal-monitor b/.claude/skills/lib/grid-cal-monitor index 2e8046f..c118018 100755 --- a/.claude/skills/lib/grid-cal-monitor +++ b/.claude/skills/lib/grid-cal-monitor @@ -35,13 +35,29 @@ try: except:print("")'; } P(){ echo "sensor.eg4_lifepower4_lifepower4_${1}_lifepower4_${1}_${2}"; } pub(){ mosquitto_pub -h "$BHOST" -p "$BPORT" -u "$BUSER" -P "$BPASS" -t "solar/control/lvx6048/$1" -m "$2"; } +raw(){ for u in 1 2; do mosquitto_pub -h "$BHOST" -p "$BPORT" -u "$BUSER" -P "$BPASS" -t "powermon/lvx6048_${u}/addcommand" -m "$1"; done; } +# revert VERIFIES it actually took (the friendly path can silently fail — lvx-control +# used to encode POP01 which the inverter rejects, and powermon's adhoc queue can wedge). +# Ground truth = behavior: in SBU with a full bank, line_power_direction leaves 'input'. +reverted_ok(){ + local ld pop; ld=$(st sensor.lvx6048_lvx6048_1_line_power_direction) + pop=$(st sensor.lvx6048_lvx6048_1_output_source_priority) + { [ -n "$ld" ] && [ "$ld" != "input" ]; } || echo "$pop" | grep -q "Battery - Utility" +} revert(){ [ "$REVERTED" = 1 ] && return 0 log "REVERT: output_priority->solar_battery_utility, charger_priority->solar_first" - pub output_priority solar_battery_utility; sleep 3 - pub charger_priority solar_first; sleep 8 - log "REVERT done. live POP=$(st sensor.lvx6048_lvx6048_1_output_source_priority)/$(st sensor.lvx6048_lvx6048_2_output_source_priority) PCP=$(st sensor.lvx6048_lvx6048_1_charger_source_priority)/$(st sensor.lvx6048_lvx6048_2_charger_source_priority)" + pub output_priority solar_battery_utility; sleep 3; pub charger_priority solar_first; sleep 12 + if reverted_ok; then log "REVERT verified (line_dir=$(st sensor.lvx6048_lvx6048_1_line_power_direction))"; REVERTED=1; return 0; fi + # escalate: powermon adhoc may be wedged and/or friendly encode rejected -> restart + raw + for try in 1 2; do + log "REVERT not effective yet — restart powermon + raw POP1/PCP0,0 (try $try)" + sudo systemctl restart powermon.service powermon2.service 2>/dev/null; sleep 12 + raw POP1; sleep 3; raw PCP0,0; sleep 15 + if reverted_ok; then log "REVERT verified after escalation"; REVERTED=1; return 0; fi + done + log "REVERT: !!! COULD NOT CONFIRM — still grid-priority. Manually run: raw POP1 to both addcommand topics (POP1, not POP01)." REVERTED=1 } trap 'revert; log "exit"' EXIT INT TERM diff --git a/LVX6048/lvx-control/lvx-control b/LVX6048/lvx-control/lvx-control index d4e7fe1..3c0efd1 100755 --- a/LVX6048/lvx-control/lvx-control +++ b/LVX6048/lvx-control/lvx-control @@ -44,7 +44,7 @@ ADHOC_TOPICS = ( # Intentionally a strict subset of flash.py's SCHEDULE — only the safe, # day-to-day knobs. The risky-end calibration setters live in flash.py. -POP_MAP = {"solar_utility_battery": "0", "solar_battery_utility": "01"} +POP_MAP = {"solar_utility_battery": "0", "solar_battery_utility": "1"} # PI18 POP is single-digit; "01" is malformed -> inverter silently rejects (confirmed 2026-06-25, broke a calibration auto-revert) PCP_MAP = {"solar_first": "0", "solar_and_utility": "1", "solar_only": "2"} PSP_MAP = {"battery_load_utility_ac": "0", "load_battery_utility": "1"} ALLOWED_MCHGC = (10, 20, 30, 40, 50, 60, 70, 80) diff --git a/LVX6048/lvx-flash/flash.py b/LVX6048/lvx-flash/flash.py index ea26f74..587e331 100755 --- a/LVX6048/lvx-flash/flash.py +++ b/LVX6048/lvx-flash/flash.py @@ -79,7 +79,7 @@ KEY_DOCS: dict[str, str] = { "grid_tie": "enum: enabled | disabled (PEI/PDI)", } -POP_MAP = {"solar_utility_battery": "0", "solar_battery_utility": "01"} +POP_MAP = {"solar_utility_battery": "0", "solar_battery_utility": "1"} # PI18 POP is single-digit; "01" is malformed -> inverter silently rejects (confirmed 2026-06-25) PCP_MAP = {"solar_first": "0", "solar_and_utility": "1", "solar_only": "2"} PSP_MAP = {"battery_load_utility_ac": "0", "load_battery_utility": "1"} PBT_MAP = {"AGM": "0", "FLOODED": "1", "USER": "2"}