Repository navigation
dimm kit: improve error handling, handle deleted output devices - #3868
Conversation
There was a problem hiding this comment.
Pull request overview
Improves I/O action resilience when configured devices are deleted and centralizes device logging.
Changes:
- Adds reusable fault-state error handling.
- Handles missing devices during logging and output assignment.
- Safely translates exceptions without arguments.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
packages/modules/io_actions/generator_systems/stepwise_control/api_io.py |
Handles missing inverter names. |
packages/modules/io_actions/generator_systems/stepwise_control/api_eebus.py |
Handles missing inverter names. |
packages/modules/io_actions/controllable_consumers/ripple_control_receiver/api.py |
Uses shared device logging. |
packages/modules/io_actions/controllable_consumers/dimming/api_io.py |
Uses shared device logging. |
packages/modules/io_actions/controllable_consumers/dimming/api_eebus.py |
Uses shared device logging. |
packages/modules/io_actions/controllable_consumers/dimming_direct_control/api.py |
Uses shared device logging. |
packages/modules/io_actions/common.py |
Adds resilient device-log formatting. |
packages/modules/common/fault_state.py |
Adds a fault-state context manager. |
packages/helpermodules/exceptions/registry.py |
Handles argument-less exceptions. |
packages/control/process.py |
Associates output errors with fault states. |
packages/control/io_device.py |
Wraps I/O actions in fault handling. |
Suppressed comments (5)
packages/control/io_device.py:78
- This lookup runs before checking whether the action is a dimming action. Consequently, a stale unrelated action whose I/O device was deleted now makes every dimming query raise, whereas it was previously ignored. Skip entries whose device is no longer present before opening the context.
io_device = data.data.system_data[f"io{action.config.configuration.io_device}"]
with FaultStateContext(io_device.fault_state, update_always=False):
packages/control/io_device.py:90
- The new unconditional dictionary lookup makes
dimming_set_import_power_leftfail on any stale action, including unrelated action types that this method previously skipped. Guard the lookup so a deleted I/O device cannot abort the whole iteration.
io_device = data.data.system_data[f"io{action.config.configuration.io_device}"]
with FaultStateContext(io_device.fault_state, update_always=False):
packages/control/io_device.py:100
- Resolving the I/O device before the action-type check means a deleted device belonging to any unrelated action now aborts direct-control lookup. Use a guarded lookup and continue past stale actions.
io_device = data.data.system_data[f"io{action.config.configuration.io_device}"]
with FaultStateContext(io_device.fault_state, update_always=False):
packages/control/io_device.py:111
- A stale action with a deleted controlling I/O device raises here before the ripple-control type check, so an unrelated stale action can disable this lookup. Skip missing devices before entering the context.
io_device = data.data.system_data[f"io{action.config.configuration.io_device}"]
with FaultStateContext(io_device.fault_state, update_always=False):
packages/control/io_device.py:122
- The unconditional lookup introduces the same stale-action regression for stepwise control: a deleted I/O device on any earlier action raises before non-stepwise actions can be skipped. Guard the lookup and continue when the device no longer exists.
io_device = data.data.system_data[f"io{action.config.configuration.io_device}"]
with FaultStateContext(io_device.fault_state, update_always=False):
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| return (f"Ladepunkt {data.data.cp_data[cp].data.config.name}: " | ||
| f"{data.data.cp_data[cp].data.get.powers}W, ") | ||
| if device["type"] == "io": | ||
| io = f"io{device['id']}" | ||
| return (f"{data.data.system_data[io].config.name}: " | ||
| "Leistung unbekannt, ") |
| return (f"Ladepunkt {data.data.cp_data[cp].data.config.name}: " | ||
| f"{data.data.cp_data[cp].data.get.powers}W, ") | ||
| if device["type"] == "io": | ||
| io = f"io{device['id']}" | ||
| return (f"{data.data.system_data[io].config.name}: " | ||
| "Leistung unbekannt, ") |
There was a problem hiding this comment.
🟡 Changes recommended
Failsafe timestamps can remain active after stepwise-control input devices recover.
Get a fresh assessment by requesting another Copilot review.
Review details
- Files reviewed: 11/11 changed files
- Comments generated: 4
- Review effort level: Balanced
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
There was a problem hiding this comment.
🟡 Changes recommended
Load-manager accessors still bypass stale-device isolation and can abort load-management processing.
Get a fresh assessment by requesting another Copilot review.
Review details
Suppressed comments (1)
packages/control/io_device.py:84
- The stale-device isolation is incomplete for
LoadManager:get_limit_loadmanager()andset_limit_loadmanager()still iterateself.actionsdirectly instead of using this helper/context. After the controlling I/O state is deleted,get_limit_loadmanager()callscheck_fault_state_io_device()and raises aKeyError, which can abort load-management calculation. Route both load-manager accessors through the same guarded lookup and use their existing fallback when the action is skipped.
def iter_actions_with_io_device(self) -> Iterator[Tuple[IoAction, ConfigurableIo]]:
for action in self.actions.values():
io_device = data.data.system_data.get(f"io{action.config.configuration.io_device}")
if not isinstance(io_device, ConfigurableIo):
log.error(f"I/O device io{action.config.configuration.io_device} not found.")
continue
yield action, io_device
- Files reviewed: 11/11 changed files
- Comments generated: 1
- Review effort level: Balanced
| message = (str(exception.args[0]) if exception.args else str(exception)) or exception.__class__.__name__ | ||
| return message, FaultStateLevel.ERROR |
…WB#3868) * dimm kit: improve error handling, handle deleted output devices * review, complete logging * Apply batched suggestions from code review Co-authored-by: Copilot Autofix powered by AI <[email protected]> * fixes * add pytest --------- Co-authored-by: Copilot Autofix powered by AI <[email protected]>
…WB#3868) * dimm kit: improve error handling, handle deleted output devices * review, complete logging * Apply batched suggestions from code review Co-authored-by: Copilot Autofix powered by AI <[email protected]> * fixes * add pytest --------- Co-authored-by: Copilot Autofix powered by AI <[email protected]>
* dimm kit: improve error handling, handle deleted output devices (#3868) * dimm kit: improve error handling, handle deleted output devices * review, complete logging * Apply batched suggestions from code review Co-authored-by: Copilot Autofix powered by AI <[email protected]> * fixes * add pytest --------- Co-authored-by: Copilot Autofix powered by AI <[email protected]> * PV-Reset: NO_CHARGING_ALLOWED blockiert den robustness-Reset nicht mehr (#3968) Nach PR #3966 blockierte ein eingesteckter, aber unterhalb der Einschaltschwelle wartender Ladepunkt (Zustand NO_CHARGING_ALLOWED) weiterhin dauerhaft den Reset von reserved_surplus/released_surplus - das ist aber der mit Abstand häufigste, langlebigste Zustand eines PV-ladenden Fahrzeugs. Jede Reservierung wird jedoch bereits beim Übergang in diesen Zustand freigegeben (siehe zB Counter.reset_switch_on_off()), sodass er nie mit einer noch offenen Reservierung erreicht wird - er gehörte also nie in die Blockierliste. Betroffen war zB ein Fall, in dem eine verwaiste reserved_surplus-Reservierung aus einem unterbrochenen Vorgang nie mehr zurückgesetzt wurde, wodurch die Einschaltschwelle dauerhaft nicht mehr erreicht werden konnte (PV-Laden startet gar nicht mehr) - siehe Diskussion. Ersetzt die 5 Einzelvergleiche + Chargepoint/Consumer-Fallunterscheidung + plug_state-Sonderfall durch eine einzige Zustandsliste der tatsächlich reservierungshaltenden Zustände (PERFORMING_PHASE_SWITCH, PHASE_SWITCH_DELAY, SWITCH_OFF_DELAY, SWITCH_ON_DELAY), verifiziert gegen jede +=/-=-Stelle in counter.py/ev.py/chargepoint.py. references #3908 (reply in thread) * fix: external_openwb chargepoint crashes when fault_state topic is missing (#3970) get_values() indexed received_topics[fault_state] directly, including inside its own KeyError handler - if the paired internal chargepoint hadn't published fault_state yet (startup, reconnect), the fallback crashed on the exact same missing key instead of handling it. * consumer: fix hierarchy, default usage (#3975) * consumer: fix hierarchy, default usage * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <[email protected]> --------- Co-authored-by: Copilot Autofix powered by AI <[email protected]> * fix: external_openwb occasionally missed retained MQTT topics under load (#3976) start_finite_loop()'s fixed 1s collection window left little margin for connection/handshake overhead when the paired internal chargepoint was busy (eg mid-charge), occasionally causing get_values() to miss a retained topic despite retain=True. Made the timeout configurable (default unchanged for the other 17 call sites) and doubled it for external_openwb specifically, which has to reliably collect ~20 topics over a real network hop rather than one or two local values. * Systembericht Verbraucher (#3956) * add consumers; reorganize structure * improve * fix: Ladepunkte nutzen die Abschaltschwelle der Verbraucher (#3984) calc_switch_off_threshold() liest fuer alle Lasten surplus.consumer.switch_off_threshold. surplus.vehicle.switch_off_threshold ist konfigurierbar, wird migriert und in der Debug-Ausgabe angezeigt, aber im Regelalgorithmus nirgends gelesen. Die Migration verschiebt den alten pv_charging/switch_off_threshold nach surplus/vehicle/switch_off_threshold. Damit regeln bestehende Anlagen seit dem Update mit dem neu angelegten Consumer-Default 0 statt mit dem konfigurierten Wert. * removing meter-only consumers from load management priority (#3998) * removing meter-only consumers from load management priority * review * extend for self_controlled * Potential fix for pull request finding 'Preserve pre-existing empty groups during migration' Co-authored-by: Copilot Autofix powered by AI <[email protected]> --------- Co-authored-by: Copilot Autofix powered by AI <[email protected]> * build UI (#3999) * Update: Hausverbrauch Zähler (#3991) * EVU auf Auto entspricht Ja * fix * avm: fix consumer switch_on/off using unresolved ain, fix bare return in session lookup (#3987) * build UI (#4000) * Feature negative dc charging (#3795) * Add Bidi to instant-charging * Update Koala-UI min/max DC-Sollleistung * fix * Build Themes * avm consumer: invertierte Session-Refresh-Bedingung beheben (#4001) ensure_valid_session_id() erneuerte die Session nur, wenn check_valid_session_id() False war - die Funktion liefert aber "ist ungültig" zurück, nicht "ist gültig". Dadurch wurde nie erneuert, sobald session_id einmal None oder abgelaufen war: alle Anfragen liefen dauerhaft mit sid=None und schlugen mit HTTP 403 fehl. Umbenannt zu session_id_expired(), passend zum tatsächlichen Rückgabewert. * Peak Filter: bei Rückwärtssprüngen auf Wert größer/gleich Höchststand warten (#4007) * Peak Filter: bei Rückwärtssprüngen auf Wert größer/gleich Höchststand warten * review * build UI (#4008) * Consumer: Add Daikin, EGO and EMS-ESP (#3969) * Add Daikin, EGO and EMS-ESP consumer modules * daikin: Air2Air-Fixes aus Review (Lena, PR #3969) + neues Altherma-Modul Air2Air: Name korrigiert ("Daikin Air2Air (HomeHub EKRHH)"), METER_ONLY entfernt (keine Leistungsmessung verfügbar). Neu: daikin_homehub_altherma - eigenes Modul für Daikin Altherma, da eigene Modbus-Register (EKRHH Installer Reference Guide 4PDE744838, Kap. 9, separat von Air2Air/Kap. 10). Register gegen das offizielle Handbuch geprüft: - switch_on/off: Reg 56 (Smart-Grid-Modus), analog zu Air2Airs Reg 1000 - set_power_limit: Reg 58 (Allgemeine Leistungsbegrenzung, gilt laut Handbuch unabhängig vom Smart-Grid-Modus, anders als Reg 57) - update: Input-Reg 51 (Stromverbrauch Wärmepumpe) - Altherma kann im Gegensatz zu Air2Air tatsächlich Leistung melden, daher METER_ONLY hier sinnvoll * Consumer: Add Mitsubishi and Gree AC modules (#3973) * Add Mitsubishi and Gree AC consumer modules * Mitsubishi/Gree: METER_ONLY entfernt, da keine Leistungsmessung Beide Module haben keine update()-Funktion und liefern somit keine Leistungsmessung; ConsumerUsage.METER_ONLY war daher nicht zutreffend. * Gree: tcid im Bind-Request ergänzt (Review Lena) cid muss beim Binden konstant "app" sein, tcid identifiziert das Zielgerät per MAC - bestätigt gegen tomikaa87/gree-remote und cmroche/greeclimate. * build UI (#4010) * Fixed Hours Tariff: migrate fixed-hours weekdays to Python weekday format (#4009) * Hierarchie: Entferne mit Verbraucher verknüpften Zähler (#4011) * Hierarchie: Entferne mit Verbraucher verknüpften Zähler * flake8 * Speicher-Vorrang bei Erholung von Mindest- bis Maximal-SoC (#3986) * bat_all: restore Speicher-Vorrang beim Erholen von Mindest-SoC bis Maximal-SoC * bat_all: Speicherleistung nicht ans Fahrzeug weitergeben, wenn Entladung nicht erlaubt ist * build UI (#4025) * Add ACLs consumer and load management topics (#3964) * Add acls * Add load management prio to status * fix colors theme: leftover pv_charging topic paths from PR #3812 topic migration (#3946) * Build Themes * Consumer: Add Kermi, LG Therma V, Luxtronik (#3971) * Add Kermi, LG Therma V and Luxtronik consumer modules * kermi, luxtronik: Skalierungsfaktoren korrigiert (Review #3971) Kermi Reg 301 (PV-Überschuss): war /10, muss *10 sein. Luxtronik Reg 10301 (el. Leistung): war *10, muss *100 sein. Reg 108 (Kermi) war bereits korrekt. * Sonnenbatterie: add OperationMode Optimization (#3769) * add Mode Optimization * check for valid OperatingMode * Fix load management single phase netting and Bidi discharge currents (#4012) * Lastmanagement: eigenen Ladestrom bei ein-/zweiphasigem Laden nicht mehr als Fremdlast zählen _set_current_left() entschied per min(element_current) < 0, ob der Strom eines Ladepunkts als Verbrauch oder Einspeisung zählt. Bei ein-/zweiphasigem Laden reicht dafür schon minimales negatives Messrauschen auf einer ungenutzten Phase - der eigene Ladestrom wurde dann nirgends vom Zähler-Rohwert abgezogen, das Lastmanagement hielt die eigene Ladung für Fremdlast (falsche "Maximalstromstärke erreicht"/Schieflast-Meldungen, siehe Discussion #3908). _set_power_left() hat exakt dasselbe Problem nicht, da dort schon die Gesamtleistung statt einzelner Phasenströme geprüft wird - jetzt angeglichen. * Bidi-Entladung: eigene Hardware-Stromgrenze des Ladepunkts durchsetzen check_min_max_current() rief check_cp_max_current() (setzt dc_max_current des Ladepunkt-Templates durch) nur im Lade-Zweig auf, nicht beim Entladen (BIDI_CHARGING, required_current < 0) - die vom Fahrzeug gemeldete max_discharge_power wurde beachtet, die eigene Hardwaregrenze des Ladepunkts nicht. Bug in #3795, check_cp_max_current() behandelt negative Werte bereits korrekt (Vorzeichen wird erhalten). * build UI (#4026) * Improve Monthly/Yearly Log (#3829) * Improve Log * Move generate_totals-Logger in logger.py * Fix * Fix Circular Import * Update .gitignore * fix * Ensure ramdisk folder exists * retrigger Copilot * Add Copilot suggestions * fix * Fix Tesla/Powerwall data handling and improve robustness of control loop (#3232) * tesla/powerwall: implement load management, add fail-fast handling and gateway diagnostics - add structured HTTP error handling in PowerwallHttpClient - distinguish transport, HTTP and JSON parsing failures - support fail_fast=False for non-critical requests - track cycle_failed and cookie_renewed state across one polling cycle - add fail-fast handling in device.py - stop remaining Tesla component updates once a critical Powerwall request fails - log native TCP connection state diagnostics via /proc/net/tcp(/tcp6) - emit periodic session / connection health logs - keep cookie reuse, but mark startup + reauth cycles explicitly - reduce /api/status traffic in counter.py - fetch firmware only after startup or after a new auth cookie was negotiated - treat /api/status as non-critical so it cannot fail the whole cycle - keep import/export counters based on aggregate["site"]["energy_imported/exported"] - do not use summed per-phase energy counters as meter source - keep /api/meters/site for phase details only - add derived fallback currents and signed power factors from P/Q/U when Tesla/Neurio currents are 0 - expose additional diagnostics such as frequency / serial number - add throttled debug logging to compare aggregate counters with per-phase sums - restore aggregate-based site counters so load management works correctly again * tesla/powerwall: simplify device/http client and keep cookie reauth handling - remove session / connection diagnostics and analysis-only helpers - remove /proc-based connection stats and periodic session logging - keep fail-fast handling for the Tesla update cycle - keep cookie reuse and 401/403 reauthentication flow - keep support for non-critical requests via fail_fast=False - reduce implementation closer to upstream while preserving Powerwall-specific fixes * tesla/powerwall: simplify device/http client and keep local current fallback - remove analysis-only diagnostics and session tracking from device.py - remove connection stats and other debug-only helpers - simplify http_client.py to a minimal request wrapper - keep cookie reuse and 401/403 reauthentication flow in device.py - use fail-fast handling in device.py via SingleComponentUpdateContext(..., reraise=True) - move Tesla-specific robustness back into the counter module only - keep aggregate["site"]["energy_imported/exported"] as sole source for EVU counters - keep local current and power factor calculation when Neurio/Tesla returns only 0 currents - remove /api/status handling from counter.py - fix formatting / lint issues (newline at EOF, spaces instead of tabs) * Fix Tesla error handling and compatibility note - use central openWB component error handling - remove Tesla-specific fail-fast handling - rely on the shared HTTP response hook - remove obsolete local API compatibility warning * se standard error handling in Tesla counter - remove _safe_float and module-specific defaults - propagate HTTP errors to central error handling - keep compatibility fallback for missing phase data - calculate phase currents from P/Q/U when Tesla reports zero currents * Fix Tesla module lint errors * Adjust Tesla API compatibility note * Error status table (#3943) * add error and warning icons to chargepoint table * Align warning icons - remove extra warning column * No tooltip for mobile - ellipsis title only if truncated * Build Themes * add consumer temperature readings to consumer card (#3974) * add consumer temperature readings to consumer card * check if temperature data is present * use getValueObject for formatting * Build Themes * Consumer: Add M-TEC, Weishaupt, Xtherma (#3972) * Add M-TEC, Weishaupt and Xtherma consumer modules * M-TEC: Reg 707 durch evcc-Quelle bestätigt, Kommentar aktualisiert Reg 707 (elektrische Leistungsaufnahme) ist in evcc's mtec.yaml als holding register mit scale 1 gelistet, identisch zu unserer Implementierung. * Weishaupt: Reg 33126 entfernt (nicht verifizierbar), Xtherma: SG-Ready on/off ergänzt Weishaupt: Reg 33126 (el. Leistungsaufnahme) ist weder in der offiziellen Datenpunktliste (83807301) noch in einer ausgereiften Community-Implementierung (OStrama/weishaupt_modbus) zu finden - update()/METER_ONLY entfernt, SollwertPV (Reg 40002, offiziell dokumentiert) bleibt unverändert. Xtherma: Reg 60 (SG-Ready-Modus) ergänzt switch_on/switch_off (SUSPENDABLE_ONOFF), eigener 30min-Throttle laut Protokoll. * Fix charge cost calc (#4022) * fix chargelog energy source calculation * Add Test * fix circular error --------- Co-authored-by: LKuemmel <[email protected]> Co-authored-by: Copilot Autofix powered by AI <[email protected]> Co-authored-by: SeaSpotter <[email protected]> Co-authored-by: ndrsnhs <[email protected]> Co-authored-by: s0170071 <[email protected]> Co-authored-by: GitHub Actions <[email protected]> Co-authored-by: BrettS <[email protected]> Co-authored-by: NicoP-codeing <[email protected]>
Dimming IO
Dimming EEBUS
Dimming Direct Control
Ripple Control Receiver
Stepwise Control EEBus
Stepwise Control IO
Übergreifende Einzelprüfungen