Repository navigation
fix(mqtt): make alert attributes self-sufficient for drone triggers - #65
Merged
ifnull merged 1 commit intoAug 31, 2026
Merged
Conversation
The per-rule alert `info` topic feeds binary_sensor.airspace_alert_<rule>'s attributes, which is the only thing an automation sees when a rule fires. It was AircraftPayload-shaped only, so a drone-triggered rule carried no UA type, no height above ground, no operator location, and no registry make/model. The documented workaround was for the automation to cross-reference sensor.airspace_nearest_drone instead. That is wrong whenever more than one drone is up: the rule fires for whichever drone matched, but the message describes whichever drone is *nearest*. Two drones airborne and the notification confidently names the wrong one, with nothing to indicate it. _alert_info now merges the RID-only half of DronePayload.from_state when state.canonical.drone is set, so the alert describes the track that actually triggered. Aircraft keys stay present on a drone track rather than being branched away. They are all None there — a drone observation carries hex=None, so country_for returns None rather than a bogus registry hit from a UAS serial — and a stable key set means a consumer template only ever guards for a null value, never for a missing attribute. `is_drone` is the explicit discriminator rather than making callers infer the band from which keys happen to exist. Also emits db_metadata, which has been listed in the documented alert attribute set since the topic shipped but was never actually emitted. For a drone that is the FAA UAS make/model — the entire point of enable_drone_registry. Additive fields only; PAYLOAD_SCHEMA_VERSION is unchanged per the CHANGELOG's stated policy. A new drift guard asserts _alert_info covers every RID field DronePayload publishes, with an explicit `exempt` set for the position and provenance fields the alert topic deliberately omits — so the next field added to DronePayload fails here instead of silently going missing from alerts. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FiVqZDdasMeshTd7CqdxEp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The bug
binary_sensor.airspace_alert_<rule>'s attributes come from the per-ruleinfotopic, and that is the only thing an automation sees when a rulefires. It was
AircraftPayload-shaped only — so a drone-triggered rule(
drone_nearby) carried no UA type, no height above ground, no operatorlocation, and no registry make/model.
The documented workaround had the automation cross-reference
sensor.airspace_nearest_drone:That is wrong whenever more than one drone is up. The rule fires for
whichever drone matched; the message describes whichever drone is nearest.
Two drones airborne and the notification confidently names the wrong one, with
nothing to indicate it. The old example even documented this as a "known
limitation".
The fix
_alert_infonow merges the RID-only half ofDronePayload.from_statewhenstate.canonical.droneis set. A drone trigger carriesis_drone,id_type,ua_type,self_id,agl_ft,alt_geom_ft,ground_speed_kt,track_deg,rid_source, and the fulloperator_*set includingoperator_location_type.docs/automations.example.yaml'sdrone_nearbyexample now reads the alertentity, and the blueprint from #64 renders drone triggers:
Identity degrades FAA registry → UA category → Self-ID → "Drone".
self_idisoperator-supplied free text and untrusted, so it is a last-resort label only,
never allowed to override a resolved registry hit.
operator_location_typeis surfaced rather than blanket-labelling everyreading "operator located" —
takeoffis the drone's own launch point, not alive operator fix.
Second bug found on the way
db_metadatawas never emitted on alert attributes, despite being listedin the documented attribute set in
docs/automations.example.yamlsince thealert topic shipped. For a drone that is the FAA UAS make/model — the entire
point of
enable_drone_registry. Now published.Design note
Aircraft keys stay present on a drone track rather than being branched away.
They are all
Nonethere (a drone observation carrieshex=None, socountry_forreturnsNonerather than a bogus registry hit from a UASserial), and a stable key set means a consumer template only ever guards for a
null value, never for a missing attribute.
is_droneis the explicitdiscriminator rather than making callers infer the band from which keys happen
to exist.
Drift guards
test_covers_every_rid_field_dronepayload_publishes— asserts_alert_infocovers every RID field
DronePayloadpublishes, with an explicitexemptset for the position/provenance fields the alert topic deliberately omits.
The next field added to
DronePayloadfails here instead of silently goingmissing from alerts.
bands. It caught this during development: an aircraft-only reference set
flagged the blueprint's new drone branch as reading unpublished attributes.
Breaking?
No. Additive fields only;
PAYLOAD_SCHEMA_VERSIONstays at 1 per theCHANGELOG's stated policy (
payloads.pyis untouched — zero diff). Existingautomations reading aircraft attributes are unaffected; the keys they read keep
the same names and meanings.
🤖 Generated with Claude Code