Repository navigation
fix(energy): align auto-update telemetry log wording and stream lifecycle properties - #102
Merged
Merged
Conversation
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
… via target_address
fedem95
approved these changes
Oct 11, 2026
fedem95
left a comment
Contributor
There was a problem hiding this comment.
Thanks, this looks good. The WHO 18 telemetry now reflects stream duration and stop semantics, and the actuator #0 suffix is preserved. CI is green. Approved.
Non-blocking note: test_negative_interval_clamped_to_stopped currently checks a local clamp after mutating the event, rather than exercising the code path that sets _update_interval. Consider adjusting it to assert the parsed event properties and log after passing through that path.
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.
WHO 18 Dimension 1200 Auto-Update Telemetry Refinements
Follow-up to #92 addressing review observations from @fedem95 and @GreenGrassBlueOcean: refines human-readable log wording to accurately reflect session duration semantics, clamps non-negative protocol boundaries, and adds explicit
stream_durationandis_streaming_activeproperties onOWNEnergyEvent.1. What is the problem?
Misleading Telemetry Log Wording:
*#18*WHERE*1200#Type*Time##) were logged as:Sensor <where> automatic updates every <time> minutes (0 = stopped).WHO_18.pdfspecification),Timespecifies the duration of the streaming session in minutes, not the sampling frequency.*#18*WHERE*113*P##) approximately every 30 seconds or on power draw changes.Time = 0arrives to indicate the stream has finished, formatting the message as"automatic updates every 0 minutes (0 = stopped)"was unnatural and confusing.Semantic Gap in Event Properties:
OWNEnergyEventexposedupdate_intervalto store the decodedTimeparameter.MyHOME) had to manually checkif event.update_interval > 0vs== 0to determine streaming state.Boundary Value Handling:
start_sending_instant_power(where, 0)previously emitted a log saying"for 0 minutes"rather than"Stopping".Documentation Discrepancy:
energy_typedocstring did not explicitly delineate official specification boundaries (Type 1 = active powerin LegrandWHO_18.pdf) from extended media types (2 gas, 3 heat, 4 water from BTicino touch screenlibqtdevices).update_intervaldocstring did not note thatstream_durationis the preferred property name.2. How is it solved?
Human-Readable Log Formatting:
update_interval > 0:Sensor <sensor> automatic updates for <update_interval> minutes.update_interval == 0:Sensor <sensor> automatic updates stopped.Added Typed Properties to
OWNEnergyEvent:stream_duration: Typed property alias returningint | Nonerepresenting the stream duration in minutes (0when stopped). Preservesupdate_intervalfor 100% backward compatibility with existing callers.is_streaming_active: Typed boolean property returning:Trueif updates are streaming (update_interval > 0),Falseif stream has stopped (update_interval == 0),Noneif the event is not a Dimension 1200 event.Defensive Clamping & Command Logging:
_update_intervaland_energy_typeare clamped withmax(0, ...)to ensure duration is strictly non-negative.start_sending_instant_power(where, duration)clampsduration = 255 if duration > 255 else max(0, int(duration))and formats log as"Stopping..."whenduration == 0.Clarified Docstrings:
update_intervaldocumented as retained for backward compatibility with preference forstream_duration.stream_durationdocumented as stream duration in minutes (0..255 per Legrand WHO 18).energy_typedocumented with explicit provenance (Type 1per Legrand WHO 18,Types 2–4perlibqtdevices).WHO 18 Dimension 1200 Event Telemetry Summary
message_typeupdate_interval/stream_durationis_streaming_activehuman_readable_log*#18*51*1200#1*255##auto_update_interval255TrueSensor 1 automatic updates for 255 minutes.*#18*51*1200#1*2##auto_update_interval2TrueSensor 1 automatic updates for 2 minutes.*#18*51*1200#1*0##auto_update_interval0FalseSensor 1 automatic updates stopped.*#18*51*113*1234##active_powerNoneNoneSensor 1 is reporting an active power draw of 1234 W.3. How is it tested?
Unit Test Assertions (
tests/test_who18_auto_update_reply.py):test_auto_update_confirmation_is_parsed: assertsstream_duration == 255,is_streaming_active is True, and exact log string"Sensor 1 automatic updates for 255 minutes.".test_auto_update_stop_is_parsed: assertsstream_duration == 0,is_streaming_active is False, and exact log string"Sensor 1 automatic updates stopped.".test_other_dimensions_are_untouched: verifies non-1200 events retainstream_duration is Noneandis_streaming_active is None.test_builder_duration_zero_or_negative: assertsstart_sending_instant_powerwith0or negative duration produces*#18*51*#1200#1*0##with"Stopping"log.test_negative_interval_clamped_to_stopped: verifies corrupted/negative values clamp safely to 0 and report stopped.Full Regression & Standards Verification:
pytest -p no:homeassistant).scripts/verify_library_standards.pypassed with 0 errors.scripts/verify_coverage.pyreports 100.0% coverage across all 24 modules (3,946 / 3,946 statements).ruff checkandmypypass with 0 errors.4. Where are the real traces?
All duration and lifecycle semantics are grounded in authentic, unedited on-wire bus captures from live customer installations:
On-Wire Customer Plant Capture (
MyHOME#664):tests/fixtures/traces/issue_466/myhome_trace_F454_who18_2026-10-08T19-30-16.json19:27:40: Meter 56 broadcasts passive power:*#18*56*113*...##.19:27:55.541: Controller requests automatic streaming for 2 minutes:*#18*56*#1200#1*2##.19:27:55.612: Meter confirms duration:*#18*56*1200#1*2##.*113*frames ~every 30 seconds.19:30:01.726: Meter emits stream stop frame:*#18*56*1200#1*0##(exactly 126.2 seconds later).Official Protocol Specification:
WHO_18.pdfv1.0.0, 2011-07-15):*#18*WHERE*#1200#Type*Time##(Time1..255 minutes).*#18*WHERE*#1200#Type*0##(Time = 0).*#18*WHERE*1200#Type*Time##.Gateway Translator Binary Analysis (
bt_supervisione):*#18*51*#1200#1*255##ACKs with SCS telegramD1 A1 02 32 00 02 1D FF, and stop frame*#18*51*#1200#1*0##ACKs withD1 A1 02 32 00 02 1D 00.