feat: expose SHT40 ambient temperature and humidity - #89
Merged
Conversation
Boards with an SHT40 (reTerminal E1001/E1002/E1003/E1004, Sticky) broadcast the reading in the advertisement's dynamic block, so these entities need no connection and no polling -- the passive coordinator already has the data. Requires py-opendisplay 7.15.0, which added the decoder. Unlike the existing chip temperature these are primary entities: not diagnostic, and enabled by default. Ambient room temperature is what a user expects to find on the device. The block's offset within the dynamic area is per-board and cannot be assumed: E1001/E1002/E1004 use 1 while the firmware default is 7, and decoding at the wrong offset yields plausible-looking garbage (a button byte of 0x28 reads as -39.9 C). It is therefore taken from the device's own config and captured per entity at setup. Rename the chip temperature to "Chip temperature" so it is distinguishable from the new ambient one, which would otherwise take the same device-class name. This is a translation_key only; the entity key -- and so the unique_id -- stays "temperature", so existing entities keep their id and history. Also pass the configured button byte indices to AdvertisementTracker. Only the bytes a BinaryInputs packet claims are buttons; the rest belong to touch controllers and sensors and decode into valid-looking button reports, so without this a refreshed SHT40 reading emits phantom button transitions. event.py filters by byte_index before firing an entity, so nothing was user-visible, but the events were produced on every advertisement.
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.
Requires py-opendisplay 7.15.0 (manifest bumped), which added the SHT40 decoder and the tracker filtering this uses.
Based on
feat/clean-port, sincemainis 124 commits behind and lacks the current beta tag.Ambient temperature + humidity
Boards with an SHT40 — reTerminal E1001/E1002/E1003/E1004 and Sticky — broadcast the reading in the advertisement's dynamic block. The passive coordinator already receives it, so these entities need no connection and no polling.
They're primary entities: not diagnostic, enabled by default. Ambient room temperature is what a user expects to find on the device, unlike the MCU's own temperature.
The offset within the dynamic block is per-board and cannot be assumed — E1001/E1002/E1004 use
1while the firmware default is7— so it comes from the device's own config and is captured per entity at setup. This matters: decoding at the wrong offset produces plausible-looking garbage rather than an obvious error (a real button byte of0x28decodes as-39.9 °C / 4.0 %RH).Failed reads (
FF FF FF) and never-written slots (00 00 00) both reportunknownrather than a bogus value.Chip temperature renamed
The existing temperature entity is the MCU's, and with
device_class=TEMPERATUREand notranslation_keyit displays as plain "Temperature" — exactly the name the new ambient entity would take. Two entities called "Temperature" on one device.It's now "Chip temperature". This is a
translation_keychange only: the entitykey, and therefore theunique_id, stays"temperature", so existing entities keep their entity_id and history. It was alreadyEntityCategory.DIAGNOSTICand disabled by default, so nothing else changes.Only
strings.jsonanden.jsonare touched; the other languages come from the translation workflow.Phantom button events
AdvertisementTrackernow receives the configured button byte indices. Only the bytes aBinaryInputspacket claims are buttons; the rest belong to touch controllers and sensors, and every byte decodes into a valid-looking button report — so a refreshed SHT40 reading emitted phantombutton_slot_changedevents on every 30-second poll.event.pyfilters bybyte_indexbefore firing an entity, so nothing was user-visible; the events were simply produced and discarded on every advertisement. This is hygiene, not a user-facing bugfix.Verification
104 tests pass(94 existing + 10 new); ruff clean on the changed files.New coverage: decode at the default and at a relocated offset,
msd_data_start_byte=0resolving to the default slot, both sentinels reportingunknown, the entity-category/enabled-by-default split between ambient and chip, the chip entity keeping its unique_id key, per-instance key uniqueness, andnative_valuebefore any advertisement arrives.Verified end to end on a real E1003 earlier in this work: after adding the sensor packet to its config, the device reports
28.0 °C / 63.6 %RH.Note for whoever lands the TouchTracker refactor
There's WIP that moves
TouchTrackerconstruction intoOpenDisplayCoordinator.__init__as a third positional parameter. This PR addsbinary_inputsin that same slot. Whichever lands second should reconcile them — making one or both keyword-only is the obvious fix.