Skip to content

mac_mapping_* entries with non-sequential numbering are silently dropped (only first ~25 imported) #43

Description

@mok726

First of all, thanks for this great tool. I ran into an issue and used AI to help me resolve it, so I'm sharing here my findings and solution, hope it helps

Description

When mac_mapping_* entries in configuration.yaml use non-sequential numbering (e.g., mac_mapping_1, _2, _3, _6, _8...), only the first batch up to the first gap is imported. All mappings after the gap are silently dropped.
In my case, I have 91 mappings defined in YAML but only 15 (with ID less or equal 25) were saved to the config entry.

Root Cause

Both config_flow.py and sensor.py iterate MAC mappings sequentially and break on the first missing key:

config_flow.py — the while True loop starting at i=26:

i = 26
while True:
    key = f"mac_mapping_{i}"
    if key in yaml_config:
        ...
        i += 1
    else:
        break  # Stops here at first gap

sensor.py — same pattern in async_setup_entry:

i = 25
while True:
    key = f"mac_mapping_{i+1}"
    if key in config_entry.data:
        ...
        i += 1
    else:
        break  # Stops here at first gap

This means any gap in numbering (e.g., no mac_mapping_26 because numbering jumps to _28) causes everything after to be lost.

Additionally
config_flow.py passes user_input directly to async_create_entry(). Since all mac_mapping_* fields are vol.Optional, any field the user doesn't explicitly fill in is dropped from user_input. With 90+ fields this means most mappings are lost even if the form renders them.

Suggested Fix

config_flow.py — collect all mac_mapping_* keys dynamically instead of sequential iteration:

Replace the for/while loops with:

mac_keys = sorted(
    (k for k in yaml_config if k.startswith("mac_mapping_")),
    key=lambda k: int(k.split("_")[2]),
)
for key in mac_keys:
    data_schema_dict[vol.Optional(key, description={"suggested_value": yaml_config.get(key)})] = str

And merge YAML mappings on form submit so optional fields left blank aren't lost:

if user_input is not None:
    merged = dict(user_input)
    for key, value in yaml_config.items():
        if key.startswith("mac_mapping_") and key not in merged:
            merged[key] = value
    return self.async_create_entry(title="Network Scanner", data=merged)

sensor.py — same dynamic collection:

mac_keys = sorted(
    (k for k in config_entry.data if k.startswith("mac_mapping_")),
    key=lambda k: int(k.split("_")[2]),
)
mac_mappings_list = [config_entry.data.get(k, "") for k in mac_keys]

NetworkScannerOptionsFlow — same pattern for the options flow form.

Steps to Reproduce

  1. Define mac_mapping_* entries in configuration.yaml with non-sequential numbers (e.g., _1, _2, _3, _6, _8, _28, _50...)
  2. Set up the integration via the UI
  3. Check config entry data — only mappings up to the first gap are saved

Environment

  • Integration version: v1.0.7
  • Home Assistant version: 2025.10.3

Regards, Marianok

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions