Commit Graph
41 Commits
Author SHA1 Message Date
theoandClaude Opus 5 a3bbf5639d Merge feature/vierde-module: kolom past zich aan het aantal binnenmodules aan
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 18:44:38 +02:00
theoandClaude Opus 5 ca2fc76552 fix: modulekolom past zich aan het aantal modules aan
Er is een vierde binnenmodule bijgekomen. De kaart verscheen al vanzelf
(StationMapper leest alle NAModule4-modules uit), maar de kolom was op
drie kaarten ontworpen: vier kaarten van 120px duwden de rij op 481px en
daarmee de onderste strook 39px voorbij de onderrand van het canvas.

De kolom heeft nu een vaste hoogte van 412px met overflow verborgen, en
fitRooms() verkleint de inhoud met een schaal zodra die niet past. Bij
drie modules verandert er niets (schaal 1), bij vier wordt het 0,86 en
met een vastgezette module 0,78. Zo blijft het scherm kloppen, ongeacht
hoeveel modules erbij komen.

De dev-fixture heeft er een vierde module bij, zodat dit lokaal te zien
is zonder Netatmo-koppeling. Servicewerker naar v12.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 18:44:38 +02:00
theoandClaude Opus 5 75111a5571 Merge feature/module-grafiekjes: verloop van vandaag bij elke binnenmodule
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 12:10:40 +02:00
theoandClaude Opus 5 bfc96acb5a feat: temperatuurverloop van vandaag ook bij de binnenmodules
Naast het getal in elke modulekaart staat nu hetzelfde soort lijntje als
bij buiten (200x40). Zonder labels: daar is in zo'n kaart geen ruimte
voor, de schaal staat al op de regel eronder en het venster is hetzelfde
"vandaag" als bij het grafiekje van buiten ernaast.

Per module een eigen getmeasure, gecachet onder temperature-<module> met
een gedeelde TTL; fetch() heeft daarvoor een losse ttlKey gekregen, want
anders zou de TTL-lookup per module mislukken en zou er helemaal niet
gecachet worden. Het basisstation meet zelf temperatuur en wordt zonder
module_id opgevraagd, dus die parameter is optioneel geworden. In de
payload als indoor[].history; mislukt er een, dan blijft die lijst leeg
en verdwijnt alleen dat lijntje, met de foutcode in errors. Een
stale-vlag per kamer zou het contract nodeloos zwaar maken.

De hoogte is overal 40px, ook bij een vastgezette module: gelijke hoogte
houdt de kamers onderling vergelijkbaar, en een hoger lijntje zou de
toch al krappe speling onder de kolom opeten. De grafiekjes voegen geen
hoogte toe aan de kaarten.

FakeSource houdt nu alle aanroepen bij in plaats van alleen de laatste,
zodat een test de volgorde van de vier temperatuur-calls kan nalopen.
Servicewerker naar v11.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 12:10:40 +02:00
theoandClaude Opus 5 4c4881fd11 Merge feature/temperatuurverloop: verloop van vandaag naast de buitentemperatuur
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 11:50:40 +02:00
theoandClaude Opus 5 107978b265 feat: klein grafiekje van het temperatuurverloop van vandaag
In de lege ruimte rechts van de grote buitentemperatuur staat nu het
verloop van vandaag: onderschrift "Vandaag", de lijn, en tijdlabels op
hele uren met "nu" rechts. Geen y-as, want de laagste en hoogste waarde
van vandaag staan al onder de balk en dat is precies de schaal.

Het getal en het grafiekje staan in een flexrij, zodat het grafiekje de
resterende ruimte pakt en meebeweegt als het getal smaller of breder
wordt. Vlak na middernacht zijn er nog geen twee meetpunten; dan blijft
het blokje verborgen in plaats van een leeg kader te tonen.

