Skip to content

Keep alerts that leave an optional field out - #130

Open
ptarjan wants to merge 2 commits into
mezz64:masterfrom
ptarjan:fix/partial-event-parsing
Open

Keep alerts that leave an optional field out#130
ptarjan wants to merge 2 commits into
mezz64:masterfrom
ptarjan:fix/partial-event-parsing

Conversation

@ptarjan

@ptarjan ptarjan commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

process_stream() read eventState and activePostCount as tree.find(...).text, with one try wrapped around the whole block. A device that leaves either element out of a packet therefore lost the entire alert — including the event type and channel id it did send — and logged:

Problem finding attribute: 'NoneType' object has no attribute 'text'

An empty <activePostCount/> is worse. int('') raises ValueError from outside that try, and the caller in alert_stream() catches ValueError as a dropped connection, so a single malformed packet tears the stream down and reconnects with backoff.

Reproduced on master, one motion alert per row:

packet before after
complete active, published active, published
no <activePostCount> dropped, error logged active, published
no <eventState> dropped, error logged active, published
empty <activePostCount> ValueError out of process_stream() active, published

Each field is now read on its own. Only eventType is required. A device that omits eventState only posts while the event is happening, so the packet itself is the active signal and update_stale() clears it as it already does for events that never post an inactive packet; an unusable post count is reported as 0.

Also tightened the channel-id loop so echid can only ever end up an int or None — it could previously fall out of the loop still holding an Element, which fetch_attributes() then silently failed to match.

Testing

Five tests added; four fail on master. Full suite: 69 passed, 1 skipped.

Verified live against a DS-7608NI-EV2/8P (V3.4.96). 120 real packets captured off alertStream over five minutes — this NVR always sends both fields, so the bad packets come from other models or firmware, but note it sends dynChannelID for VMD and channelID for videoloss, i.e. which optional elements appear already varies per event type on one device. With the patch the live stream connects and delivers events normally (8 callbacks in 25 s across three channels), and replaying one of those real packets with eventState and activePostCount stripped now delivers the event instead of discarding it.

Reported downstream in home-assistant/core#173869 (84 occurrences of the log line, "events stopped coming to HA but third-party apps still get them") and home-assistant/core#144386.

A packet missing eventState or activePostCount died on .text of a None
find() result, and the one try/except around the whole block turned that
into "Problem finding attribute: 'NoneType' object has no attribute
'text'" and discarded the event -- including its event type and channel,
which were present. An empty activePostCount was worse: int('') raised
ValueError out of process_stream(), and the caller reads ValueError as a
dropped connection, so one malformed packet cost the whole stream a
reconnect and its backoff.

Read each field on its own instead. Only the event type is required; a
missing state means the device only posts while the event is happening,
so treat the packet as active and let update_stale() clear it, and an
unusable post count is reported as 0.
assertNoLogs landed in 3.10, so the four tests on master that use it, and
the five added here, error out on the 3.9 leg of the matrix. Install a
context-manager equivalent when the real one is missing.
@ptarjan

ptarjan commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

CI was red on the 3.9 leg: assertNoLogs only exists from 3.10. Four of the nine errors were already there on master (UnsupportedSensorTypeTestCase, MotionDetectionUnsupportedTestCase) — the new matrix has been failing 3.9 since it landed — so the shim in e00efe8 fixes those too. All four legs green now.

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.

1 participant