Onze apparaten zitten vol sensoren, deze produceren meetresultaten die ingezet worden om zaken bij te sturen. Zo wordt de temperatuur van de processor in uw computer gemeten om bij oververhitting de processor wat te laten afkoelen door deze minder te belasten. Zo gaat deze langer mee.
Twee weken terug gebruikten we een webcamera om de lichtintensiteit in een ruimte te meten en daarmee de helderheid van de monitor mee te regelen.
De hier gepresenteerde opdrachten en scripts ga je waarschijnlijk niet letterlijk gebruiken, maar ze bevatten wel veel opdrachten waarmee je gegevens kunt afzonderen, opslaan en verwerken met behulp van wiskundige berekeningen.
Elektronische sensoren werken niet zoals menselijke sensoren. We ervaren vochtige warmte als veel warmer (zelf ondraaglijk) als droge warmte. We merken een brandende kaars in het donker goed op, maar in de zon verdwijnt deze in een overvloed van zonlicht.
Er bestaan dan ook verschillende manieren om bijvoorbeeld de lichtintensiteit via een webcam te meten. Ten eerste door de met de webcam genomen foto te analyseren (zie Schermhelderheid automatisch aanpassen):
dany@pindabook:~> convert fswebcam.jpg -colorspace gray -format "%[fx:1*mean]" info:
0.366426
Je kunt de lichtintensiteit van de omgeving ook bepalen aan de hand van de manier waarop de foto is genomen. Sommige programma's om foto's te nemen slaan die gegevens op in de foto zelf (EXIF gegevens). Om een goede foto te nemen passen camera's naargelang het omgevingslicht hun diafragma-opening (FNumber), sluitertijd (ExposureTime) en de filmgevoeligheid (ISOSpeedRatings) automatisch aan. Aan de hand van deze EXIF waarden kan je op een andere manier de hoeveelheid omgevingslicht meten.
Op een Raspberry Pi kan je met raspistill een foto met deze EXIF gegevens via een PiCamera maken:
pi@rpipindanet:~ $ raspistill -n -w 800 -h 480 -o brightness.jpg
Om de EXIF waarden uit te lezen, installeer je ImageMagick:
pi@rpipindanet:~ $ sudo apt-get install imagemagick
De EXIF gegevens vraag je op met de opdracht:
pi@rpipindanet:~ $ identify -verbose brightness.jpg
Image: brightness.jpg
Format: JPEG (Joint Photographic Experts Group JFIF format)
Mime type: image/jpeg
Class: DirectClass
Geometry: 800x480+0+0
...
Orientation: Undefined
Properties:
date:create: 2019-08-24T14:12:01+02:00
...
exif:ExposureProgram: 3
exif:ExposureTime: 22108/1000000
exif:Flash: 0
exif:FlashPixVersion: 48, 49, 48, 48
exif:FNumber: 20000/10000
exif:FocalLength: 30390/10000
exif:ImageLength: 480
exif:ImageWidth: 800
exif:InteroperabilityOffset: 908
exif:ISOSpeedRatings: 50
exif:Make: RaspberryPi
...
signature: 85b95c3277e4a09728dddac3d06d13a47018639df994045af199a41b7e36b45d
Profiles:
Profile-exif: 25626 bytes
Artifacts:
filename: brightness.jpg
verbose: true
Tainted: False
Filesize: 289KB
Number pixels: 384K
Pixels per second: 4.267MB
User time: 0.090u
Elapsed time: 0:01.090
Version: ImageMagick 6.9.7-4 Q16 arm 20170114 http://www.imagemagick.org
Om de EXIF gegevens te verwerken, sla je ze op in een variabele:
pi@rpipindanet:~ $ jpginfo=$(identify -verbose brightness.jpg)
De waarden om de lichtintensiteit van de omgeving te berekenen, haal je er als volgt uit:
pi@rpipindanet:~ $FNumber=$(grep FNumber <<< "$jpginfo" | awk '{print $2}')
pi@rpipindanet:~ $ExposureTime=$(grep ExposureTime <<< "$jpginfo" | awk '{print $2}')
pi@rpipindanet:~ $ISOSpeedRatings=$(grep ISOSpeedRatings <<< "$jpginfo" | awk '{print $2}')
pi@rpipindanet:~ $echo $FNumber $ExposureTime $ISOSpeedRatings
20000/10000 22108/1000000 50
Uiteindelijk bereken je met deze gegevens het omgevingslicht:
pi@rpipindanet:~ $lux=$(awk "BEGIN {printf \"%.2f\", ($FNumber * $FNumber) / ($ISOSpeedRatings * $ExposureTime)}")
pi@rpipindanet:~ $echo $lux
3.62
Deze berekende waarde wordt dan uiteindelijk beschikbaar gemaakt via een http (apache) verbinding. Daar het opzetten van een http verbinding ons te ver zou afleiden, vermeld ik hier dat we daarvoor deze in een speciale http server map opslaan. Het script gedeelte op mijn Raspberry Pi verantwoordelijk voor het maken en opslaan van de gemeten lichtintensiteit wordt dan:
if [ ! -d /var/www/html/motion/day ]; then mkdir -p /var/www/html/motion/day; fi if [ ! -d /var/www/html/data ]; then mkdir -p /var/www/html/data; fi now=$(date +%H:%M) raspistill -n -w 800 -h 480 -o /var/www/html/motion/day/$now.jpg find /var/www/html/motion/day/*.jpg -mtime +0 -type f -delete # Calculate lux jpginfo=$(identify -verbose /var/www/html/motion/day/$now.jpg) FNumber=$(grep FNumber <<< "$jpginfo" | awk '{print $2}') ExposureTime=$(grep ExposureTime <<< "$jpginfo" | awk '{print $2}') ISOSpeedRatings=$(grep ISOSpeedRatings <<< "$jpginfo" | awk '{print $2}') lux=$(awk "BEGIN {printf \"%.2f\", ($FNumber * $FNumber) / ($ISOSpeedRatings * $ExposureTime)}") echo $lux > /var/www/html/data/lux if [ ! -f /var/www/html/data/luxmax ]; then echo 0 > /var/www/html/data/luxmax fi luxmax=$(cat /var/www/html/data/luxmax) if [ ! -f /var/www/html/data/luxmin ]; then echo 1000000 > /var/www/html/data/luxmin fi luxmin=$(cat /var/www/html/data/luxmin) if [ ${lux%.*} -eq ${luxmax%.*} ] && [ ${lux#*.} \> ${luxmax#*.} ] || [ ${lux%.*} -gt ${luxmax%.*} ]; then luxmax=$lux fi if [ ${lux%.*} -eq ${luxmin%.*} ] && [ ${lux#*.} \< ${luxmin#*.} ] || [ ${lux%.*} -lt ${luxmin%.*} ]; then luxmin=$lux fi echo $luxmax > /var/www/html/data/luxmax echo $luxmin > /var/www/html/data/luxmin
Naast het opslaan van de lichtintensiteit, wordt ook een minimum en maximum waarde berekend en opgeslagen. Deze waarden hebben we nodig om straks de helderheid van de monitor te berekenen.
Nu we lichtintensiteit van het omgevingslicht kennen, kunnen we deze gebruiken om bijvoorbeeld de helderheid van onze monitor te regelen. Een eerste methode staat beschreven in het artikel Schermhelderheid automatisch aanpassen. Deze hield echter weinig rekening met de werking van ons oog en de verwerking van de oogbeelden door onze hersenen. Een realistischer beeldregeling krijg je door de schermhelderheid niet lineair aan te passen. Het script om de helderheid van de monitor automatisch aan te passen wordt dan:
#!/bin/bash # brightness.sh # Bepaal de map van het script SOURCE="${BASH_SOURCE[0]}" while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink TARGET="$(readlink "$SOURCE")" if [[ $TARGET == /* ]]; then SOURCE="$TARGET" else DIR="$( dirname "$SOURCE" )" SOURCE="$DIR/$TARGET" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located fi done RDIR="$( dirname "$SOURCE" )" DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )" # Controleer of het script al gestart is! aantal=$(ps aux | grep -v "grep" | grep "$0" | wc -l) # Bij een eerste start wordt het script gestart, # bij een tweede start wordt het draaiende script afgesloten if [ $aantal -gt 2 ]; then # Sluit het draaiende script af proces=$(ps aux | grep -v "grep" | grep "$0" | awk '{print $2}') kill $proces exit fi # Test op de melding Invalid MIT-MAGIC-COOKIE-1 key xhost 2>&1 | grep "Invalid MIT-MAGIC-COOKIE-1 key" if [ $? = 0 ]; then echo "Invalid MIT-MAGIC-COOKIE-1 key melding omzeilen" xhost local:+ fi while : do # Welke monitor is actief? monitor=$(xrandr | grep " connected" | cut -f1 -d " ") echo "Aangeslote monitor: $monitor" # Haal het omgevingslicht op lux=$(curl -k https://rpipindanet/data/lux) if [ $? = 0 ]; then # Ophalen van meting gelukt en kan dus opgeslagen worden echo "Omgevingslicht: $lux" maxlux=$(curl -k https://rpipindanet/data/luxmax) minlux=$(curl -k https://rpipindanet/data/luxmin) echo Maximaal gemeten omgevingslicht: $maxlux echo Minimaal gemeten omgevingslicht: $minlux rangelux=$(awk "BEGIN {printf \"%.2f\", $maxlux - $minlux}") echo Bereik gemeten omgevingslicht: $rangelux rellux=$(awk "BEGIN {printf \"%.2f\", ($lux - $minlux) / $rangelux}") rellux=$(awk "BEGIN {printf sqrt($rellux)}") echo Relatief omgevingslicht: $rellux helderheid=$(awk "BEGIN {printf \"%.2f\", 0.60 + $rellux * 0.40}") # Huidige helderheid huidige=$(xrandr --verbose | grep -i brightness | cut -f2 -d ' ' | head -n1) # Helderheid geleidelijk aanpassen echo "Helderheid aanpassen van $huidige naar $helderheid" if [ ${huidige%.*} -eq ${helderheid%.*} ] && [ ${huidige#*.} \< ${helderheid#*.} ] || [ ${huidige%.*} -lt ${helderheid%.*} ]; then for i in $( LANG=en_US seq $huidige 0.01 $helderheid ); do echo verhogen: $i xrandr --output $monitor --brightness $i sleep 1 done else for i in $( LANG=en_US seq $huidige -0.01 $helderheid ); do echo verlagen: $i xrandr --output $monitor --brightness $i sleep 1 done fi fi # Wacht 1 minuut sleep 60 done
De regel
rellux=$(awk "BEGIN {printf sqrt($rellux)}")
zorgt voor het niet lineaire verloop van de regeling (sqrt = vierkantswortel).
Let ook op het gedeelte waarbij we de helderheidsaanpassing van het beeldscherm geleidelijk laten verlopen. Plotse grote helderheidssprongen zijn namelijk storend.