Data uit een extra getmeasure (scale=30min, type=Temperature, op de
buitenmodule) vanaf middernacht lokale tijd, cache 15 minuten, in de
payload als outdoor_history: {points, stale} zodat een storing daar de
rest niet raakt. PressureHistory is generiek gemaakt tot MeasureSeries
met de naam van het waardeveld als parameter, in plaats van er een bijna
identieke tweede klasse naast te zetten. StationMapper geeft nu ook het
id van de buitenmodule door.

Onderweg gevonden: FixtureSource deed een modulo op een float, wat een
PHP-deprecation vóór de JSON in de response zette. Dat verklaart de
kapotte JSON die eerder in de browserconsole langskwam. Opgelost met
intdiv. Servicewerker naar v10.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 11:50:40 +02:00
theoandClaude Opus 5 5058bb850d Merge feature/hele-uren: tijdlabels op hele uren bij de luchtdrukgrafiek
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 11:33:14 +02:00
theoandClaude Opus 5 5d61b6ec90 feat: tijdlabels op hele uren in plaats van de ruwe meettijden
De labels toonden de werkelijke meettijdstippen van Netatmo (11:41,
17:41, 23:41), wat onrustig leest. Nu markeringen op hele uren die op de
klok zijn uitgelijnd: elke 6 uur vanaf middernacht, dus 00:00, 06:00,
12:00, 18:00, elk op zijn echte tijdspositie in het venster. "nu" blijft
op de rechterrand; een markering die daar te dicht bij komt valt weg.

axisMarks() is vervangen door hourTicks(), die uur voor uur door het
venster loopt en telkens de lokale klok raadpleegt. Daardoor blijven de
labels ook op de zomertijdwissel hele lokale uren, waar optellen in vaste
stappen er een uur naast zou zitten; daar is een test voor. Een label
vlak op de linkerrand wordt niet gecentreerd, zodat het binnen de
grafiek blijft. Servicewerker naar v9.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 11:33:14 +02:00
theoandClaude Opus 5 e2db301aef Merge feature/luchtdruk-assen: x- en y-as bij de luchtdrukgrafiek
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 11:30:15 +02:00
theoandClaude Opus 5 c0715b7cc9 feat: assen bij de luchtdrukgrafiek
De lijn had geen schaal, dus je kon niet zien hoeveel hPa de uitslag was
of wanneer een dip viel. Nu links de hoogste en laagste waarde van het
venster in hele hPa, uitgelijnd op boven- en onderkant van de lijn, en
eronder vijf tijdlabels (0/25/50/75/100% van het venster) met "nu"
rechts, ondersteund door drie lichte verticale hulplijnen. Posities
komen uit de pure functie axisMarks(), met tests.

De losse tekst "1009 – 1015 hPa in 24 u" in de kopregel vervalt: de
y-as zegt hetzelfde en de x-as maakt het venster duidelijk. De extra
labelrij past door de marge onder de grote temperatuur 8px te krappen;
er blijft 5px speling boven en onder de hero. Servicewerker naar v8.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 11:30:11 +02:00
theoandClaude Opus 5 c95d198341 Merge feature/buienradar: regenradar-overlay bij een tik op het regenblok
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 11:13:32 +02:00
theoandClaude Opus 5 c542601d4e feat: tik op het regenblok voor de Buienradar-animatie
Het regenblok linksonder opent een overlay met de geanimeerde regenradar
van Buienradar (550x512, tijd in het beeld), naast de regencijfers die we
al hebben: vandaag, de 3 vorige dagen en het maandtotaal. Sluit na 20
seconden of bij een tik, net als het uuroverzicht.

Het beeld loopt via onze eigen /api/radar.php in plaats van een <img>
rechtstreeks naar Buienradar: de spec wil alles lokaal geserveerd, de
iPad praat zo nooit met een derde partij, we cachen 4 minuten (de radar
ververst elke 5) en de servicewerker kan het laatste beeld offline
bewaren. Bij een storing komt het laatst opgehaalde beeld terug; pas als
er niets is, een nette melding in plaats van een leeg vlak.
Bronvermelding staat in de overlay, zoals Buienradar vraagt.

Verder: de overlay-machinerie (20s-timer, balk, sluiten) staat nu een
keer in plaats van per overlay, Http kan optioneel redirects volgen (de
beeld-API leidt door naar een CDN), en alle /api/-paden zijn in de
servicewerker network-first met een cachesleutel zonder querystring.
Servicewerker naar v7.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 11:13:28 +02:00
theoandClaude Sonnet 5 2200a849f9 Merge feature/module-pinnen: tik op een module om bovenaan te zetten met groter font
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 10:27:14 +02:00
theoandClaude Sonnet 5 350dafe591 feat: tik op een module om die bovenaan te zetten met een groter temperatuurgetal
Tik op een van de drie binnenmodules zet die bovenaan de lijst (de
overige twee behouden hun onderlinge volgorde) en vergroot alleen het
temperatuurgetal van 50 naar 92px. Nogmaals tikken op de bovenste
(vastgezette) module zet 'm weer los. Puur client-side, geen nieuwe
API-velden: state.pinnedRoomId + de pure functie pinRoom() (met tests)
in format.js. De keuze overleeft de 5-minuten-verversing, reset bij een
volledige herlaad. Servicewerker naar v6.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 10:27:09 +02:00
theoandClaude Sonnet 5 48d68b86fa fix: treat a stale/legacy-shaped forecast cache as unavailable, not silently empty
Na de deploy van het uuroverzicht (commit 8e90eb1) bleef de nog geldige
cache op de server een tijdlang in het oude platte 'daily'-blok staan
i.p.v. het nieuwe {daily, hourly}. DashboardService::forecast() las
daaruit stil een lege verwachting zonder errors-melding. Nu wordt een
cache- of bronresultaat zonder geldig 'daily'-blok behandeld als een
storing (forecast_unavailable), zichtbaar in plaats van stil.

Handmatig verholpen op productie door de verouderde cachefile te
wissen; deze fix voorkomt herhaling bij een volgende formaatwijziging.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 10:20:00 +02:00
theoandClaude Sonnet 5 b6f4836b12 Merge feature/uuroverzicht: uuroverzicht per dag met temperatuur, regen en wind
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 10:18:17 +02:00
theoandClaude Sonnet 5 8e90eb1129 feat: uuroverzicht per dag (temperatuur, regen, wind)
Tik op een dag in de verwachtingsstrook voor een uuroverzicht van
temperatuur, regen en wind (richting + snelheid), om de 2 uur, 12
punten per dag. Sluit na 20 seconden vanzelf of bij een tik op de
overlay zelf.

Backend: Open-Meteo levert hourly-data in dezelfde call als daily
(geen extra verzoek, dezelfde 60min-cache). Nieuwe HourlyForecastMapper
groepeert per kalenderdatum en bemonstert om het andere uur, robuust
voor de zomertijddag (23/25 uur). OpenMeteoClient::dailyForecast()
hernoemd naar forecast(), geeft nu {daily, hourly} terug. Elke dag in
de forecast-array krijgt een hourly-lijst.

