Skip to content

Preserve Leaflet map on dynamic entity configuration updates - #219

Open
KevinBodwell wants to merge 4 commits into
nathan-gs:mainfrom
KevinBodwell:fix/preserve-map-on-entity-config-update
Open

KevinBodwell wants to merge 4 commits into
nathan-gs:mainfrom
KevinBodwell:fix/preserve-map-on-entity-config-update

Conversation

@KevinBodwell

Copy link
Copy Markdown

I use ha-map-card with auto-entities to display frequently changing geo_location data, most notably Blitzortung lightning strikes. New strikes are added as they arrive, and existing strikes move through different size/color groups as they age before eventually disappearing. Because auto-entities updates the card configuration whenever that generated entity list changes, ha-map-card was rebuilding the entire Leaflet map for each of those updates. During active weather this could mean repeatedly recreating the base tile layer for every new strike or age transition, causing unnecessary tile requests, visible map refreshes, and loss of the efficiency Leaflet normally provides by keeping the underlying map in place while only changing its data layers. The goal of this change is to let dynamic entity sets update normally—adding, changing, and removing markers—without recreating the underlying map when the map configuration itself has not changed.

  • Dynamic cards such as auto-entities call setConfig() whenever their generated entity list changes.
  • map-card currently interprets every setConfig() as requiring full setup.
  • Full setup removes and recreates the Leaflet map and base tile layer.
  • This PR detects entity-only configuration changes and reconciles entities instead.
  • Unchanged entities remain intact.
  • Added entities are created.
  • removed entities and their history layers are cleaned up.
  • entities whose configuration changes are individually recreated.
  • map/tile configuration changes still take the existing full-rebuild path.
  • You tested this against a rapidly changing set of geo_location entities where entities are added, removed, and restyled based on age.
  • Base tiles remain loaded and current pan/zoom state is preserved.

During testing, repeated failed entity creation exposed that each warning created a new Leaflet attribution control. Warning controls are now reused and duplicate messages suppressed.

  • Related to geo_location_sources #70. That issue discusses using auto-entities as a workaround for dynamically displaying Blitzortung geo_location entities. This PR does not implement native geo_location_sources support, but it makes that dynamic-entity approach substantially more efficient by avoiding a complete Leaflet map/tile-layer rebuild each time the generated entity list changes.
  • Also partially related to suppressing error messages #133: repeated failures for a temporarily unavailable/missing entity no longer create additional duplicate warning controls on each reconfiguration. This does not add a general option to suppress entity warnings.

Example config:

In this setup, new lightning entities are continuously added, existing entities move between age-based style groups, and old entities are removed, causing auto-entities to repeatedly call setConfig() on the same map-card.

type: custom:auto-entities
card:
  type: custom:map-card
  history_start: 2 hours ago
  zoom: 12
  tile_layer_url: https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png

filter:
  include:
    - domain: geo_location
      attributes:
        source: blitzortung
      last_updated: < 1m ago
      options:
        display: icon
        icon: mdi:circle
        size: 20
        color: "#ff0000"
        focus_on_fit: false

    - domain: geo_location
      attributes:
        source: blitzortung
      last_updated 1: "> 1m ago"
      last_updated 2: < 5m ago
      options:
        display: icon
        icon: mdi:circle
        size: 15
        color: "#fff200"
        focus_on_fit: false

    - domain: geo_location
      attributes:
        source: blitzortung
      last_updated: "> 30m ago"
      options:
        display: icon
        icon: mdi:circle
        size: 3
        color: "#757575"
        focus_on_fit: false

@nathan-gs

Copy link
Copy Markdown
Owner

This is a real problem — auto-entities calling setConfig() on every lightning/age change currently tears down the whole Leaflet map. Reconciling entities instead of rebuilding tiles is the right approach, and the warning-control reuse is a good extra.

Not merging yet:

  1. No tests. This is lifecycle-sensitive (add / remove / restyle / keep). Please add unit tests for _sameConfigExceptEntities, _getChangedEntityIds, and EntitiesRenderService.reconfigure (unchanged entity kept, changed entity recreated, removed entity cleanup()'d).
  2. Dead statements in _sameConfigExceptEntities:
    oldEntities;
    newEntities;
    Drop these; they will trip unused-expression lint.
  3. JSON.stringify equality is order-sensitive. auto-entities can reshuffle keys and force a full rebuild. That's safe (just slower) but worth a stable compare, or at least a comment that extra rebuilds are acceptable.
  4. entity.hass is updated only on the keep path. Please also push hass into every remaining entity on the normal render() path — that is likely the same root cause as Live marker updates fail unless history_start is explicitly configured #217 (live marker updates only work when history is subscribed).

Once tests are in I'll merge this. It will make the Blitzortung / auto-entities setup in #70 much more usable.

…-entity-config-update

# Conflicts:
#	src/components/MapCard.test.js
#	src/services/render/EntitiesRenderService.js
#	src/services/render/EntitiesRenderService.test.js
@LeeS773-prog

Copy link
Copy Markdown

I hit the same rebuild with auto-entities on a feed that changes every few seconds, and fixed it the same way in my own copy of the card: reconcile in place, keep an entity whose config is unchanged, recreate one whose config changed, and fully clean up one that left (marker, circle, GeoJSON and history stream).

On your review points: mine has the tests you asked for (unchanged entity kept, changed entity recreated, removed entity cleaned up, plus setConfig cases deciding rebuild versus in-place), and it pushes hass into every entity on the normal render() path. It still compares configs with JSON.stringify, so a reshuffled config costs a full rebuild, which you noted is safe.

@KevinBodwell, if you're still working on this, you're welcome to the tests for #219. If you'd rather hand it off, I can open a PR built on yours, with your commit kept. Whichever you prefer.

Preserve entity configuration tests alongside upstream zoom control tests.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants