Two indoor sensors, wind compass, and stop framebuffer cache thrashing
Downstairs and upstairs are now separate readings. The station names them
backwards -- "temperature_4" is downstairs and "inside_temperature" is
upstairs -- so ha_config.h says which is which. Downstairs is the primary:
big number on the card, and it is what the furnace controls on, because it
is where people are and heat rises. Upstairs sits beside it, obviously
subordinate by size, and costs no vertical space in a layout that has none.
The anemometer came back on 2026-08-07, so wind gets its own column: a dial
whose needle points at the direction the wind is coming FROM (weather-vane
convention, matching the cardinal below it), the speed, and a 5-minute trend
arrow.
- The needle does not animate. A spin would look better, but every animated
frame is a redraw, and redrawing is what starves the bounce refill ISR.
- Below 0.5 mph it shows "Calm" and draws no needle. A vane that is not
being pushed reports whatever it last settled on, which on this station
is a steady 0 degrees -- a confident needle pointing due north at zero
wind. The live snapshot caught exactly that.
- The trend is local, not HA's 10-minute average, so the window is ours to
pick: 1-minute buckets over 5 minutes, threshold 1.5 mph.
That last point needed the trend engine to stop assuming one hour. Window,
bucket size, minimum age and threshold are now per-channel in a table, which
also removes the threshold arguments main.c was passing in.
Grid drops to 117px cells to make room, so the sun sub-line is just which
event it is and "RAIN TODAY" is "RAIN" -- both were overrunning.
On the artefacts: bounce mode is NOT a DMA read of the framebuffer. The
refill is a CPU memcpy in an ISR, which is why the driver skips the usual
write-back in draw_bitmap ("the data gets read by the CPU as well"). So the
panel streams 750KB per frame at ~44Hz through the DCache, evicting the
working set of everything else on the chip, continuously -- which is the real
reason this board is so sensitive to WiFi and to any extra rendering.
bb_invalidate_cache frees each chunk after it is copied. The header warns it
"can be dangerous if data is written from other core(s)"; that does not apply
here, because it invalidates the buffer being scanned and by design LVGL only
draws into the other one. Whether it is enough is for the panel to say.
Also gives tools/ha_snapshot.py a --token-file so the token no longer has to
travel through a shell command line to reach it.
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
1 parent
7a58f9838a
commit
ea1b8b8d15
13 files changed
+435
-155
No files matched your search
@@ -140,19 +140,37 @@ The forecast is a second, slower request (every 30th poll). It cannot be part
|
||||
of the template: HA removed the `forecast` attribute from weather entities in
|
||||
2024.4, and templates cannot call services.
|
||||
|
||||
### The wind sensors are dead
|
||||
### Wind, and the compass
|
||||
|
||||
The station's anemometer has been offline since **2026-07-27**: `wind_speed`,
|
||||
`wind_gust`, `wind_direction` and `feels_like` all read `unavailable`, and the
|
||||
WIND tile shows `--` by design. It is deliberately *not* backfilled from the
|
||||
met.no forecast — regional modelled wind under a heading that means "my yard"
|
||||
is worse than showing nothing.
|
||||
The station's anemometer was offline 2026-07-27 to 2026-08-07 and is live
|
||||
again. It has its own column now: a dial whose needle points at the direction
|
||||
the wind is coming **from** (weather-vane convention, matching the cardinal
|
||||
label beneath it), the speed in mph, and an arrow for the 5-minute trend.
|
||||
|
||||
`sensor.moonlight_beach_max_gust` is a trap: it is **not** unavailable. It
|
||||
still reports its last value from 2026-07-28 and will render as a plausible
|
||||
live number. Anything that uses it needs a staleness check first.
|
||||
Three things worth knowing:
|
||||
|
||||
### Fallback
|
||||
- **The needle does not animate.** A spin would look better, but every
|
||||
animated frame is a redraw, and redrawing is what starves the bounce refill
|
||||
ISR. It snaps once a minute and the dirty area is just the dial.
|
||||
- **Below 0.5 mph it shows "Calm" and draws no needle.** A vane that is not
|
||||
being pushed reports whatever it last settled on — on this station that is a
|
||||
steady 0°, which would otherwise render as a confident needle pointing due
|
||||
north.
|
||||
- **The trend is computed locally, not taken from HA's 10-minute average.**
|
||||
`HA_TREND_CH_WIND` uses 1-minute buckets over a 5-minute window, which is as
|
||||
fine as a 60-second poll can support. The threshold is 1.5 mph — wind is
|
||||
noisy and a twitchy arrow is worse than none.
|
||||
|
||||
### Two indoor sensors
|
||||
|
||||
`temperature_4` is **downstairs** and `inside_temperature` is **upstairs** —
|
||||
the names come from the Ambient Weather console, not the house, so they read
|
||||
backwards. Downstairs is the primary: big number on the card, and it is what
|
||||
the furnace controls on, because it is where people are and heat rises.
|
||||
`HA_ENT_CONTROL_TEMP` in `ha_config.h` is the single place that choice is
|
||||
made; the big card in `ui_manager.c` should move with it.
|
||||
|
||||
### Fallback### Fallback
|
||||
|
||||
When HA cannot be reached, `ambient_weather.c` fills in outdoor temperature,
|
||||
humidity and wind from the cloud API and the status line says so. Indoor, sun,
|
||||
@@ -232,7 +250,18 @@ own reads, and the resulting corrupt pixels persist indefinitely because LVGL
|
||||
does not know they are wrong and never reinvalidates them.
|
||||
|
||||
A **20**-scanline bounce buffer stages each chunk in internal RAM (64KB across
|
||||
two buffers). This was 16 for a long time because 20 "fails to allocate once
|
||||
two buffers), with `bb_invalidate_cache` enabled.
|
||||
|
||||
That flag matters more than it looks. Bounce mode is **not** a DMA read of the
|
||||
framebuffer — the refill is a CPU `memcpy` in an ISR, which is why the driver
|
||||
skips the usual write-back in `draw_bitmap` ("the data gets read by the CPU as
|
||||
well"). So the panel streams 750KB per frame at ~44Hz *through the DCache*,
|
||||
evicting the working set of everything else on the chip, continuously. That is
|
||||
the real reason this board is so sensitive to WiFi activity and to any extra
|
||||
rendering. `bb_invalidate_cache` frees each chunk after it is copied. The
|
||||
header warns it "can be dangerous if data is written from other core(s)" —
|
||||
that does not apply here, because it invalidates the buffer being *scanned*
|
||||
and by design LVGL only ever draws into the other one. This was 16 for a long time because 20 "fails to allocate once
|
||||
WiFi is up" — which was true when `display_init()` ran after
|
||||
`wifi_init_sta()`. The two-phase split changed that: `display_alloc()` now
|
||||
takes these buffers from a virgin heap with ~200KB free, long before WiFi has
|
||||
|
||||
Reference in new issue
Block a user