-
Slimme meterstanden opslaan in Prometheus
Een van de redenen dat ik een Raspberry Pi in m’n meterkast heb hangen is omdat ik de slimme meter wil kunnen uitlezen, zodat het duidelijk is welk deel van de opbrengst van de zonnepanelen terug het net op gaat en welk deel we zelf gebruiken. Zeker nu het salderen er in 2027 uit gaat is dat interessante informatie om te bepalen wat een thuisbatterij zou opleveren.
Om de meter uit te lezen en de tellerstanden op te slaan heb ik een tooltje geschreven in Rust, een programmeertaal die de laatste jaren heel populair is geworden onder systeemprogrammeurs. Eén van de killer features van Rust is memory-safeness, wat het makkelijker maakt om veilige code te schrijven… of althans, makkelijker dan C en C++ dat doen in ieder geval.
C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do it blows your whole leg off
– Bjarne Stroustrup (uitvinder van C++)In ieder geval, hier wilde ik graag eens mee spelen en dan is een concreet project wel handig. Omdat ik werkelijk geen idee had van hoe Rust werkt en dat de verder uitstekende tutorials natuurlijk niet vertellen hoe je een slimme meter uitleest of hoe je een Prometheus exporter schrijft, heb ik ChatGPT gevraagd een voorzetje te geven. Dit leverde in eerste instantie een hoop niet werkende rommel op, maar wel een paar waardevolle regels code die ik vervolgens kon aanpassen en gebruiken.
Uiteindelijk heb ik alles verwerkt in een tool met de prachtige naam kamstrup-162jxc-p1-prometheus-exporter-rs.
Meterstanden uitlezen
Slimme meters in Nederland zijn gespecificeerd in het document “Dutch Smart Meter Requirements” dat wordt onderhouden door Netbeheer Nederland. Er zijn inmiddels meer dan tien versies van de standaard in omloop en je meter, afhankelijk van wanneer die is geïnstalleerd, moet voldoen aan een van die versies.
Bij ons in de meterkast hangt een “oudje”, een Kamstrup 162JXC, die voldoet aan DSMR 3.0 uit 2010. Volgens DSMR zit er een seriële poort op die het eindgebruikers mogelijk maakt om de meter lokaal uit te lezen. Deze poort wordt P1 genoemd en is een aansluiting met RJ-11 plug; een telefoonstekker.
Voor het uitlezen van de meter heb je een kabel nodig vanuit de RJ11 poort naar je computer; ik heb deze besteld. Met het UNIX “call up” command
cu
praat je vervolgens over de seriële poort:cu -l /dev/ttyUSB0 -E% --parity=even
Elke 10 seconden verschijnt een rapport van de actuele meterstanden in beeld:
/KMP5 KA6UXXXXXXXXXXXX 0-0:96.1.1(XXXXXX) 1-0:1.8.1(20203.975*kWh) 1-0:1.8.2(18247.900*kWh) 1-0:2.8.1(00238.368*kWh) 1-0:2.8.2(00532.631*kWh) 0-0:96.14.0(0001) 1-0:1.7.0(0000.29*kW) 1-0:2.7.0(0000.00*kW) 0-0:96.13.1() 0-0:96.13.0() 0-1:24.1.0(3) 0-1:96.1.0(XXXXXX) 0-1:24.3.0(240914210000)(08)(60)(1)(0-1:24.2.1)(m3) (14094.865) !
Steeds wanneer er zo’n blok langskomt lees ik de standen uit, reken het om naar de juiste eenheden (kWh naar Wh, kW naar W) en houdt het bij voor de volgende stap, het opslaan van de tellerstanden.
Exporteren naar Prometheus
Om meterstanden langdurig op te slaan gebruik ik de “timeseries” database Prometheus. Een timeseries database is een database geoptimaliseerd voor het opslaan van gegevensreeksen afgezet tegen de tijd. Voorbeelden zijn aandelenkoersen, waterstanden en dus ook de meterstanden van je stroomteller. Prometheus verzamelt de informatie actief door elke geconfigureerde service periodiek te bevragen. Daarbij doet een simpele HTTP (web)server die slechts een enkele “pagina” bevat in een specifiek formaat dienst als bron.
# HELP kamstrup_162jxc_p1_actual_power_delivered_watts Actual electricity power delivered (+P) in 1 Watt resolution (1-0:1.7.0) # TYPE kamstrup_162jxc_p1_actual_power_delivered_watts gauge kamstrup_162jxc_p1_actual_power_delivered_watts 290 # HELP kamstrup_162jxc_p1_actual_power_received_watts Actual electricity power received (-P) in 1 Watt resolution (1-0:2.7.0) # TYPE kamstrup_162jxc_p1_actual_power_received_watts gauge kamstrup_162jxc_p1_actual_power_received_watts 0 # HELP kamstrup_162jxc_p1_total_energy_delivered_watthours Total electricity energy delivered (+P) in 1 Watthour resolution (1-0:1.8.1 / 1-0:1.8.2) # TYPE kamstrup_162jxc_p1_total_energy_delivered_watthours counter kamstrup_162jxc_p1_total_energy_delivered_watthours{meter="1"} 20203975 kamstrup_162jxc_p1_total_energy_delivered_watthours{meter="2"} 18247900 # HELP kamstrup_162jxc_p1_total_energy_received_watthours Total electricity energy received (-P) in 1 Watthour resolution (1-0:2.8.1 / 1-0:2.8.2) # TYPE kamstrup_162jxc_p1_total_energy_received_watthours counter kamstrup_162jxc_p1_total_energy_received_watthours{meter="1"} 238368 kamstrup_162jxc_p1_total_energy_received_watthours{meter="2"} 532631 # HELP kamstrup_162jxc_p1_total_gas_delivered_m3 Total gas delivered in m3 (0-1:24.3.0) # TYPE kamstrup_162jxc_p1_total_gas_delivered_m3 counter kamstrup_162jxc_p1_total_gas_delivered_m3 14094.865
Automatisch opstarten met de Raspberry Pi
Het is natuurlijk het handigst als zo’n exporter altijd opstart samen met de rest van het systeem. Raspberry Pi OS is Debian based and as such uses
systemd
for managing persistent services. On my Pi, I just created a file/etc/systemd/system/kamstrup-162jxc-p1-prometheus-exporter.service
with the contents below:[Unit] Description=Kamstrup 162JXC P1 Prometheus exporter After=time-sync.target [Service] ExecStart=/usr/bin/kamstrup-162jxc-p1-prometheus-exporter-rs --port 9292 --serial-port /dev/ttyUSB0 Type=simple [Install] WantedBy=multi-user.target
Nu nog een
systemctl enable kamstrup-162jxc-p1-prometheus-exporter-rs
, de service wordt ingeladen en start voortaan bij elke boot. Het verbindt automatisch met de seriële poort en start de Prometheus exporter webserver.Conclusie
Het is vrij eenvoudig om een slimme meter uit te lezen en de resultaten bij te houden in een database. De componenten zijn klein en overzichtelijk. Het ging zelfs zó eenvoudig dat ik meteen ook ben begonnen aan een tool om de zonnepanelen uit te lezen!
Links
-
Schaatsseizoen '24/'25
Het schaatsseizoen ‘24/’25 is helaas weer ten einde. Het was een wisselend seizoen met mooi ijs, zonovergoten trainingen, maar ook compleet verregende wedstrijden.
Noud
Voor Noud was dit het tweede seizoen dat hij wedstrijden rijdt en aan het begin gingen de tijden ook nog naar beneden. Helaas ving hij in de week voor de Förderkreispokal de griep en stond hij amper hersteld in de stromende regen aan de start. Het ging hem helemaal niet goed en het is verbazingwekkend wat voor tijd hij nog heeft neer weten te zetten op de 500 meter; maar anderhalve seconde boven zijn PR. Pas bijna een maand later op de clubkampioenschappen was hij weer goed hersteld en werden de tijden weer lager, met zelfs weer superdikke PR’s op de 500 meter.
Datum Wedstrijd 100 meter 300 meter 500 meter 1000 meter PRs seizoen 2023-2024 0:18.140 0:51.76 1:31.66 2:56.19 2024-11-09 NRW-Pokal (1) 0:17.35 0:50.07 2024-12-21 NRW-Pokal (2) 0:16.47 0:50.19 2025-01-25 Förderkreispokal 0:55.93 1:33.03 2025-02-08 Super Sprint 0:18.52 / 0:17.65 2025-02-15 RSNL Clubkampioenschappen 0:19.06 1:24.78 2025-02-22 NRW-Pokal (3) 0:16.61 1:22.59
Noud start zijn 100 meter op de 3e NRW-PokalJoris
De leuke verrassing van dit seizoen was dat ook Joris enthousiast is gaan schaatsen! Hij heeft in november een proefles gedaan en zei meteen al dat hij het hele seizoen wil meedoen. Zo wordt de auto op zaterdagochtend steeds voller!
Meedoen met wedstrijden vond hij nog wel een beetje spannend, maar bij de clubkampioenschappen stond hij er en hij vond het zó leuk dat hij meteen de week erop weer meedeed met de laatste “NRW-pokal”-wedstrijd van het seizoen en daar zomaar even twee PR’s reed.
Datum Wedstrijd 100 meter 500 meter 2025-02-15 RSNL Clubkampioenschappen 0:25.27 2:06.30 2025-02-22 NRW-Pokal (3) 0:21.62 2:05.31
Joris start zijn 100 meter op de 3e NRW-PokalChristian
Ikzelf heb alleen de clubkampioenschappen verreden, maar ik heb de ritten op paracetamol gedaan. Ik was al een paar dagen niet helemaal lekker, maar ik wilde per se die ene wedstrijd die we hebben ook meedoen. De resultaten lieten flink te wensen over en de dagen erna had de griep mij dan ook te pakken. Ik hoop dat het volgend seizoen een stuk beter gaat.
Datum Wedstrijd 500 meter 1000 meter PRs 0:57.72 (2009) 1:58.71 (2009) 2025-02-15 RSNL Clubkampioenschappen 1:04,33 2:12,89 -
Maak de Raspberry Pi PoE-hat ventilator stiller
Ik heb een Raspberry Pi met Power-over-Ethernet (PoE) hat in de meterkast hangen (met onder andere een P1 kabel om de slimme meter uit te lezen). Het nadeel is dat de PoE hat een kleine ventilator heeft die standaard erg agressief staat afgesteld. Gelukkig is die te configureren zodat de temperatuur in het veilige bereik blijft en je niet gek wordt van het gejank van die kleine herrieschopper.
In
/boot/firmware/config.txt
:# PoE Hat Fan Speeds dtoverlay=rpi-poe-plus dtparam=poe_fan_temp0=65000,poe_fan_temp0_hyst=5000 dtparam=poe_fan_temp1=67000,poe_fan_temp1_hyst=2000 dtparam=poe_fan_temp2=69000,poe_fan_temp2_hyst=2000 dtparam=poe_fan_temp3=71000,poe_fan_temp3_hyst=2000
Reboot je Pi en check of het naar wens is:
$ od -An --endian=big -td4 /proc/device-tree/thermal-zones/cpu-thermal/trips/trip?/temperature /proc/device-tree/thermal-zones/cpu-thermal/trips/trip?/hysteresis 65000 67000 69000 71000 5000 2000 2000 2000
Let erop dat er vier temperaturen zijn die je kan instellen, als ze niet expliciet zijn opgegeven in
config.txt
hebben ze een standaardwaarde die waarschijnlijk niet is die je wil.Links
- https://github.com/raspberrypi/firmware/blob/1.20240529/boot/overlays/README#L4062-L4082
- https://github.com/raspberrypi/firmware/issues/1689#issuecomment-1053403166
- https://jjj.blog/2020/02/raspberry-pi-poe-hat-fan-control/
- https://pimylifeup.com/raspberry-pi-temperature/
- https://www.jeffgeerling.com/blog/2021/taking-control-pi-poe-hats-overly-aggressive-fan
-
Logging the Switch bestaat 20 jaar!
Twintig jaar geleden begon ik een weblog genaamd “Logging the Switch”. Ik had destijds met genereuze hulp van de Belastingdienst (met de pc-privéregeling die diezelfde maand nog werd afgeschaft) de Apple Power Mac G5 gekocht en ging van Linux op de Intel PC naar Linux op de PowerPC. Mijn ervaringen zou ik delen op dit weblog. Of althans, dat was de bedoeling. De praktijk was anders.
Het was al vrij snel duidelijk dat zulke nieuwe hardware echt niet meteen ging werken op Linux. De CPU zelf werd in eerste instantie al niet eens herkend, laat staan dat het systeem kon opstarten. Ik moest dus een andere “Switch” gaan maken, naar Mac OS X. Maar dat was helemaal niet zo’n interessant onderwerp, dus al vrij snel kwamen andere dingen voorbij, zoals welke CDs ik kocht, welke foto’s ik had gemaakt en welke tijden ik op het ijs reed. Soms in het Nederlands, soms in het Engels.
In 2006 maakte ik een tijdelijk uitstapje naar een tweede weblog, Christian in IJsland, omdat ik merkte dat die twee niet lekker samen gingen op hetzelfde adres. Twee totaal verschillende doelgroepen.
Na de studie zakte het aantal posts flink in. Ik heb meerdere keren besloten te gaan stoppen en de boel af te sluiten, maar telkens kwam er toch weer een berichtje. Het leven stond even in de weg, we trouwden, kochten een huis en kregen kinderen. Andere dingen werden even belangrijker. En toch, op een gegeven moment begon het weer te kriebelen en begonnen de posts langzaam weer te komen, vooral over hobbyprojecten zoals Arduino en VR.
Techniek door de jaren heen
De techniek is in de loop van de jaren flink veranderd, maar ik ben altijd op de achtergrond blijven knutselen en schaven aan het weblog.
Begin 2004 experimenteerde ik al wat met Movable Type embedded in mijn toenmalige website. Daarvan is nog een klein beetje te zien op the Internet Archive. Ik beschouw dat echter nog niet echt als het begin van Logging the Switch, het was meer een probeersel.
Later dat jaar ging ik over naar Instiki ( van David Heinemeier Hansson die later Ruby on Rails, Basecamp en de e-maildienst Hey zou gaan ontwikkelen), waar Logging the Switch dan echt werd geboren. Website en weblog waren toen nog gescheiden. Minder dan een jaar later zou ik de hele boel overzetten naar Hobix en toen waren ook website en weblog samengevoegd.
De jaren daarna is de weblog regelmatig verhuisd van hosting. Eerst heb ik bij Spacelabs nog verschillende servers gebruikt en daarna kwam het op een eigen VPS te staan. In 2015 introduceerde GitHub hun Pages, waarbij je elk repository (gratis) een website kon geven mét eigen domein. Het bleek erg lastig om ouwe Hobix op zulk nieuw spul te draaien, want in de tussentijd was de ontwikkelaar van Hobix van de aardbodem verdwenen en hij had al zijn code meegenomen. Hobix was al vijf jaar niet meer onderhouden en werkte niet meer samen met de nieuwste Ruby-versies die GitHub Pages vereiste. Ik moest nogmaals de blog migreren naar een ander systeem, dat werd Jekyll.
De afgelopen acht jaar gebruik ik GitLab Pages, omdat zij nét iets flexibeler zijn in hun automatisering en meer mogelijkheden bieden voor het genereren van statische websites. De site op GitHub staat blijkbaar wel nog steeds online, maar daar heeft de tijd stilgestaan.
Het is ook niet zo dat ik de afgelopen acht jaar niets meer aan onderhoud heb gedaan, integendeel! Ik ben eigenlijk best regelmatig aan het rommelen in de code die de site genereert om hier en daar wat te verbeteren, de navigatie te stroomlijnen, het er nét iets mooier uit te laten zien. Eigenlijk doe ik dat meer dan nieuwe stukjes schrijven…
Dit waren de eerste twintig jaar, wat gaan de volgende twintig brengen?
-
RSNL Clubkampioenschappen 2024
Na meer dan veertien jaar heb ik eindelijk weer eens een wedstrijd gereden. Het was afwachten wat de overhand zou hebben; de verbetering van de techniek of de veroudering van het gestel 😜. Het bleek het laatste te zijn, want de PRs van toen zijn nu ver buiten bereik gebleken. Ik moest me tevredenstellen met een 01:03.220 op de 500 meter en 02:09.900 op de 1000 meter. Ter vergelijking, dit waren de PRs die ik bij Isis heb gereden:
Afstand Datum PR 300 m 2009-01-14 (Eindhoven) 00:37.920 500 m 2009-02-18 (Eindhoven) 00:57.720 1000 m 2009-02-18 (Eindhoven) 01:58.710 1500 m 2009-02-19 (Eindhoven) 02:57.660 3000 m 2008-03-11 (Thialf) 06:16.750
2023-12-16: Noud aan de start bij de NRW-PokalInmiddels heb ik wel opvolging gekregen, want Noud rijdt sinds dit jaar ook fanatiek op de schaats en heeft al een aantal wedstrijden verreden. Met de sprongen die hij dit jaar heeft gemaakt duurt het niet lang voordat hij mijn tijden verpulvert. Ik kijk er nu al naar uit, hij heeft er in ieder geval heel veel plezier in; op naar de laatste wedstrijd van het seizoen!
Datum Wedstrijd 100 meter 300 meter 500 meter 1000 meter 2023-12-09 Förderkreispokal 1:06.870 1:46.330 2023-12-16 NRW-Pokal (2) 0:22.370 1:44.070 2024-01-07 Super Sprint 0:20.470 0:57.090 2024-02-17 RSNL Clubkampioenschappen 1:31.660 2:56.190 2024-02-24 NRW-Pokal (3) 0:18.140 0:51.760 Update 25 februari: Tijden NRW-Pokal (3) toegevoegd.
-
Hoe werkt een mechanisch horloge?
In navolging van mijn vorige post, waarin ik zei dat we onze rol van ontdekkingsreizigers op het wereldwijde web weer moesten herpakken, vond ik een prachtig voorbeeld van zo’n website die er gewoon is om te zijn. De site van Bartosz Ciechanowski bevat niet heel veel artikelen, maar het zijn stuk voor stuk juweeltjes. Met werkende 3D modellen legt hij in jouw eigen webbrowser uiteenlopende principes stap voor stap uit.
Een kleine greep uit het aanbod: Een gedetailleerde omschrijving van de verschillende bewegingen in een mechanisch horloge, van de grote veer tot aan de datumaanwijzer, de kroon en het automatisch opwindmechanisme. Een uiteenzetting van de principes achter het Global Positioning System (GPS), waaruit ook meteen af te leiden is dat zowat elke televisieserie die GPS-signalen beweert te hacken volledige onzin is. Een hogerdimensionale reis in de wereld van de tesseract die je doet duizelen. Een technische uitleg hoe een digitale computer toch met floating point getallen kan rekenen.
Elke pagina is weer een ijzersterk didactisch verhaal gecombineerd met een vernuftig stukje techniek.
-
Waar zijn alle websites heen?
Ik zag laatst een artikel op Slashdot langskomen, waar de schrijver zich afvroeg waar alle websites gebleven waren.
Het verhaal begint in 2009, toen het internet nog een digitale speeltuin was vol verrassingen. Facebook en Instagram waren als de coole kids op het schoolplein die de laatste roddels verspreidden, en surfen op het web betekende het intikken van webadressen met de hoop op een avontuurlijke ontdekkingsreis bij elke klik.
Fast forward naar 2024 en het internet lijkt een totale make-over te hebben ondergaan. De “Voor Jou Pagina” levert nu op maat gemaakte content van je favoriete “creators”, speciaal afgestemd op verschillende platforms. De ooit gevarieerde wereld van websites lijkt echter te zijn verdwenen, alles is in hetzelfde format gedwongen, en dat roept vragen op over de huidige toestand van het web en waarom we er helemaal niet zo blij meer mee zijn.
De echte verandering zit hem echter in onszelf. De vreugde van ontdekking en “curatie”, ooit essentieel voor de internetervaring, lijkt te zijn uitbesteed aan bedrijfsalgoritmen. We scrollen nu eindeloos passief door content, vertrouwend op algoritmes voor onze digitale avonturen. Algoritmes die echter hele andere belangen dienen…
De oplossing? Laten we teruggaan naar onze rol als ontdekkingsreizigers! Iedereen kan een curator worden door open webportals te creëren. Gebruik platforms zoals Linktree.com om je favoriete blogposts, artiesten of coole websites te delen. Heb je meer te melden, open je eigen website op WordPress.com en link ernaar vanuit je socials in plaats van jouw ideeën op te sluiten in de platforms van anderen. Laten we de interconnectiviteit nieuw leven inblazen en het web weer leuk maken om te ontdekken, zonder dat je een computernerd hoeft te zijn.
En als je nog een stapje verder wilt gaan hoeft het helemaal niet ingewikkeld te zijn. Het boek hiernaast heb ik bij ons in de bibliotheek gevonden voor Jasper die op school als verrijkingsproject “Een eigen website” heeft gekozen. Bouw je eigen website, stap voor stap, van de grond op. Je eigen virtuele volkstuintje op het internet.
-
Arduino ✕ PlatformIO
De electronica en code voor de Rheinturm zijn al een hele tijd af, maar ik moet nog steeds een “behuizing” voor het geheel bedenken. Ik twijfel nog tussen een eenvoudige houten plaat of een uitgesneden vorm, maar een 3D geprint model zou ook heel tof zijn. Blijkbaar zijn 3D-printers tegenwoordig ook niet meer super duur als je van
prutsentinkeren houdt… Anyway, dat is weer een heel andere hobby!Voorlopig ligt de boel dus veilig in een doos opgeborgen te wachten op de afwerking. Tot die tijd wil ik de code wel een beetje netjes achterlaten, zodat het later makkelijk weer op te pakken is. Daarbij heb ik al gemerkt dat de Arduino IDE niet het beste stuk software is om dat mee te doen. Arduino-Rheinturm gebruikt een aantal software-bibliotheken die ingeladen moeten worden en de vraag is of die over twee of drie jaar nog werken in de Arduino IDE.
Daarnaast is het prototype wat ik nu heb gebouwd weliswaar gebaseerd op een Arduino UNO, maar heb ik tegen de tijd dat ik de definitieve versie maak, misschien een ander type controller waar de Arduino IDE helemaal niet mee samenwerkt. Wat ik nodig heb, is een manier om te zeggen welke bibliotheken ik nodig heb en hoe de broncode moet worden gebouwd voor de controller die ik op dat moment heb. Als je ooit een Java-project hebt gemaakt, zul je denken aan Maven of Gradle. Voor Ruby heb je Gemspecs en Bundler, voor Python is er
setup.py
(of tegenwoordigproject.toml
) enpip
en in de JavaScript-wereld gebruik jepackage.json
ennpm
.PlatformIO
Het van oorsprong Oekraïense project PlatformIO is zo’n tool voor embedded software development. Een enkele
platformio.ini
in je project en de sources op een aangewezen plek (Convention over Configuration), meer heb je niet nodig om snel weer op weg te zijn als je een tijd weg bent geweest van je project.[env:uno] platform = atmelavr board = uno framework = arduino lib_deps = bxparks/AceTime @ ^2.0.1 adafruit/Adafruit NeoPixel @ ^1.11.0 northernwidget/DS3231 @ ^1.1.2 rlogiacco/CircularBuffer @ ^1.3.3
Doordat spullen op voor PlatformIO bekende plaatsen staan, kan die ook de benodigde projectbestanden genereren om het te openen in je IDE, zonder dat die bestanden in Git hoeven te worden gezet. Vandaag de dag werk ik met JetBrains CLion, maar misschien is dat morgen Visual Studio Code. Die snappen elkaars projectstructuur niet, dus dan is het fijn dat je niet helemaal opnieuw hoeft te beginnen met de inrichting, maar gewoon
platformio -c clion init
ofplatformio -c vscode init
kan doen en alles staat weer recht.Daar houdt het echter niet op, want als ik een andere microcontroller gebruik, dan kan ik eenvoudig een nieuwe minimale configuratie aanmaken en ben ik ook weer op weg. Met de juiste hardware zou het zelfs mogelijk moeten zijn om unit testen te schrijven die de code kan verifiëren.
CLion
De overstap van Arduino IDE via PlatformIO naar CLion was wel fundamenteel, want plotseling had ik een hele krachtige omgeving tot mijn beschikking waarmee het programmeren in C++ daadwerkelijk ondersteund wordt. Het nodigde uit tot opschonen en opsplitsen van de code, waardoor ik nu een heel nette structuur heb die ik over een jaar of twee ook nog begrijp. En ja, dan kan je de code ook maar beter publiek maken, want misschien heeft iemand er ooit nog iets aan.
Links
-
VR panorama browser
Zoals ik afgelopen week al schreef, wilde ik de panorama-viewer verder uitbreiden om meer foto’s toe te voegen. Interacties in de derde dimensie werken echter nét anders dan op het platte scherm. Daarnaast zijn allerlei conventies nog helemaal niet uitgewerkt, dus iedereen doet maar wat en dat is heel verfrissend.
In de 20e eeuw werden de nieuwe grafische interfaces aangeleerd door het gebruik van bedieningselementen die waren ontworpen naar het voorbeeld van een fysieke tegenhanger, een skeuomorfisme zoals dat heet. Mappen, schuifknoppen en zandlopers; allemaal elementen uit de echte wereld om ons te laten begrijpen hoe de interface werkt in de platte digitale wereld.
Meta Quest: Zwevende 2D windows met een 3D sausjeDigitale 3D werelden kunnen werken op een heel andere manier, maar de interface-ontwerpers maken het zich er makkelijk vanaf en plakken gewoon een 2D interface in de lucht, want die kennen we al. Ze willen het ons nu nog niet te lastig maken, maar de échte revolutie moet nog komen, denk ik.
Apple visionOS: Nog niet veel beterSimpel
Hoe dan ook, ik wilde iets simpels maken om mee te beginnen. Met A-Frame doe je dat met Custom Elements in HTML. Hieronder zie je het specifieke deel om de scene te definiëren.
<a-scene> <a-assets> <img id="image-0" src="image-0.jpg"> <img id="city" src="https://cdn.aframe.io/a-painter/images/sky.jpg"> <img id="floor" src="https://cdn.aframe.io/a-painter/images/floor.jpg"> </a-assets> <a-sky src="#city"></a-sky> <a-curvedimage id="panorama" src="#image-0" position="0 2 0" height="2.5" radius="2" theta-start="60" theta-length="240"></a-curvedimage> <a-cylinder id="ground" src="#floor" radius="32" height="0.1"></a-cylinder> </a-scene>
Eerst definieer je een aantal assets, in dit geval afbeeldingen, waar je vanaf andere plekken naar kan verwijzen. Om te voorkomen dat je in het luchtledige lijkt te zweven is het verstandig een
a-sky
toe te voegen met een 360º afbeelding. Daarnaast heb ik eena-cylinder
toegevoegd die als een soort vloer dient.De
a-curvedimage
bevat het echte panorama-plaatje en is eigenlijk een boogsegment van de wand van een cilinder. Het is een beetje zoeken naar de juiste waardes, maar de meeste van mijn panorama’s zijn ongeveer 240º. Als het niet helemaal klopt, is dat nog niet zo’n ramp, want dat zie je amper, behalve als je met veel rechte lijnen werkt en het allemaal precies zou moet passen.Nu voeg ik nog twee
a-image
toe onder de panorama om zometeen vooruit en achteruit te kunnen en voila, de scène is zo’n beetje klaar:
Overzicht van de sceneMet A-Frame hoef je je om de rendering verder geen zorgen meer te maken. Je headset schakelt om naar VR-modus en je wordt omringd door de scène die je hebt gebouwd. De interactie daarentegen zul je wel zelf moeten opbouwen, want anders dan op het platte web kan je hier niet gewoon ergens een
<a href=...>
wegzetten om een link te maken.Interactie
In 2D interfaces zijn we gewend dat we één aanwijzer hebben die we eventueel met meerdere apparaten kunnen bedienen ( muis, touchpad, tekenpen, …). In de 3D wereld zijn al die apparaten opeens onafhankelijke bedieningen geworden, vergelijkbaar met hoe een smartphone elke vinger apart detecteert en “multitouch gestures” herkent. A-Frame ondersteunt hoofd- en controller-tracking, dus je kijkrichting en wat je met je controllers doet kan als invoer dienen. Omdat je hoofd (waarschijnlijk) geen knoppen heeft, werkt een interactie daarmee anders dan met een hand-controller.
Een controller declareer je door een
a-entity
te maken met een aantal attributen, bijvoorbeeld zo:<a-entity oculus-touch-controls="hand: right" laser-controls b-button-listener></a-entity>
Met
oculus-touch-controls="hand: right"
zeg je dat je de Meta Quest controller voor de rechter hand wil configureren. Delaser-controls
zorgt ervoor dat de controller een laserstraal afschiet in de wijsrichting, en dat een aantal events worden afgevuurd als die laserstraal een object raakt, waarover later meer.Uit de VR-modus gaan
Ten slotte koppel ik met
b-button-listener
mijn eigen code aan de controller hardware:AFRAME.registerComponent('b-button-listener', { init: function () { this.el.addEventListener('bbuttondown', function (e) { const sceneEl = document.querySelector('a-scene'); if (sceneEl.is('vr-mode')) { sceneEl.exitVR(); } }); } });
Dit zorgt ervoor dat als je op de B knop op de controller drukt wanneer je in VR-mode bent, dat je uit VR-mode gaat.
Een foto vooruit of achteruit gaan
De twee kleine fotootjes onderaan op het screenshot had ik nog niet aan de scène toegevoegd, dus dat doen we nog even:
<a-image id="prev-image" src="#image-2" position="-1 0.5 -1.5" rotation="-45 30 0" width="1" height="0.33" cursor-listener="direction: prev"></a-image> <a-image id="next-image" src="#image-1" position="1 0.5 -1.5" rotation="-45 -30 0" width="1" height="0.33" cursor-listener="direction: next"></a-image>
Hier zie je de
cursor-listener
component. Deze code is straks verantwoordelijk voor het naar hetclick
signaal luisteren dat delaser-controls
component produceert wanneer je op een van dea-image
s “klikt”. Je ziet dat je extra informatie kan meegeven, net als bij deoculus-touch-controls
, om de component te configureren.AFRAME.registerComponent('cursor-listener', { schema: { direction: {type: 'string', default: 'next'} }, init: function () { this.el.addEventListener('click', (e) => { switch (this.data.direction) { case 'prev': nextImage(-1); break; default: nextImage(1); break; } }); } });
In de code hierboven wordt aan
this.el
, dat is dea-image
waar het op staat, een event listener toegevoegd voor hetclick
signaal. Afhankelijk van de waarde vandirection
zal hij nu de volgende of de vorige afbeelding inladen.De logica voor het wisselen van de afbeelding is niet A-Frame of WebXR specifiek en kan je vinden in de source van de panorama pagina (net als de rest van deze blog trouwens).
En dat is het! Het resultaat is een wereld waarin je kan schakelen tussen zes panorama’s met behulp van je controllers! Voor degenen zonder headset, een filmpje:
Nuttige links
- Een lijst van voorbeelden met A-Frame (in onwijze 90s homepage vibe) van Lee Stemkoski
- A-Frame documentatie
-
Aan de slag in Virtual Reality met WebXR
We hebben onszelf laatst een VR-headset cadeau gedaan. Om Beat Saber te spelen natuurlijk, maar ook om lekker mee te knutselen. Er zijn native ontwikkelomgevingen voor zo’n beetje elke headset die op de markt te krijgen is, maar er is ook een W3C specificatie voor VR- en AR-applicaties, gezamenlijk vaak XR genoemd. Die specificatie heet WebXR en breidt het 2D web uit met de derde dimensie.
Nu is de W3C specificatie vrij low-level dus is het lastig daar een toepassing mee te maken, maar er zijn al frameworks ontwikkeld die het veel makkelijker maken. Een van die frameworks is A-Frame en daarmee heb ik al een simpele viewer geknutseld voor de panoramafoto’s die ik in de loop van de tijd heb gemaakt.
Met een desktop browser kan je die pagina gewoon openen en in XR-emulatie bekijken, met een headset krijg je een “immersieve ervaring” zoals dat zo mooi heet.
Kijk maar eens naar het panorama van de Pont du Gard in VR wat ik afgelopen vakantie heb gemaakt.
Ik wil de viewer nog verder uitbreiden zodat het een echte applicatie is waarin je meerdere panorama’s kan bekijken, want ze komen in VR echt veel beter tot hun recht dan op een plat beeldscherm.
-
Djöflaterta
Lang geleden leefde ik een paar maanden in IJsland, waar ik kennismaakte met de perfecte IJslandse variant van de Devil’s Pie: Djöflaterta. Nu was ik niet helemaal kapot van het recept wat ik destijds had en ben ik op zoek gegaan naar een nieuwe samenstelling.
Ik heb denk ik de perfecte receptuur nu gevonden: Djöflaterta sem bráðnar í munninum oftewel “Duivelse taart die smelt in je mond”.
Voor het beslag
Voeg de ingrediënten een voor een toe en blijf mixen op hoge snelheid.
150 gr margarine
1 1/2 cup suiker (355 ml)
3 eieren
2 cups bloem (473 ml)
1 tl bakpoeder
1/2 tl zout
1 tl baking soda
2 tl vanilledruppels
1 cup melk (237 ml)
2 el cacaoMeng alles door elkaar en doe in 2 springvormen en bak 20-30 min op 180°. Houd het in de gaten, zodat het bovenop niet te donker wordt.
Met een enkele springvorm lukt het ook, dan duurt het ongeveer 40-50 minuten en moet je het uiteindelijk horizontaal snijden. Dit recept gebruikt zowel bakpoeder als baking soda; het deeg is dan ook heel erg “fluffy” als het is gebakken.
Voor de crème
50 gr boter
300 gr poedersuiker
1 ei
1 tl vanilledruppels
2-6 el melk
2 el cacao
of 2 eieren en sla de melk overLaat de cake volledig afkoelen voordat je de creme erop smeert, want anders loopt het er zo weer uit.
Voor de ganache
Hiervoor heb ik een ander “recept” gevonden wat goed werkt. Gebruik pure chocolade en slagroom in 1:1 verhouding. Smelt de chocolade au bain-marie en laat het een beetje afkoelen. Breng de slagroom aan de kook en voeg het bij de chocolade. Goed roeren en laten afkoelen tot het een stevige pasta is, dat kan prima in de koelkast. Wel regelmatig doorroeren zodat je niet een grote dikke klont krijgt.
Nu kan je de pasta eenvoudigweg eroverheen smeren en ziet het er zalig uit, en zo smaakt het ook…
-
Stabiel de tijd bijhouden tussen herstarten
Met baby steps, zo komen we er wel. Eerder had ik het erover dat de Arduino geen eigen RTC (Real Time Clock) heeft en daardoor ten eerste een vrij grote afwijking van enkele seconden per dag heeft en ten tweede de tijd-instelling steeds kwijtraakt bij herstarten.
Er zijn twee goed ondersteunde RTCs voor Arduino verkrijgbaar; de DS1307 en de DS3231. Qua prijs ontlopen ze elkaar niet veel, maar qua precisie is de DS3231 absoluut superieur met een afwijking van maar ±2 minuten per jaar. Aansluiten op de Arduino, het wordt langzaam een beetje voorspelbaar, is weer een fluitje van een cent.
VCC
enGND
naar de plus en min,SDA
direct op analoge poortA4
enSCL
direct naar analoge poortA5
.
DS3231 met batterijhouder en pinsVervolgens kan je met de DS3231 library de boel besturen:
#include <DS3231.h> #include <AceTime.h> BasicZoneProcessor zoneProcessor; TimeZone tz = TimeZone::forZoneInfo(&zonedb::kZoneEurope_Amsterdam, &zoneProcessor); void setup() { // Initialiseer de verbinding Wire.begin(); Serial.begin(9600); } void loop() { // Haal de huidige tijd op uit de RTC DateTime rtcNow = RTClib::now(); ZonedDateTime now = ZonedDateTime::forUnixSeconds64(rtcNow.unixtime(), tz); now.printTo(Serial); delay(100); }
De tijd instellen
De kans dat de RTC de juiste tijd geeft als je hem voor het eerst gebruikt is op zich vrij klein, dus moet je hem eerst instellen. Via de seriële poort van de Arduino kunnen we de module instellen:
void loop() { // Als er iets op de seriële poort klaar staat... if (Serial.available()) { // ... dan lees het als een integer long readLong = Serial.parseInt(); // ... en lees de rest van de buffer leeg, zoals een <enter> of spaties while (Serial.available()) { Serial.read(); } // stel de RTC in op de integer die van de seriële poort is ingelezen rtc.setEpoch(readLong); } ZonedDateTime now = ZonedDateTime::forUnixSeconds64(RTClib::now().unixtime(), tz); now.printTo(Serial); delay(100); }
Vervolgens kunnen we de tijd instellen door de Unix epoch timestamp over de seriële poort naar de Arduino te sturen. De huidige Unix epoch krijg je met het commando
date +%s
. Je kan de uitvoer daarvan in de Arduino IDE naar de seriële poort sturen (Tools | Serial monitor), maar het kan ook vanaf de command line met hetcu
commando. Eerst moet je weten welk device je seriële poort heeft; in de Arduino IDE zie je dat onderin het scherm als je Arduino verbonden is. Bij mij is dat/dev/cu.usbmodem101
, vervolgens start jecu
met het commando:$ sudo cu -l /dev/cu.usbmodem101
Nu zie je alles wat over de seriële poort binnenkomt, dus in dit geval elke 100 milliseconden de huidige tijd. Het
cu
commando kan echter ook berichten terugsturen (zieman cu
), en heeft zelfs nog functionaliteit om de invoer uit een ander programma te halen door middel van~$<command>
. We krijgen de huidige epoch metdate +%s
(zie ookman date
).Als je door de stroom aan timestamps heen het commando
<enter>~$date +%s
invoert, zul je zien dat de timestamps opeens de huidige tijd weergeven. Aangezien je dit maar af en toe hoeft te doen zou je kunnen overwegen dit in een apart programma te doen, want dat scheelt weer in het geheugengebruik. Je sluitcu
netjes af met het commando<enter>~.
.Andere tijdsignaal-bronnen
Een RTC is zeker niet de enige bron van tijdsignalen. Als je een WiFi module toevoegt aan de Arduino, kan de tijd opgehaald worden vanaf een NTP-server. Met een GPS-ontvanger kan je de tijd ophalen van satellieten. Een nog andere optie is om een tijdsignaal van de DCF77-zender in Mainflingen bij Frankfurt op te vangen. Ook de originele klok in de Rheinturm doet dit!
Ik wil daar in de toekomst nog wel eens naar kijken, maar op dit moment is de klok volledig zelfstandig operationeel! De volgende stap is eerst iets compleet anders: de lichtstrip moet worden ingebouwd in een meer permanente opstelling.
Pagina 1 van 28
Volgende keyboard_arrow_right