Saturday, 27 December 2014

Automatically manage the Trash in OSX

While Windows has a configurable size limit imposed on its trashbin, OSX has nothing. 

Apple's OSX does not have a mechanism to manage the trashcan. I found a simple and easy way over on the discussions.apple.com forum and turned it into a repository on GitHub: https://github.com/Mausy5043/OSX-EmptyTrash

OSX-EmptyTrash helps to manage the trash. An Applescript is offered that allows one to remove old files from the trash on a regular basis. Once a day (default: 17:00) the Trash is checked. Files that have been in the trash for longer that the preconfigured amount of time (default:7 days) are automagically removed (default: 7-pass overwrite). 
A .plist file is provided to automate the task by adding it as a LaunchAgent.

Saturday, 25 October 2014

Installing 'raspian-ua-netinst'

Download the image

Start by downloading the latest build from GitHub and unzip it.
Next, format an SD-card as FAT32 and put the unzipped files on the card. If during unzipping, the files are put in a directory then only transfer the files in it to the root directory of the card.
Put the SD-card in the Pi and power it up.
After about 15...20 minutes the Pi will reboot and a login prompt will appear. If you have a headless Pi you'll need to wait for at least 15 minutes before attempting an ssh login.

Then try to log in using ssh.
Login with root / raspbian
Change the root password to something else.
# passwd 
Update the locale:
# dpkg-reconfigure locales
Select the appropriate locale. I always use en_US.UTF8. Then also set this as the default.
Next, configure the timezone:
# dpkg-reconfigure tzdata
Those who don't like or understand vi can now install nano:
# apt-get install nano
Set the hostname to something you like better than the default 'pi'
# nano /etc/hostname 
Then make it possible to login remotely via SSH without getting loads of locale related errors.
# nano /etc/ssh/sshd_config
Comment out the line that reads AcceptEnv LANG LC_*
Then regenerate new SSH-keys for extra security:
# rm /etc/ssh/ssh_host_*
# dpkg-reconfigure openssh-server
Make a note of the IP-address (if you have the luxury of a monitor and keyboard):
# ifconfig
(If you're using a headless Pi, you will have had to find out the IP-address earlier.)

Then reboot.
# reboot
It is now possible to safely login from a remote terminal (e.g. PuTTY on Windows or iTerm.app on OSX). At this point it would be a good idea to do an update/upgrade cycle:
# apt-get update
# apt-get autoclean
# apt-get autoremove
# apt-get -yuV upgrade
This last command tells me that it didn't upgrade all the software:
Reading package lists... DoneBuilding dependency treeReading state information... DoneThe following packages have been kept back:   libgcc1 (4.7.2-5+rpi1 => 4.8.2-21~rpi3rpi1)   libstdc++6 (4.7.2-5+rpi1 => 4.8.2-21~rpi3rpi1)0 upgraded, 0 newly installed, 0 to remove and 2 not upgraded. 
This is fixed by the command:
# apt-get -yuV dist-upgrade
There are a couple of packages I like to use, that can be installed now.
# apt-get install screen lsof bc htop raspi-copies-and-fills apt-utils sudo nfs-common rsync
These will pull in a host of other packages that are required. Just, sit back and wait...

For added security, now create a new user with sudo privileges that can be used instead of the root-account. For the example here I will use the username 'pi'. You might want to use something else.
# adduser pi
This will ask for a passwd to set for the new user and some (optional) accounting information.
Then add the new user to some useful groups:
# usermod -a -G sudo pi
# usermod -a -G adm pi
# usermod -a -G users pi
# usermod -a -G video pi
# usermod -a -G dialout pi
Prevent having to type your password at every 'sudo' you do.
# visudo
Change this line:
%sudo   ALL=(ALL:ALL) ALL
To look like this:
%sudo   ALL=(ALL:ALL) NOPASSWD: ALL

I also like to move some parts of the filingsystem to RAM:
# nano /etc/fstab
add these lines:
tmpfs /tmp tmpfs nodev,nosuid,size=30M,mode=1777                 0 0
tmpfs /var/log tmpfs defaults,noatime,nosuid,mode=0755,size=100M 0 0

Next, reboot and you'll be able to login with the newly created user. Then edit the .profile file:
$ nano .profile
And add this line at the end of the file
PATH="/usr/local/sbin:/usr/sbin:/sbin:$PATH"

Having created an extra user with sudo privileges it is time to take away some of the privileges of the root-account.
$ sudo nano /etc/ssh/sshd_config
Find the line reading:
PermitRootLogin yes
And change the yes to a no.

Extended installation

Create a mountpoint for future use.
$ sudo mkdir /mnt/share1
I'll be using nfs to mount a drive from one of the servers on my local network. To prevent problems with slow mounts I need to blacklist a kernel-module. I have no idea why, but this seems to work. Other Pies in my network, running a full Raspbian version don't have this problem but also don't use this fix. Again, I don't have a clue why.
$ sudo nano /etc/modprobe.d/blacklist.conf
Then add this line:
blacklist rpcsec_gss_krb5

Create various folders
$ mkdir etc
$ mkdir bin
$ mkdir bin/run
If you're using this Pi as a headless machine there is no need for all the gettys so we'll disable a couple as follows:
First make a backup of the original
$ sudo cp /etc/inittab /etc/inittab.org
$ sudo nano /etc/inittab
Find these lines and comment them out:
#3:23:respawn:/sbin/getty 38400 tty3
#4:23:respawn:/sbin/getty 38400 tty4
#5:23:respawn:/sbin/getty 38400 tty5
#6:23:respawn:/sbin/getty 38400 tty6
Then make a backup copy of the final file
$ cp /etc/inittab ~/etc/inittab
I like a coloured terminal, so I'll set up .bashrc to support that:
$ nano .bashrc
First, find this line and uncomment it:

force_color_prompt=yes

then scroll down and make changes so these lines read as follows:

    alias grep='grep --color=auto'
    alias fgrep='fgrep --color=auto'
    alias egrep='egrep --color=auto'
fi

# some more ls aliases
alias ll='ls -l'
alias la='ls -al'
#alias l='ls -CF'

(Additionally you may want to create a file .dircolors and fill it with your desired definitions. This is outside the scope of this howto. Google is your friend).

Reduce the amount of video memory to the bare minimum:
$ nano /boot/config.txt
Add this line:
gpu_mem=16

Reboot and log back in, to make all the above changes take effect in one go.
$ sudo reboot

Finally

The number of packages installed on my Pi is now:
$ dpkg -l |wc -l
180

For comparison, on a default Raspbian system I have running it is 825!
Remember to regularly (e.g. once a week) execute an update/upgrade cycle (as described above) to ensure you are on the most up-to-date version of the operating system.

Tuesday, 14 October 2014

Slimme electriciteitsmeter (Kamstrup 162JxC) uitlezen met de Raspberry Pi (dutch how-to)

Inleiding

Begin oktober 2014 besloot de netwerkbeheerder dat het tijd was om mijn vertrouwde, ouderwetse electriciteitsmeter te vervangen door een 'slimme' meter.
De nieuwe meter betreft een Kamstrup 162JxC.
Omdat ik al diverse projecten heb uitgevoerd met de Raspberry Pi (MediaCenter, UPS monitor/controller, data-logging met RRDtool) en omdat ik tot op heden handmatig de meterstanden bijhield, vond ik het wel een leuke uitdaging om eens te kijken of ik deze meter met een Raspberry Pi kon uitlezen. Er zit immers een communicatie-poort op deze meter die erom vraagt om uitgelezen te worden.
Het manual van de meter vond ik op kamstrup.nl. Helaas staat er weinig bruikbare informatie in.
Informatie over de P1 poort vond ik hier (DSMR v4) of hier (DSMR v3) Dit documentje lijkt meer nuttige informatie te bevatten.

Boodschappenlijstje

  • Om de verbinding te kunnen maken tussen de meter en de Raspberry Pi is een speciale kabel nodig. Deze "P1 Converter Cable" is te koop op de website smartmeterdashboard.nl. Ik heb daar de P1 Converter Cable v2 gekocht voor 22.50 euro.
  • Voor de Raspberry Pi zelf shop ik altijd bij The Pi Hut. Ik heb daar een Raspberry Pi Model B+, een 8GB (kleiner is al  bijna niet meer te krijgen...) micro-SDHC kaart (met NOOBS), een 5V 2A micro-USB voeding en een Multicomp Case op de kop getikt voor totaal ongeveer 59.00 euro (incl. verzendkosten).
  • Een UTP-kabel (voor deze toepassing is een Cat.5 al voldoende) heb ik nog liggen en de router staat in de meterkast, dus de verbinding met mijn thuisnetwerk is makkelijk gemaakt.
  • Enige kennis van Python, Linux (bij voorkeur Debian of een afgeleide daarvan) en ervaring met de Raspberry Pi zijn een pré. 
  • Mocht onderstaande beschrijving op punten onduidelijk zijn... Google is je vriend.
De totale kosten voor dit project zijn dus 81.50 euro.

De Raspberry Pi model B+ vervangt een al bestaande Pi model B. Het B-model ga ik gebruiken voor dit project. Het B-plus-model krijgt een andere bestemming.
Omdat de Raspberry Pi geen monitor of toetsenbord heeft, is een computer nodig die via het (thuis-)netwerk verbinding kan maken met de Pi. Voor Windows kun je gebruik maken van ssh via Putty; in OSX is Terminal.app of iTerm.app een goede keuze en is ssh standaard beschikbaar. Ik neem even aan dat het IP-adres bekend is. Op mijn router heb ik het MAC-adres van de Raspberry Pi verbonden aan een vast IP-adres. Dat maakt het inloggen later een stuk gemakkelijker.

NOOBS

NOOBS staat voor "New Out OBox Software" en is een pakket bestaande uit 6 operating systems die erg populair zijn voor de Raspberry Pi (ArchLinux, Raspian, Pidora, RaspBMC, OpenELEC en RiscOS). Als je een SD-kaart specifiek voor de Raspberry Pi koopt, wordt die momenteel zo'n beetje standaard met dit pakket erop geleverd. Leuk voor de beginners om eens mee te experimenteren, maar omdat ik voor dit project geen behoefte heb aan de geboden keuzemogelijkheden, zal ik de SD-kaart leeg maken en er een andere bestemming aan geven.

Raspbian

De nieuwste versie van Raspbian download ik altijd vanaf de RaspberryPi.org website. Hoe een SD-kaart voorzien moet worden van dit image is daar ook te vinden in de installatie instructie. Een alternatieve installatie methode voor Apple gebruikers is, om gebruik te maken van de OSX app "Apple-Pi-Baker.app"
Als de image op de kaart staat zijn we klaar om van start te gaan.

Als je al een SD-kaartje hebt (en vooral als die kleiner is dan 4GB) dan valt het te overwegen om er een afgeslankte versie van Raspbian op te installeren. Zie deze handleiding (engelstalig). Ga daarna hieronder verder bij het hoofdstukje "Pakketten installeren".

Power On!

In principe kun je nu al meteen de boel in de meterkast aansluiten. Plaats de SD-kaart in de Pi, sluit de P1 Converterkabel aan op de electriciteitsmeter en steek de USB-stekker in de Pi. Sluit dan de voeding aan en steek de stekker in het stopcontact.
In mijn netwerk heb ik voor de Raspberry Pi het IP-adres 10.0.1.228 gealloceerd.
Op mijn laptop (Putty of terminal) wacht ik op het actief worden van de Raspberry Pi met het ping commando.
$ ping 10.0.1.228
PING 10.0.1.228 (10.0.1.228): 56 data bytes
Request timeout for icmp_seq 0
Request timeout for icmp_seq 1
64 bytes from 10.0.1.228: icmp_seq=64 ttl=64 time=4.366 ms
Nu kan ingelogd worden met
$ ssh pi@10.0.1.228
Als eerste zal nu de installatie afgemaakt moeten worden.
$ sudo raspi-config

In het menu dat nu verschijnt (zie afbeelding) maak ik de volgende selecties:
1. Expand Filesystem -> OK
2. Change User Password -> OK -> volg de aanwijzingen op het scherm
3. Enable Boot to Desktop/Scratch -> Console text console -> OK
4. Internationalisation Options -> I1 Change locale -> Er verschijnt nu een lange lijst met locales (regios/talen). Bij en_GB.UTF8 staat al een sterretje. Haal dat weg door erop te gaan staan met de cursor en op de spatiebalk te drukken.  Zoek vervolgens de gewenste locale en selecteer die met de spatiebalk. Zelf selecteer ik altijd en_US.UTF8. De kans dat mijn US toetsenbord dan goed werkt is dan het grootst ;-) Selecteer daarna de gewenste locale als de default. -> OK.
5. Internationalisation Options -> I2 Change timezone -> Ik kies hier Europe/Amsterdam.
8. Advanced Options -> A2 Hostname -> OK -> Verander desgewenst de standaard hostname (raspberrypi) in iets anders. Omdat alle servers binnen mijn netwerk de naam hebben van een elementair deeltje kies ik voor de voor de hand liggende naam electron.
9. Advanced Options -> A3 Memory Split -> Verander de hoeveelheid videogeheugen naar 16. Meer hebben we niet nodig.
10. Advanced Options -> A4 SSH -> Enable : SSH staat al aan, maar voor de zekerheid enable ik deze optie alsnog.

Finish -> Would you like to reboot now? -> NO : Ik ben nog niet klaar...

Terug op de command-line zien we een hoop foutmeldingen. Ongeveer zoiets als dit:
perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
LANGUAGE = (unset),
LC_ALL = (unset),
LC_CTYPE = "UTF-8",
LANG = "en_GB.UTF-8"
are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").
locale: Cannot set LC_CTYPE to default locale: No such file or directory
locale: Cannot set LC_MESSAGES to default locale: No such file or directory
locale: Cannot set LC_ALL to default locale: No such file or directory
/usr/bin/locale: Cannot set LC_CTYPE to default locale: No such file or directory
/usr/bin/locale: Cannot set LC_MESSAGES to default locale: No such file or directory
/usr/bin/locale: Cannot set LC_ALL to default locale: No such file or directory
Daar ga ik eerst iets aan doen. De oorzaak van deze meldingen is gelegen in het feit dat de terminal via ssh een locale probeert in te stellen.
$ sudo nano /etc/ssh/sshd_config
Bijna onderaan dit bestand staan de regels
# Allow client to pass locale environment variables
AcceptEnv LANG LC_*
Plaats een # voor die tweede regel (comment out), zodat je er dit staat:
# Allow client to pass locale environment variables
# AcceptEnv LANG LC_*
Om de SD-kaart te sparen verplaatsen we de /tmp directory naar tmpfs:
$ sudo nano /etc/fstab
Voeg deze regel toe:
tmpfs /tmp tmpfs nodev,nosuid,size=30M,mode=1777 0 0 
Ook de swap hebben we niet nodig:
$ sudo dphys-swapfile uninstall
$ sudo rm /etc/init.d/dphys-swapfile
En de gebruiker pi moet ook toegevoegd worden aan de groep dialout.
$ sudo usermod -a -G dialout pi
Rest ons nog om de ssh sleutels te regenereren gevolgd door een reboot.
$ sudo rm /etc/ssh/ssh_host_*
$ sudo dpkg-reconfigure openssh-server

$ sudo reboot; exit

Pakketten installeren

De volgende stap is het installeren van diverse software die niet standaard op de Raspberry Pi aanwezig is, maar wel handig kan zijn. Om te beginnen voeren we een update uit van de reeds aanwezige software:
$ sudo apt-get update
$ sudo apt-get autoclean
$ sudo apt-get autoremove
$ sudo apt-get -yuV upgrade
Het is zeer aanbevelenswaardig, om bovenstaande vier commando's met enige regelmaat op het systeem uit te voeren, zodat het systeem up-to-date blijft.
Dan installeer ik:
  • htop; een grafische versie van top,
  • screen; hiermee kan een terminal-sessie worden voortgezet zonder dat je daarvoor ingelogd hoeft te zijn,
  • lsof; toont open bestanden EN door welke programma ze geopend zijn,
  • bc; command-line calculator,
  • python-serial; een Python module die we nodig hebben om met P1 poort op de electriciteitsmeter te kunnen communiceren,
  • cu; programma om de communicatie met de P1-poort te kunnen testen en troubleshooten.
$ sudo apt-get install bc htop screen lsof python-serial cu
Pas de opstartparameters aan, zodat de serieele poort niet door de kernel misbruikt wordt:
$ sudo nano /boot/cmdline.txt
In dit bestand verwijder ik de console= en kgdboc= parameters (hier doorgestreept):

dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 elevator=deadline root=/dev/mmcblk0p2 rootfstype=ext4 rootwait

$ sudo reboot; exit

Communicatie test

Nu is het tijd om te kijken of de Raspberry Pi onze slimme meter via de P1 Converter kabel kan verstaan. Als eerste dient gecontroleerd te worden of de P1 Converter Cable goed gedetecteerd is:
$ dmesg | grep usb
Deze output laat zien dat de kabel goed gedetecteerd wordt:
[2014-10-28 16:30:15]  usb 1-1.2: new full-speed USB device number 4 using dwc_otg
[2014-10-28 16:30:15]  usb 1-1.2: New USB device found, idVendor=0403, idProduct=6001
[2014-10-28 16:30:15]  usb 1-1.2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[2014-10-28 16:30:15]  usb 1-1.2: Product: P1 Converter Cable
[2014-10-28 16:30:15]  usb 1-1.2: Manufacturer: FTDI
[2014-10-28 16:30:15]  usb 1-1.2: SerialNumber: A6Y1OLG2
[2014-10-28 16:30:15]  usbcore: registered new interface driver usbserial
[2014-10-28 16:30:15]  usbcore: registered new interface driver usbserial_generic
[2014-10-28 16:30:15]  usbserial: USB Serial support registered for generic
[2014-10-28 16:30:16]  usbcore: registered new interface driver ftdi_sio
[2014-10-28 16:30:16]  usbserial: USB Serial support registered for FTDI USB Serial Device
[2014-10-28 16:30:16]  usb 1-1.2: Detected FT232RL
[2014-10-28 16:30:16]  usb 1-1.2: Number of endpoints 2
[2014-10-28 16:30:16]  usb 1-1.2: Endpoint 1 MaxPacketSize 64
[2014-10-28 16:30:16]  usb 1-1.2: Endpoint 2 MaxPacketSize 64
[2014-10-28 16:30:16]  usb 1-1.2: Setting MaxPacketSize 64
[2014-10-28 16:30:16]  usb 1-1.2: FTDI USB Serial Device converter now attached to ttyUSB0

De laatste regel toont dat de kabel verbonden is met /dev/ttyUSB0. Handig om te weten.

Als tweede test proberen we de meter uit te lezen:
$ cu -l /dev/ttyUSB0 -s 9600 --parity=none
Binnen 10 seconden zou dan iets dergelijks op het scherm moeten verschijnen:
Connected.
/KMP5 KA6U00xxxxxxxx

0-0:96.1.1(xxxxxxx)
1-0:1.8.1(00170.393*kWh)
1-0:1.8.2(00122.009*kWh)
1-0:2.8.1(00000.000*kWh)
1-0:2.8.2(00000.000*kWh)
0-0:96.14.0(0002)
1-0:1.7.0(0000.38*kW)
1-0:2.7.0(0000.00*kW)
0-0:17.0.0(999*A)
0-0:96.3.10(1)
0-0:96.13.1()
0-0:96.13.0()
!

Sluit 'cu' af met ~. gevolgd door een enter. Als je via ssh ingelogd bent op de Pi kan het zijn dat nu de verbinding met de Pi verbroken wordt. Dit komt omdat ssh ook de ~. herkent als een "verbreek-de-verbinding" signaal. IN dat geval dient de tilde tweemaal getypt te worden: ~~., zodat ssh de tilde-punt negeert.

In de DSMR specificatie v3.0 op pagina 14 staat een tabel met de betekenis van de verschillende regels. Ik ben vooral geïntereseerd in het cumulatieve verbruik (1.8.1 en 1.8.2 in kWh) en in het actuele vermogen (1.7.0 in kW). Voor mensen die ook stroom terug leveren zijn respectievelijk 2.8.1, 2.8.2 en 2.7.0 ook interessant. 96.14.0 geeft aan of het hoge of lage tarief actief is (ook wel piek/dal of dag/nacht). Ook 96.3.10 kan interessant zijn. Deze geeft aan of er (1) stroom wordt afgenomen of (2) stroom wordt teruggeleverd.

Merk op dat de gegevens die de meter verstuurt voorafgegaan worden door een schuine streep ("/") en dat het einde van de data afgesloten wordt met een uitroepteken ("!"). Hier ga ik later in het programma dankbaar gebruik van maken.

Automatisch uitlezen van de meter


Als dat nog niet is gedaan, maak je nu een directory aan om de binary in op te slaan:
$ mkdir ~/bin

Dan maken we een bestand aan:
$ nano ~/bin/readkamstrup.py
En vullen het met deze code:
#! /usr/bin/python

import sys, serial, re

port          = serial.Serial()
port.baudrate = 9600
port.bytesize = serial.SEVENBITS
port.parity   = serial.PARITY_EVEN
port.stopbits = serial.STOPBITS_ONE
port.xonxoff  = 1
port.rtscts   = 0
port.dsrdtr   = 0
port.timeout  = 0
port.port     = "/dev/ttyUSB0"

def gettelegram():
  # flag used to exit the while-loop
  abort = 0
  # countdown counter used to prevent infinite loops
  loops2go = 40
  # storage space for the telegram
  telegram = []
  # end of line delimiter
  delim = "\x0d"

  try:
    port.open()
  except:
    abort == 4
    # open error terminates immediately
    return telegram, abort

  while abort == 0:
    try:
      line = "".join(iter(lambda:port.read(1),delim)).strip()
    except:
      # read error
      abort = 2
    if line == "!":
      # end of telegram uncountered
      abort = 1
    telegram.append(line)
    loops2go = loops2go - 1
    if loops2go < 0:
      abort = 3

  # test for correct start of telegram
  if telegram[0][0] != "/":
    abort = 2

  try:
    port.close()
  except:
    abort == 5

  # Return codes:
  # abort == 1 indicates a successful read
  # abort == 2 means that no valid data was read from the serial port
  # abort == 3 indicates a data overrun. More lines were received than expected.
  # abort == 4 indicates a serial port open error.
  # abort == 5 indicates a serial port close error.
  return (telegram, abort)

if __name__ == "__main__":

  electra1in = -1
  electra2in = -1
  electra1out = -1
  electra2out = -1
  tarif = -1
  swits = -1
  powerin = -1
  powerout = -1
  telegram, status = gettelegram()
  if status == 1:
    for element in range(3, len(telegram) - 1):
      line =  re.split( '[\(\*\)]', telegram[element] )
      #['1-0:1.8.1', '00175.402', 'kWh', '']
      if (line[0] == '1-0:1.8.1'):
        electra1in = float(line[1])
      #['1-0:1.8.2', '00136.043', 'kWh', '']
      if (line[0] == '1-0:1.8.2'):
        electra2in = float(line[1])
      #['1-0:2.8.1', '00000.000', 'kWh', '']
      if (line[0] == '1-0:2.8.1'):
        electra1out = float(line[1])
      #['1-0:2.8.2', '00000.000', 'kWh', '']
      if (line[0] == '1-0:2.8.2'):
        electra2out = float(line[1])
      #['0-0:96.14.0', '0002', '']
      if (line[0] == '0-0:96.14.0'):
        tarif = int(line[1])
      #['1-0:1.7.0', '0000.32', 'kW', '']
      if (line[0] == '1-0:1.7.0'):
        powerin = float(line[1])
      #['1-0:2.7.0', '0000.00', 'kW', '']
      if (line[0] == '1-0:2.7.0'):
        powerout = float(line[1])
      #['0-0:17.0.0', '999', 'A', '']
         # not recorded
      #['0-0:96.3.10', '1', '']
      if (line[0] == '0-0:96.3.10'):
        swits = int(line[1])
      #['0-0:96.13.1', '', '']
         # not recorded
      #['0-0:96.13.0', '', '']
         # not recorded

    # Print the data
    print '{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}'.format(electra1in, electra2in, powerin, electra1out, electra2out, powerout, tarif, swits)

Zet de rechten:
$ chmod 740 ~/bin/readkamstrup.py
$  readkamstrup.py
175.402, 137.382, 0.53, 0.0, 0.0, 0.0, 2, 1

Door nu met het script te spelen, zijn hier leuke dingen mee te doen. Zo laat ik ook de datum/tijd afdrukken, waarna ik de data in een rrdtool database opneem ten behoeve van een webpagina waarop de status wordt weergegeven. 

Veel succes en plezier. Laat gerust in de comments een opmerking achter als je bovenstaande code gebruikt.