Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions custom_components/ocpp/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,15 +167,19 @@ async def async_step_cp_user(
**user_input,
CONF_NUM_CONNECTORS: self._detected_num_connectors,
}
self._data[CONF_CPIDS].append({self._cp_id: cp_data})
cpids_list = self._data.get(CONF_CPIDS, []).copy()
cpids_list.append({self._cp_id: cp_data})
self._data = {**self._data, CONF_CPIDS: cpids_list}

Comment on lines +170 to +173
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

⚠️ Potential issue

Prevent duplicate CPIDs and fix CPID mismatch (discovery vs. user input).

Good switch to immutable update, but we always append and we key by self._cp_id while duplicate-checking uses user_input[CONF_CPID] (nested field not covered by _async_abort_entries_match). This can create duplicate CPIDs and ignores a potential mismatch between discovered cp_id and the value entered in the form.

  • Update-or-insert the CPID (not always append).
  • Optionally enforce that user_input[CONF_CPID] == self._cp_id or ignore the form’s CPID to avoid drift.

Apply:

-            cpids_list = self._data.get(CONF_CPIDS, []).copy()
-            cpids_list.append({self._cp_id: cp_data})
-            self._data = {**self._data, CONF_CPIDS: cpids_list}
+            cpids_list = list(self._data.get(CONF_CPIDS, []))  # shallow copy
+            # Update if CP already exists, else append
+            existing_idx = next((i for i, d in enumerate(cpids_list) if self._cp_id in d), -1)
+            if existing_idx >= 0:
+                cpids_list[existing_idx][self._cp_id] = cp_data
+                cp_idx = existing_idx
+            else:
+                cpids_list.append({self._cp_id: cp_data})
+                cp_idx = len(cpids_list) - 1
+            self._data = {**self._data, CONF_CPIDS: cpids_list}

Optional (enforce discovery CPID):

-            # Don't allow duplicate cpids to be used
-            self._async_abort_entries_match({CONF_CPID: user_input[CONF_CPID]})
+            # Enforce the discovered CPID; reject mismatches early
+            if user_input[CONF_CPID] != self._cp_id:
+                return self.async_abort(reason="cp_id_mismatch")

Also applies to: 162-169

🤖 Prompt for AI Agents
In custom_components/ocpp/config_flow.py around lines 162-173, the current code
always appends a new CPID entry keyed by self._cp_id and can create duplicates
or drift from the CPID supplied in user_input; change this to update-or-insert
the cpids list instead of always appending, by searching existing entries for a
matching CPID key and replacing its data if found, otherwise append; also
resolve the potential mismatch by either enforcing user_input[CONF_CPID] ==
self._cp_id (raise/abort if different) or ignore the form CPID and always use
self._cp_id as the canonical key/value before updating the list; apply the same
fix to the earlier block at lines 162-169.

if user_input[CONF_MONITORED_VARIABLES_AUTOCONFIG]:
self._data[CONF_CPIDS][-1][self._cp_id][CONF_MONITORED_VARIABLES] = (
DEFAULT_MONITORED_VARIABLES
)
return self.async_update_reload_and_abort(
self._entry,
data_updates=self._data,
self.hass.config_entries.async_update_entry(
self._entry, data=self._data
)
return self.async_abort(reason="Added/Updated charge point")

Comment on lines 174 to +182
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Write to the correct CP entry and ensure runtime picks up changes (reload).

  • When autoconfig is true, we currently update [-1]. If we updated an existing CP above, [-1] may point to the wrong CP. Use the computed cp_idx.
  • After updating entry data, reload the entry or use the HA helper to ensure the running integration observes the new CP immediately.
-            if user_input[CONF_MONITORED_VARIABLES_AUTOCONFIG]:
-                self._data[CONF_CPIDS][-1][self._cp_id][CONF_MONITORED_VARIABLES] = (
-                    DEFAULT_MONITORED_VARIABLES
-                )
-                self.hass.config_entries.async_update_entry(
-                    self._entry, data=self._data
-                )
-                return self.async_abort(reason="Added/Updated charge point")
+            if user_input[CONF_MONITORED_VARIABLES_AUTOCONFIG]:
+                self._data[CONF_CPIDS][cp_idx][self._cp_id][CONF_MONITORED_VARIABLES] = (
+                    DEFAULT_MONITORED_VARIABLES
+                )
+                # Option A (preferred if available):
+                return self.async_update_reload_and_abort(
+                    entry=self._entry,
+                    data=self._data,
+                    reason="cp_added_or_updated",
+                )
+                # Option B (fallback):
+                # self.hass.config_entries.async_update_entry(self._entry, data=self._data)
+                # await self.hass.config_entries.async_reload(self._entry.entry_id)
+                # return self.async_abort(reason="cp_added_or_updated")

To confirm whether async_update_reload_and_abort is available in your HA base and used elsewhere in the repo:


🏁 Script executed:

#!/bin/bash
rg -n "async_update_reload_and_abort|async_reload\(" -g '!**/venv/**' -C2

Length of output: 148


🏁 Script executed:

#!/bin/bash
# Search for async_update_reload_and_abort and async_reload usages in the codebase
rg -n "async_update_reload_and_abort" -C2 .
rg -n "async_reload\(" -C2 .

Length of output: 2445


🏁 Script executed:

#!/bin/bash
# Search for cp_idx occurrences and context in config_flow.py
rg -n "cp_idx" -C3 custom_components/ocpp/config_flow.py

Length of output: 0


Compute correct CP index and reload entry after update (config_flow.py 174–182)

  • Don’t use [-1]; locate the CP’s position in self._data[CONF_CPIDS], e.g.:
    cp_list = self._data[CONF_CPIDS]
    cp_idx = next(i for i, cp in enumerate(cp_list) if self._cp_id in cp)
    self._data[CONF_CPIDS][cp_idx][self._cp_id][CONF_MONITORED_VARIABLES] = DEFAULT_MONITORED_VARIABLES
  • After calling self.hass.config_entries.async_update_entry(self._entry, data=self._data), invoke the existing reload helper to apply changes immediately:
    await async_reload_entry(self.hass, self._entry)
🤖 Prompt for AI Agents
In custom_components/ocpp/config_flow.py around lines 174 to 182, the code uses
[-1] to set monitored variables for a charge point which can target the wrong
CP; find the actual index of the CP in self._data[CONF_CPIDS] by locating the
dict that contains self._cp_id, set CONF_MONITORED_VARIABLES on that computed
index instead of using [-1], call
self.hass.config_entries.async_update_entry(self._entry, data=self._data) as
before, and then await the existing async_reload_entry helper for this entry to
apply the changes immediately.

else:
return await self.async_step_measurands()

Expand All @@ -201,10 +205,11 @@ async def async_step_measurands(self, user_input=None):
self._data[CONF_CPIDS][-1][self._cp_id][CONF_MONITORED_VARIABLES] = (
self._measurands
)
return self.async_update_reload_and_abort(
self._entry,
data_updates=self._data,

self.hass.config_entries.async_update_entry(
self._entry, data=self._data
)
return self.async_abort(reason="Added/Updated charge point")

return self.async_show_form(
step_id="measurands",
Expand Down
Loading