“Mammaaaaaaa? Hvor mange minutter er det siden jeg ble født?!” Alle med små barn har vel fått det spørsmålet før. Eller? Min er i hvert fall utroooolig glad i store tall, er veldig opptatt av bursdagen sin, og spurte meg om antall dager og minutter daglig. Flere ganger daglig, faktisk. Spørsmålene økte i frekvens jo mer vi nærmet oss selve bursdagen. På et tidspunkt gikk jeg lei av å google (jeg tar ikke dét regnestykket i hodet) og kom på at jeg har jo en raspberry pi liggende - kanskje dette er akkurat det prosjektet jeg lette etter som er overkommelig nok til å starte med? Og det kan være en artig bursdagsgave - to fluer i én smekk her altså! (Egentlig tre, siden jeg fikk også et lite pusterom fra samme spørsmål som gikk i loop)
Så - har du, som meg, én eller to Raspberry Pi liggende på hylla som støver ned, og kjenner på et lite stikk av dårlig samvittighet (for en gadget liksom, av alle ting) men det føles bare litt for tungt å ta opp noe nytt? Start i det små, og overlatt til Raspberry Pi å besvare ett (eller flere) av barnas gjentagende spørsmål. Nå vet junior til enhver tid hvor mange minutter har gått siden han ble født, og jeg har hatt det morsomt underveis. Det er superenkelt, jeg lover!
¶Komme i gang
Armert med en pi starter kit, gikk jeg gjennom inventar jeg hadde behov for:
- microSD kort med pre-installert OS på - smooth
- strøm-kabel
- skjerm-kabel
Check-check-check. Jeg var usikker på om jeg måtte gjøre noe spesielt for å få wifi til å fungere, men det viste seg å være plug-and-play det og.
Det jeg nå manglet var en liten display for å vise utregningen. På Kjell&Co hadde de noen displayer, men det kostet en tusenlapp, hadde masse farger og touch støtte - det ble for overkill. Heldigvis har jeg en god kollega Finn som er litt-over-snittet-ivrig-gadget-enthusiast (og også en god venn og nabo - flaks!!) som sendte meg dette bildet da jeg klaget min nød:
Han loddet også ferdig kabler på skjermen - akkurat den biten synes jeg fortsatt er for høy terskel å komme over. Mål for 2026 det kanskje..
Midt i prosjektet oppdaget jeg at OS’et kom med noen ferdig-installerte spill, så det slukte jo litt tid det og, men herregud så morsomt <3
Men ok, tilbake til prosjektet! Først måtte jeg jo koble til den lille skjermen. Det ble en del gloser rettet mot de bittesmå pins og kabler som bare ikke ville sitte på plass. Til slutt brukte jeg gjennomsiktig teip for å holde det tett.
¶Koden
Med alle hardware-dingsene på plass var det på tide å ta fatt i selve utregningen
from datetime import datetime
given_date = datetime(<YYYY>, <M>, <DD>, <HH>, <MM>)
def datetime_range(given_date):
now = datetime.now()
difference = now - given_date
days = difference.days
minutes = difference.total_seconds() // 60
return days, minutes
days, minutes = datetime_range(given_date)
print(f"Dager: {days}, Minutter: {minutes}")
Neste steg var å få sendt utregningen til OLED-display istedenfor terminalvindu.
Det tok et par forsøk for å finne ut av hvilke koordinater jeg skulle bruke for å få teksten dit jeg ville:
from luma.core.interface.serial import i2c
from luma.core.render import canvas
from luma.oled.device import ssd1306
serial = i2c(port=1, address=0x3C)
device = ssd1306(serial)
with canvas(device) as draw:
draw.text((14,0), f"Siden dd.mm.yyyy", fill="white")
draw.text((0,14), f"{days} dager", fill="white")
draw.text((0,44), f"{minutes:.0f} min.", fill="white")
Yay, det funka! Men bare en gang, her er det statisk verdi som blir beregnet og skrevet ut. Legge på en liten løkke, og gjøre teksten finere:
from PIL import ImageFont
import time
try:
font_large = ImageFont.truetype("/usr/share/fonts/truetype/quicksand/Quicksand-Medium.ttf", 20)
font_medium = ImageFont.truetype("/usr/share/fonts/truetype/quicksand/Quicksand-Bold.ttf", 16)
font_small = ImageFont.truetype("/usr/share/fonts/truetype/quicksand/Quicksand-Bold.ttf", 14)
except OSError:
font_large = font_medium = font_small = None
while True:
days, minutes = datetime_range(given_date)
with canvas(device) as draw:
draw.text((14,0), f"Siden dd.mm.yyyy", font=font_small, fill="white")
draw.text((0,14), f"{days} dager", font=font_large, fill="white")
draw.text((0,44), f"{minutes:.0f} min.", font=font_medium, fill="white")
time.sleep(60)
Her vil en våken leser fort se at presisjonen er ikke nøyaktig på millisekunder, men jeg regner med at det er et par år til ungen oppdager det og at dette er greit nok inntil videre.
Her er hele koden, med noe feilhåndtering og logging lagt på:
import logging
import time
from PIL import ImageFont
from datetime import datetime
from luma.core.interface.serial import i2c
from luma.core.render import canvas
from luma.oled.device import ssd1306
logging.basicConfig(
filename='/home/pi/Documents/Python/log.txt',
level=logging.DEBUG,
filemode='w',
format='%(asctime)s - %(levelname)s - %(message)s'
)
try:
font_large = ImageFont.truetype("/usr/share/fonts/truetype/quicksand/Quicksand-Medium.ttf", 20)
font_medium = ImageFont.truetype("/usr/share/fonts/truetype/quicksand/Quicksand-Bold.ttf", 16)
font_small = ImageFont.truetype("/usr/share/fonts/truetype/quicksand/Quicksand-Bold.ttf", 14)
except OSError:
font_large = font_medium = None
given_date = datetime(<YYYY>, <M>, <DD>, <HH>, <MM>)
def datetime_range(given_date):
now = datetime.now()
difference = now - given_date
days = difference.days
minutes = difference.total_seconds() // 60
return days, minutes
try:
logging.info("Starting OLED display script")
serial = i2c(port=1, address=0x3C)
device = ssd1306(serial)
logging.info("OLED device initialized successfully")
while True:
days, minutes = datetime_range(given_date)
with canvas(device) as draw:
draw.text((14,0), f"Siden dd.mm.yyyy", font=font_small, fill="white")
draw.text((0,14), f"{days} dager", font=font_large, fill="white")
draw.text((0,44), f"{minutes:.0f} min.", font=font_medium, fill="white")
logging.info(f"Display updated: {days} days, {minutes} minutes")
time.sleep(60)
except Exception as e:
logging.error(f"Error: {e}")
print(f"Error: {e}")
GØY! Men, jeg vil også at programmet kjører automatisk i det pi’en får strøm. Ikke det at det er så stor fare for strømbrudd, men design for et barneskolebarn bør være robust nok til å bli dratt ut og inn av stikkontakten og flyttet masse på.
¶Auto-boot
Automatisk oppstart viste seg å være ganske overkommelig den også. Den kan fikses med en service, og jeg kalte min for oled-display.service og la den under /etc/systemd/system/.
[Unit]
Description=OLED Display Service
After=multi-user.target
[Service]
Type=simple
User=pi
Group=i2c
WorkingDirectory=/home/pi
Environment=PATH=/home/pi/.local/bin:/usr/local/bin:/usr/bin:/bin
Environment=PYTHONPATH=/home/pi/.local/lib/python3.7/site-packages
ExecStartPre=/bin/sleep 10
ExecStart=/usr/bin/python3 /home/pi/Documents/Python/Birthday.py
Restart=always
RestartSec=5
KillMode=mixed
TimeoutStopSec=5
[Install]
WantedBy=multi-user.target
Også må den aktiveres for å kunne kjøre for hver boot:
sudo systemctl enable oled-display.service
¶Det estetiske
Nå var det store spørsmålet innpakningen. Selv om det kanskje er litt kult med litt sånn “rå” format, så hadde jeg lyst å få det til å være mer koselig og personlig. Jeg har ikke noe 3D printer og er ikke noe flink til å snekre. Valget falt på en bilderamme med foto av bursdagsbarnet. Jeg skar ut et lite hull nederst i rammen, limte fast display, plasserte boksen bak og så….
Kablene tålte ikke så mye harselering og strøk med - dagen før bursdagen!! Heldigvis var Finn hjemme og kunne lodde ny display og brukte denne gangen mykere kabler .
Det så ganske fint ut på forsiden syntes jeg, mens baksiden ble kanskje noe nedprioritert?
Ett av de store spørsmålene ble besvart og automatisert, men det åpnet for ledig tid til nye store spørsmål - det kan hende jeg må skaffe meg flere Raspberry Pi etterhvert.
