Lampen schakelen met zonsondergang en zonsopgang

Doel 

Verlichting aan en uitschakelen met het opkomen en ondergaan van de zon.

Benodigdheden 
Tutorial 

We hebben al eerder lampen automatisch geschakeld met behulp van een programmaatje om draadloos schakelbare stopcontacten van de action te schakelen en cron. Hoewel dat zeker nuttig kan zijn is zoiets even makkelijk haalbaar met een tijdschakelaar van een paar euro. Zelf gebruikte ik de methode uit die tutorial om mijn buitenverlichting aan en uit te schakelen aan het eind en begin van de dag maar dan moet je zeker in de lente en de herfst om de paar weken de tijden aanpassen. Dat is niet handig. In deze tutorial gaan we pas echt de meerwaarde van een RPi geschakeld stopcontact benutten. We gaan de buitenverlichting aanzetten als de zon onder gaat en weer uitzetten als hij opkomt. Deze keer gebruik ik overigens gewoon Raspbian (ipv Arch Linux), zoals de rest van de wereld, daardoor beginnen we weer helemaal bij het begin.

Mijn filosofie is altijd: Maak zoveel mogelijk gebruik van de tools die er standaard al draaien. Dat betekend bijvoorbeeld als ik iets op een specifieke tijd wil uitvoeren, dan gebruik ik Cron, de "job scheduler" die standaard op alle Linux distro's aanwezig is, dus ook op Raspbian. Ook Python staat standaard op Raspbian geïnstalleerd en we zullen daar dus ook gebruik van maken.

De aanpak is als volgt: We vinden een manier om er achter te komen wanneer de zon precies opkomt en ondergaat op onze locatie. Deze informatie gebruiken we om elke nacht een "cronjob" in te plannen die onze lampen de aankomende dag op de exacte tijden van zonsopkomst en zonondergang uit- en aanschakelt.

De Hardware

We sluiten eerst de rf-transmitter aan op de juiste poorten van de RPi op de volgende manier:
  • Vcc van de transmitter op pin 4 (het cijfer in het rondje) van je Pi (VCC 5V)
  • GND van de transmitter op pin 6 van je Pi (GND)
  • Data in van de transmitter op pin 8 van je Pi (GPIO14)
Wat de VCC, GND (ground) en ATAD pinnen op de rf transmitter precies zijn vind je in een PDF op de informatie pagina van de RF transmitter op de iPrototype website. Het plaatjes hieronder komt uit die PDF.

rf-transmitter
Figuur 1: De pinnen van de RF transmitter.

Welke pinnen je op RPi moet gebruiken vind je op "De Raspberry Pi GPIO pinnen". Voor de duidelijkheid, de oriëntatie van dat plaatje klopt met de RPi als je de pinnen links boven houdt. Uiteindelijk sluit je dus de eerste, derde en vierde pin van links boven aan.

De Software

Open een terminal of log in op je RPi via SSH, update nu eerst je Pi:
sudo apt-get update && sudo apt-get upgrade

Vervolgens willen we dat de tijd (altijd) correct is op onze RPi. Op de RPi draait standaard een NTP (Network Time Protocol) daemon dus de tijd klopt altijd perfect, wat niet altijd klopt is de tijdzone waarin de Pi denkt zich te bevinden. Om de Pi de vertellen in welke tijdzone hij zich bevindt doen we het volgende:
sudo cp /usr/share/zoneinfo/Europe/Amsterdam /etc/localtime

We hebben ook een programmatje nodig wat daadwerkelijk de 434 Mhz transmitter aanstuurt en de stopcontacten schakelt. Net als in de tutorial "Lampen aan- en uitschakelen met je telefoon " gebruiken we een stukje code van Tweaker weejewel (inmiddels gefixt door mouse86 voor de RPi2) uit zijn Tweakblog "Lampen schakelen met een Raspberry Pi". Zorg dat je in je home map zit met het commando:
cd
Download een zip file met de schakelprogramma's voor de verschillende merken draadloos schakelbare stopcontacten:
wget -O lights.zip https://dl.dropboxusercontent.com/u/7522515/tweakers/rpi-kaku/20150702V1-lights.zip?dl=1
Pak het zip bestand uit:
unzip lights.zip
ga de gecreëerde map in:
cd lights
en compileer de versie die je nodig hebt, in mijn geval de versie voor de Action stopcontacten:
g++ -o action action.cpp -I/usr/local/include -L/usr/local/lib -lwiringPi
Dit commando genereert een executable genaamt "action" (of elro, blokker, etc). We verplaatsen de executable naar de map /usr/bin, deze map staat in de path variabele en executables die in die map staan kun je vanaf elke locatie bij hun naam aanroepen:
sudo cp action /usr/bin/
Nog een belangrijk detail is om het programma standaard met root (admin) rechten uit te voeren met:
sudo chmod +s /usr/bin/action

Het programma "action" vraagt om wat parameters die overeenstemmen met hoe je afstandsbediening staat ingesteld. Voor mij is het commando om de stopcontacten te schakelen:
action 63 A on
"63" staat voor hoe de pinnen in het stopcontact staan en de "A" staat voor het stopcontact in de set (ik heb er 3, de ene reageert op A, de andere op B en de derde op C). Om het stopcontact weer uit te schakelen geef je het commando:
action 63 A off

Als het getal 63 niet werkt moet je de stopcontacten open schroeven en kijken hoe de "switches" staan. Op deze website vind je een "dip switch calculator" waarmee je kunt berekenen welk getal bij jouw switch configuratie past. Als de switches hetzelfde staan (je heb 1 switch te veel, je moet even proberen hoe dat uitpakt) dan komt het getal wat je nodig hebt te staan bij DMX Address, dit is het getal wat je moet gebruiken in plaats van "63" in de rest van deze tutorial.

Als het goed is kun je nu je stopcontact op de commandline aan en uitschakelen.

We hebben ook een aantal Python modules nodig om straks de tijden van zonsopkomst en zonsondergang te berekenen en om dagelijks de schakeltijd aan te passen:
sudo apt-get install python3-crontab
De tweede, Astral zit helaas niet in de repositories van Raspbian dus daarvoor moeten we eerst Pip installeren. Pip is een tool om Python modules (Packages) te installeren uit de Python Package Index:
sudo apt-get install python3-pip
Nu kunnen we Pip gebruiken om Astral te installeren:
sudo pip3 install astral
Alles wat we nodig hebben staat nu geïnstalleerd.

De lampen schakelen met zonsopkomst en zonsondergang

Nu we het stopcontact (en dus de lamp) kunnen schakelen met een programmaatje moeten we dit programmaatje alleen nog op de juiste tijden zien uit te voeren. Dit doen we normaal gesproken met een cronjob, hoe je dat precies zou doen staat hier beschreven: "Lampen automatisch schakelen". Het probleem met die oplossing is dat zo de lamp elke dag op dezelfde tijd wordt aan- en uitgeschakeld terwijl de zonsopkomst en zonsondergang met een paar uur variëren over het jaar heen. Het script hieronder gebruikt de eerder geïnstalleerde Python modules Astral en python-cronjob om de tijden van de zonsopkomst en -ondergang van de huidige datum en locatie toe te voegen aan de crontab (de lijst met ingeplande taken voor een Linux/Unix systeem). We gaan dit script ook in /usr/bin plaatsen zodat het makkelijk aan te spreken is, we gaan ons programmaatje sunrise.py noemen:
sudo nano /usr/bin/sunrise.py
Plak de volgende code in de lege file:

#!/usr/bin/env python3

import datetime
from astral import Astral
from crontab import CronTab

lights_on = '/usr/bin/action 63 C off'
lights_off = '/usr/bin/action 63 C on'

city = 'Amsterdam' # Only capital cities and some UK cities are supported
city = Astral()[city] # Make Astral object

now = datetime.datetime.now() # Get current date and time
t_sunrise = city.sunrise(date=now.date(), local=True) # Get sunrise at current date
t_sunset = city.sunset(date=now.date(), local=True) # Get sunset at current date

# Get the crontac for the current user
cron  = CronTab(user=True)

# Remove the previous entries for Sunrise and Sunset
try:
    cron.remove_all(comment='Sunrise')
    cron.remove_all(comment='Sunset')
except:
    pass
sunrise = cron.new(command=lights_off, comment='Sunrise') # Set command to run at Sunrise
sunset = cron.new(command=lights_on, comment='Sunset') # Set command to run at Sunset

sunrise.hour.on(t_sunrise.hour) # Set the Sunrise hour for the current date on the cronjob
sunrise.minute.on(t_sunrise.minute) # Set the Sunrise minute
sunset.hour.on(t_sunset.hour) # Set the Sunset hour
sunset.minute.on(t_sunset.minute) # Set the Sunset minute

cron.write() # Write the crontab

Wat de code precies doet is te lezen in de comments, de opmerkingen achter de hekjes. Let op: Bovenaan het script moet je de commando's die jouw stopcontacten schakelen achter lights_on en lights_off invullen!

Sluit de nano editor:
ctrl-x, y, enter
en maak het script vervolgens "executable":
sudo chmod +x /usr/bin/sunrise.py

Als je nu in de crontab van root kijkt:
sudo crontab -l
Zie je daar nog niets staan, maar als we nu ons eigen script uitvoeren:
sudo sunrise.py
en nog eens kijken in de crontab van root:
sudo crontab -l
dan staat daar netje dat het stopcontacten programma voor aan en uit zoals jij het aan het begin van het script hebt gedefinieerd (in mijn geval "action 63 C on" en "action 63 C off") precies op de tijden van zonsopgang en zonsondergang (ok, voor Amsterdam, voor mij scheelt dat 2 minuten, daar kan ik mee leven) staan ingepland. Als we dit zo zouden laten zouden te tijden nooit meer worden geüpdatet, dus met de hand voeren we nog een regel in, in dezelfde crontab, die er voor zorgt dat elke nacht om 2 uur de crontab wordt geüpdatet met de tijden voor zonsopkomst en zonsondergang voor de aankomende dag. Om dit te kunnen doen moet je begrijpen hoe je dingen in een crontab instelt, zie hier de betekenis van de crontab regels:

*    *    *    *    *  uit te voeren commando
┬    ┬    ┬    ┬    ┬
│    │    │    │    │
│    │    │    │    │
│    │    │    │    └───── dag van de week (0 - 7) (0 of 7 is zondag)
│    │    │    └────────── maand (1 - 12)
│    │    └─────────────── dag van de maand (1 - 31)
│    └──────────────────── uur (0 - 23)
└───────────────────────── minuut (0 - 59)

Om de crontab te kunnen editen met een editor voor normale stervelingen voeren we eerst het volgende commando uit:
export EDITOR=/usr/bin/nano
We openen de crontab van root:
sudo crontab -e
En als bovenste regel voeren we in:
0 2 * * * /usr/bin/sunrise.py # Set Sunrise/Sunset times below
Deze regel zorgt ervoor dat de tijden die eronder staan elke nacht om 2u worden overschreven met de nieuwe tijden voor zonsopkomst en zonsondergang.

Let op, zelf heb ik de fout gemaakt sunrise.py tijdens het testen te draaien als gewone gebruiker (pi) en als root (met sudo), dit zorgt ervoor dat het schakel programma in de crontab van de normale gebruiker terecht komt en in die van root met onverwachte resultaten (en kopzorgen), bijvoorbeeld dat de lamp niet schakelt als twee crontabs (root en pi) hetzelfde commando willen gebruiken op dezelfde tijd. Let dus op dat sunrise.py alleen voorkomt in de crontab van root (in ons geval), dat kun je checken door de output van crontab -l (crontab van de normale gebruiker pi) en sudo crontab -l (de crontab van root) te vergelijken.

Als je ergens tegenaan loopt, laat een comment achter of neem contact op via het contactformulier!

Tip

Als je de RPi opstart met de 434 MHz transmitter aangesloten dan staat deze transmitter constant aan. Je kunt dit merken aan het feit dat je afstandsbediening het ineens erg slecht doet, dat lijkt te komen doordat de zender een hoop ruis uitzend. Dit doet de zender totdat hij een keer wordt gebruikt. Om problemen te voorkomen kun je nog een regel toevoegen aan je crontab, open eerst de editor met de crontab van root:
export EDITOR=/usr/bin/nano
crontab -e
en voeg de volgende regel toe:
@reboot /usr/bin/action 63 B on # Switch a powerplug not in use
In mijn geval stuurt hij dan een signaal naar een van de stopcontacten die ik niet gebruik en stopt de ruis direct.

Bronnen