Frontend: temperatuurlijn hergebruikt sparklinePath (nu ook als
sparklinePoints voor exacte uitlijning met de 12-koloms grid), regen
als kleine staafjes, windpijl (nieuw icoon) wijst waarheen de wind
waait. 20s-balk via CSS transition met reflow-restart. Servicewerker
naar v5.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 10:18:11 +02:00
theoandClaude Sonnet 5 90e979f562 Merge feature/verwachting-vandaag: verwachting toont nu ook vandaag (6 dagen)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 10:01:20 +02:00
theoandClaude Sonnet 5 8bbfd62d16 feat: toon vandaag ook in de 5-daagse verwachting (nu 6 dagen)
ForecastMapper mapt voortaan index 0 t/m 5 van Open-Meteo (was 1 t/m 5),
zodat vandaag als eerste kolom in de verwachtingsstrook verschijnt naast
de bestaande 5 dagen erna. Verwachtingskolommen gaan van 5 naar 6 breed
(103px i.p.v. 124px), weericoon iets verkleind (58 -> 50px) om te passen.
Spec bijgewerkt om de wijziging vast te leggen. Service-worker-versie naar
v4 zodat het scherm dit zelf binnen enkele minuten oppikt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 10:01:14 +02:00
theoandClaude Sonnet 5 281eb1406f fix: dedupe SW registration, proactively check for updates every 5min and on foreground
Op een kiosk-scherm dat nooit navigeert gebeurt de browser-eigen update-check
voor de service worker onvoorspelbaar laat (soms pas bij de dagelijkse
04:00-reload). Roep nu expliciet registration.update() aan bij het opstarten,
elke 5 minuten en bij elke visibilitychange naar zichtbaar. Ook een eerdere
niet-bedoelde dubbele registerServiceWorker()-aanroep bij visibilitychange
verwijderd (ontstaan door een brede Python str.replace zonder count-limiet).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 09:56:21 +02:00
theoandClaude Fable 5.1 ef37c69076 Merge feature/luchtkwaliteit-luchtdruk: luchtvochtigheid, CO2-pil en luchtdrukgrafiek
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-13 09:35:53 +02:00
theoandClaude Fable 5.1 768cc7151f feat(ui): humidity, CO2 pill per room and 24h pressure sparkline
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-13 09:35:53 +02:00
theoandClaude Fable 5.1 dba1875683 feat(api): humidity, CO2, current pressure and 24h pressure history
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-13 09:34:20 +02:00
theoandClaude Fable 5.1 66bce8e8d0 chore: ignore phpunit result cache
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 15:13:54 +02:00
theoandClaude Fable 5.1 7fd49cc391 docs: deploy via Ansible on pensare-server
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 15:13:01 +02:00
theoandClaude Fable 5.1 246756438b Merge feature/weerscherm: Weerscherm v1 (backend, frontend, Netatmo, Open-Meteo, PWA, docs)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 14:50:52 +02:00
theoandClaude Fable 5.1 9dbb10a7ac fix: stack banner title and hint vertically
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 14:50:38 +02:00
theoandClaude Fable 5.1 dc8cbee8da docs: README, OrbStack notes, autoload fallback for deploys without composer
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 14:49:39 +02:00
theoandClaude Fable 5.1 e971163f71 feat: PWA manifest, app icons, service worker with tests
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 14:48:11 +02:00
theoandClaude Fable 5.1 efe6928953 fix: round rain month total to avoid float noise
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 14:46:08 +02:00
theoandClaude Fable 5.1 4250fa5abf feat: NetatmoClient with token rotation, OpenMeteoClient, LiveSource, netatmo-init
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 14:45:54 +02:00
theoandClaude Fable 5.1 dababbd1f2 feat: Http curl wrapper and TokenStore with atomic write and flock
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 14:45:18 +02:00
theoandClaude Fable 5.1 c65bc1d957 feat: frontend design A with scaling, formatting, refresh and error states
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 14:43:37 +02:00
theoandClaude Fable 5.1 6ef2d3f060 feat: format.js pure helpers with node tests, weather icons
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 14:42:06 +02:00
theoandClaude Fable 5.1 dfc28ee6c3 feat: /api/data.php with fixture source, robots.txt
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 14:40:15 +02:00
theoandClaude Fable 5.1 216b6616fc feat: DashboardService with per-source cache and stale fallback, FixtureSource
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 14:39:03 +02:00
theoandClaude Fable 5.1 89e1e544c5 feat: ForecastMapper and file Cache
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 14:38:30 +02:00
theoandClaude Fable 5.1 d657fd069f feat: RainCalculator with timezone-aware day mapping and month total
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 14:37:06 +02:00
theoandClaude Fable 5.1 12f5f97a53 feat: StationMapper maps getstationsdata to outdoor/indoor/rain
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 14:36:00 +02:00
theoandClaude Fable 5.1 b38b7a3ac4 feat: project skeleton with Config and exceptions
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 14:34:39 +02:00
theoandClaude Fable 5.1 0bf3527115 docs: add spec, mockup and implementation plan
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 14:33:34 +02:00