elektronische Adventskranzkerzen-Steuerung

Die Aufgabe

Nachrüstung von vier elektrischen Kerzen auf einem Adventskranz von ca. 3 Metern Durchmesser für den Rastplatz in Berne - Weserdeich.

Die Funktionen

Basisfunktionen

  • Ansteuerung von vier elektrischen Kerzenlampen (bevorzugt 12V LEDs)
  • Spannungsbereich 5 V, 12 V oder 24 V DC bzw. 230 V AC über Steckernetzteil
  • Unabhänginger Betrieb –> Termingesteuerte Ein-/und Ausschaltung der vier Kerzen je nach Adventswoche
  • Robustheit gegen Verlust der Versorgungsspannung (Netzausfall) bzgl. Uhrzeit und Daten (Betriebssystem und Software)

Zusatzfinktionen

  • WLAN Access Point für Wartung und Servicezwecke
  • Webserver für Darstellung einer Konfigurationsseite mir folgenden Funktonen:
    • Ein- und Ausschalten der einzelnen Kerzen (LEDs)
    • Reset der aktuellen Kerzensteuerung auf den aktuellen Tag
    • Anzeige der aktuellen Systemzeit des R-Pi
    • Setzten von Datum und Uhrzeit des R-Pi
    • Neustart des Systems
Innenansicht, links R-Pi, rechts das Relais-Modul
Innenansicht, Verdrahtung des Relais-Moduls
Beschriftung der LED-Ausgänge
Beschriftung der Spannugsversorgung

Die Technik

Komponente: Quelle Preis
Raspberry Pi B+ z.B. eBay 10 €
USB-WLAN Adapter, EDIMAX, EW-7811UN, Chipsatz RTL8188CUS diverse ~ 6,90 €
Netzteil 12V, 15 Watt Reichelt ~ 8 €
Relaiskarte, Typ: 4-Kanal Channel Relais Relay 5V/230V eBay ~ 7,50 €
Echtzeituhr als RTC-Modul, Typ: DS3231 eBay ~ 4,60 €
Gehäuse Reichelt, Art.-Nr.: BOPLA KS 450 8,35 €
Befestigungsmaterial diverse ~ 5 €
Kabel diverse 2 €
Lampenfassung, 4x ELV ? €
LEDs, 4x ELV ? €
Hohlstecker-Buchsen, 4x für LEDs Reichelt, Art.-Nr.: HEBL 25 2 €
Hohlstecker-Buchse, 1x Netzteil Reichelt, Art.-Nr.: HEBL 21 0,30 €
Sicherungen inkl. Sicherungshalter, nx Reichelt, Art.-Nr.: PL FPG1-40 1,19 €
Aluplatte 100 mm x 160 mm http://www.AluFritze.de 4,92 €
DC/DC Wandler 9-36V/5V 4W für R-Pi eBay 3,50 €

Die Software

  • Raspbian GNU/Linux 8 Jessie Lite, Stand 23.09.2016
  • eigene Shell Scripte
  • eigene PHP Scripte

Die Installation des Raspbian Grundsystems ist in diversen Anleitungen im Netz oder hier beschrieben.

Raspbian

Da ich ein Raspbian Lite verwende, welches an sich schon auf das wesentliche reduziert ist, muss z.B. nur der ungenutzte Bluetooth-Kram entfernt werden. Ein bisschen notwendige Software kann auch gleich nachinstalliert werden.

sudo su
apt-get update
apt-get upgrade
apt-get install mc aptitude i2c-tools
apt-get purge pi-bluetooth
aptitude purge pi-bluetooth

Die Echtzeituhr

Echtzeituhr-Bausteins (RTC) DS3231SN am Raspberry Pi B+ in Betrieb nehmen:

sudo su
raspi-config
  --> Advanced Options
    --> I2C aktivieren
  --> Finish
# reboot
shutdown -r now && exit

Nach dem Neustart wird das I2C Kernelmodul automatisch geladen und steht zur Kommunikation mit der Echtzeituhr zur Verfügung. Damit die benötigten I2C Treiber (Module) beim Systemstart automatisch geladen werden, müssen sie in die Konfigurationsdatei /etc/modules eingetragen werden. Zusätzlich wird noch der Zugriff auf eine (nun vorhandene) Hardware Echtzeituhr ermöglicht (HWCLOCKACCESS=yes) und ein Gerätename (rtc0) für den späteren Zugriff auf die Uhr festgelegt.

sudo su
echo "i2c-dev" >> /etc/modules
echo "rtc-ds1307" >> /etc/modules
echo "i2c-bcm2708" >> /etc/modules
echo "HWCLOCKACCESS=yes" >> /etc/default/hwclock
echo "HCTOSYS_DEVICE=rtc0" >> /etc/default/hwclock

Im Anschluss zeigt ein erster Test, ob die Echtzeituhr am I2C-Bus des Prozessors gefunden wird und ansprechbar ist.

root@raspberrypi2:~# i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --                         
root@raspberrypi2:~# 

Aah!, sehr schön. Die neue Echtzeituhr wird als I2C-Gerät mit der Adresse 0x68 erkannt.
Jetzt muss noch der Kernel über das neue Gerät (ds3231) und die Adresse (0x68) informiert werden unter der es erreichbar ist. Dann kann die Echtzeituhr auch per Kommando hwclock ausgelesen und eingestellt werden.

root@raspberrypi2:~# echo ds3231 0x68 | sudo tee /sys/class/i2c-adapter/i2c-1/new_device
root@raspberrypi2:~# hwclock
Sa 29 Jan 2000 12:21:02 CET  -0.526365 seconds

Super!, die (noch unprogrammierte) Hardware-Uhr ist über die soeben ermittelte I2C Adresse per hwclockansprechbar und liefert eine Zeit und ein Datum zurück.
Kleiner Test, ob die (System-) Uhrzeit des Raspberry Pi aktuell richtig gesetzt ist:

root@raspberrypi2:~# date
Mo 18. Jan 21:05:33 CET 2016

Ja, ist sie, dank vorinstalliertem NTP Dämon ntpd ;-)
Systemzeit in die Echtzeituhr schreiben (-w wie write) und anschließend wieder auslesen (-r wie read):

root@raspberrypi2:~# hwclock -w
root@raspberrypi2:~# hwclock -r
Sa 29 Jan 2000 12:26:07 CET  -0.423200 seconds

Damit bei jedem Start des Raspberry Pi die Uhrzeit von der Echtzeituhr gelesen und als Systemzeit gesetzt wird, müssen folgende Zeilen in der /etc/rc.local oberhalb des exit 0 hinzugefügt werden:

#!/bin/bash
sleep 5
/bin/echo ds3231 0x68 > /sys/class/i2c-adapter/i2c-1/new_device
sleep 2
/sbin/hwclock -s
sleep 2
/var/www/html/kerzeneinschalten.sh
exit 0

Mit der letzten Zeile ./var/www/html/kerzeneinschalten.sh wird beim Systemstart einmalig ein Script zum initialen Einschalten der Adventskranzkerzen ausgeführt.

WLAN Access Point

Da das System im späteren Einsatz keinen (kabelgeführten) Internetanschluss besitzen wird, ein Zugriff z.B. per SSH aber trotzdem möglich sein soll (am besten natürlich drahtlos), wird ein WLAN Access Point eingerichtet. Hier mit einem USB-WLAN Adapter Typ EW-7811UN von EDIMAX.
Die notwendigen Softwareteile sind dann:

  • hostapd - die Access Point Funktionalität an sich
  • dnsmasq - DHCP Server damit der Client automatisch eine IP Adresse bekommt
  • wireless-tools und iw zur Konfiguration des WLAN
  • firmware-realtek - die notwendige Firmware für den USB-WLAN Adapter
sudo apt-get install hostapd dnsmasq firmware-realtek wireless-tools iw

Konfiguration der LAN- und der WLAN-Schnittstelle mit einer statischen IP Adresse und einer Subnetzmaske.

sudo su
vi /etc/network/interfaces
allow-hotplug eth0
iface wlan0 inet static
address 192.168.100.181
netmask 255.255.255.0
 
allow-hotplug wlan0
iface wlan0 inet static
address 192.168.0.1
netmask 255.255.255.0

Damit die Access Point Funktion auch beim Booten automatisch gestartet wird, muss sie unter /etc/default/hostapd aktiviert und der Speicherort der Konfigurationsdatei angegeben werden:

sudo su
vi /etc/default/hostapd
...
DAEMON_CONF="/etc/hostapd/hostapd.conf"
RUN_DAEMON="yes"
...

Über die Konfigurationsdatei /etc/hostapd/hostapd.conf werden dann die wesentlichen Funktionen wie z.B. der Access Point Name (SSID), die Verschlüsselung und natürlich das Password selber eingestellt. Bei WPA2 muss das Passwort mindestens 8 Zeichen lang sein, sonst verweigert hostapd den Dienst.

sudo su
cat <<EOT > /etc/hostapd/hostapd.conf
# Schnittstelle
interface=wlan0
 
# Treiber
driver=nl80211
# WLAN-Konfiguration
ssid=<SSID-DES-ACCESSPOINTS>
channel=5
hw_mode=g
 
# ESSID sichtbar
ignore_broadcast_ssid=0
 
# Verschlüsselung (hier: WPA2)
wpa=2
wpa_key_mgmt=WPA-PSK
rsn_pairwise=CCMP
wpa_passphrase=<PASSWORT>
auth_algs=1
 
# Schlüsselintervalle
wpa_group_rekey=600
wpa_ptk_rekey=600
wpa_gmk_rekey=86400
 
# Ländereinstellungen
country_code=DE
ieee80211d=1
 
# MAC-Authentifizierung (0=aus)
macaddr_acl=0
EOT

Damit jeder Client automatisch eine IP Adresse bekommt, wird in der /etc/dnsmasq.conf der DHCP Adressbereich (hier von 192.168.0.2 bs.10) und eine Gültigkeitsdauer (12h) eingestellt. Der DHCP Server soll dabei nur über die WLAN Schnittstelle IP Adressen verteilen (interface=wlan0), nicht aber über die LAN Schnittstelle (no-dhcp-interface=eth0) - da lauscht der DHCP-Client für den Fall, das der R-Pi an das heimischen Netz angeschlossen wird.

sudo su
vi /etc/dnsmasq.conf
interface=wlan0
dhcp-range=interface:wlan0,192.168.0.2,192.168.0.10,255.255.255.0,12h
no-dhcp-interface=eth0

Mit der Folgenden Zeile wird das Powermanagement des USB-WLAN Adapters deaktiviert. Macht man das nicht kann es u.U. zu Verbindungsabbrüchen kommen.

sudo echo "options 8192cu rtw_power_mgnt=0 rtw_enusbss=0" >> /etc/modprobe.d/8192cu.conf

Den DHCP-Client benötigen wir bei statischer Konfiguration der Netzwerkschnittstellen nicht, daher wird er deaktiviert:

systemctl daemon-reload
service dhcpcd stop
systemctl disable dhcpcd
 
nano /etc/systemd/system/rc-local.service
 
[Unit]
 Description=/etc/rc.local Compatibility
 ConditionPathExists=/etc/rc.local
 
[Service]
 Type=forking
 ExecStart=/etc/rc.local start
 TimeoutSec=0
 StandardOutput=tty
 RemainAfterExit=yes
 SysVStartPriority=99
 
[Install]
 WantedBy=multi-user.target
 
systemctl enable rc-local
systemctl start rc-local.service
systemctl status rc-local.service

WiringPi

Zur Ansteuerung der GPI/O-Pins gibt es ein komfortables Tool namens wiringPi, zu finden unter www.wiringpi.com.

sudo su
apt-get install wiringpi

Web-GUI und Scripte

Zum testen der LEDs des Adventskranzes sollen diese einzelnen per Web-Interface schaltbar sein. Zu diesem Zweck wird ein Webserver benötigt. Der Einfachheit halber habe ich mich für den allseits bekannten Apache2 entschieden. Dieser bringt auch gleich ein PHP-Modul mit welches für die Ausführung diverser anderer Funktionen benötigt wird.

sudo apt-get install apache2 php5

Damit für das Schalten der LEDs auch „Schaltelemente“ in Form sog. „Slider“ oder auch „Schiebeschalter“ zur Verfügung stehen, bediene ich mich der Java Script Funktionen aus dem jQuery Framework.

sudo su
cd /var/www/html/
wget http://code.jquery.com/jquery-1.12.4.min.js
wget http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.js
wget http://dev.jtsage.com/cdn/datebox/1.4.5/jqm-datebox-1.4.5.all.js
wget http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.css

Shell Script zum Schalten der Kerzen

Mit Hilfe dieses Shell Scriptes wird in Abhängigkeit des aktuellen Datums ermittelt, welche Adventskerzen eingeschaltet werden müssen. Das Script ist dazu in folgende Teile bzw. Funktionen unterteilt:

  • function debug()

Hilfsfunktion zur Ausgabe von Debug Meldungen, kann über den Parameter debug beim Start aktiviert werden. Fehlt der Parameter so werden keine Textmeldungen während der Scriptlaufzeit ausgegeben.

  • function random_candles()

Damit nicht jeden Tag im Advent die selbe Kerze (LED) leuchtet wird in dieser Funktion eine zufällige Reihenfolge festgelegt. Es werden immer alle vier Kerzen zufällig verteilt und dabei nicht unterschieden, welche Adventswoche gerade ist.

  • function switch_gpio ()

Hier wird der jeweilige GPI/O Pin des Prozessor respektive das daran angeschlossene Relais ein oder aus geschaltet.

  • function preset_candles ()

Um einen definierten Startzustand zu erhalten werden alle GPI/Os (Relais) zu Beginn in den AUS-Zustand geschaltet.

  • function get_advent_days ()

Die Berechnung der Adventssonntage erfolg in Abhängigkeit des jeweiligen Kalenderjahres jeweils beim Start des Scriptes. Berechnete Daten werden nicht abgespeichert.

  • function print_advent_days ()

Hilfsfunktion zur textuellen Ausgabe der berechneten Adventssonntage.

  • function switch_candles ()

In Abhängigkeit der berechneten Adventssonntage wird in dieser Funktion die jeweilige Anzahl an Kerzen geschaltet.

kerzeneinschalten.sh
#!/bin/bash
#
#
## Debugging parameters:
#TODAY="$1"
##TODAY="20161204"
#CURRENT_YEAR="2017"
 
# normal parameters:
DATEFORMAT="%Y%m%d"
TODAY=`date +$DATEFORMAT`
CURRENT_YEAR=`date +%Y`
CHRISTMAS="${CURRENT_YEAR}1224"
TREE_KINGS="${CURRENT_YEAR}0106"
 
# Zuordnung Adventskerze <-> GPIO Pin:
CANDLE_ADDRESS[0]="17"
CANDLE_ADDRESS[1]="18"
CANDLE_ADDRESS[2]="27"
CANDLE_ADDRESS[3]="22"
 
# Zufallszahl zuruecksetzten
rand=""
 
# Verwendete Kerzen zuruesetzten
CANDLE_TO_USE[0]=""
CANDLE_TO_USE[1]=""
CANDLE_TO_USE[2]=""
CANDLE_TO_USE[3]=""
 
# Debugging ja/nein
DEBUG=""
 
function debug()
{
MESSAGE=$1
echo "$MESSAGE"
}
 
 
function random_candles()
{
if [ -n "$DEBUG" ]; then debug "Entering randomization of candle usage:"; fi
COUNTER=0
while [ $COUNTER -lt 4 ]; do
  rand=`echo $(($RANDOM % 4))`
       if [ "${CANDLE_TO_USE[$rand]}" = ""  ]; then
         CANDLE_TO_USE[$rand]=$COUNTER
         if [ -n "$DEBUG" ]; then debug "$COUNTER. Candle to use: ${CANDLE_ADDRESS[$rand]} "; fi
         COUNTER=$((COUNTER + 1))
       fi
done
}
 
function switch_gpio ()
{
i=$1
case $2 in
  on)
   state=0
  ;;
  off)
   state=1
  ;;
  *)
esac
 
if [ -n "$DEBUG" ]; then debug "Switch candle ${CANDLE_ADDRESS[$i]} $state"; fi
   gpio -g mode ${CANDLE_ADDRESS[$i]} out
   sleep .1
   gpio -g write ${CANDLE_ADDRESS[$i]} $state
   sleep .1
}
 
function preset_candles ()
{
if [ -n "$DEBUG" ]; then debug "Initial state: all candles off!"; fi
for i in $(seq 0 3);
do
  switch_gpio $i off
done
}
 
function get_advent_days ()
{
X=`date -d "$CURRENT_YEAR-12-24 - 3 weeks" +%w`
ADVENT[0]=`date -d "$CURRENT_YEAR-12-24 - 3 weeks -$X day" +$DATEFORMAT`
 
X=`date -d "$CURRENT_YEAR-12-24 - 2 weeks" +%w`
ADVENT[1]=`date -d "$CURRENT_YEAR-12-24 - 2 weeks -$X day" +$DATEFORMAT`
 
X=`date -d "$CURRENT_YEAR-12-24 - 1 weeks" +%w`
ADVENT[2]=`date -d "$CURRENT_YEAR-12-24 - 1 weeks -$X day" +$DATEFORMAT`
 
X=`date -d "$CURRENT_YEAR-12-24 - 0 weeks" +%w`
ADVENT[3]=`date -d "$CURRENT_YEAR-12-24 - 0 weeks -$X day" +$DATEFORMAT`
}
 
function print_advent_days ()
{
if [ -n "$DEBUG" ]; then debug "1. Advent in $CURRENT_YEAR ist der: ${ADVENT[0]}"; fi
if [ -n "$DEBUG" ]; then debug "2. Advent in $CURRENT_YEAR ist der: ${ADVENT[1]}"; fi
if [ -n "$DEBUG" ]; then debug "3. Advent in $CURRENT_YEAR ist der: ${ADVENT[2]}"; fi
if [ -n "$DEBUG" ]; then debug "4. Advent in $CURRENT_YEAR ist der: ${ADVENT[3]}"; fi
}
 
function switch_candles ()
{
 
if [ $TODAY -le $TREE_KINGS ] ; then
  if [ -n "$DEBUG" ]; then debug "Weihnachten ist vorbei aber die Heiligen drei Koenige sind auch noch nicht..."; fi
  if [ -n "$DEBUG" ]; then debug "Trotzdem alle Kerzen an! ;-)"; fi
    for i in $(seq 0 3);
    do
      switch_gpio ${CANDLE_TO_USE[$i]} on
    done
 
elif [ $TODAY -lt ${ADVENT[0]} ] ; then
  if [ -n "$DEBUG" ]; then debug "noch keine Adventszeit :-("; fi
elif [ $TODAY -ge ${ADVENT[0]}  ] && [ $TODAY -lt ${ADVENT[1]} ] ; then
  if [ -n "$DEBUG" ]; then debug "erste Adventswoche :-)"; fi
  for i in $(seq 0 0);
    do
      switch_gpio ${CANDLE_TO_USE[$i]} on
  done
elif [ $TODAY -ge ${ADVENT[1]} ] && [ $TODAY -lt ${ADVENT[2]} ] ; then
  if [ -n "$DEBUG" ]; then debug "zweite Adventswoche :-)"; fi
  for i in $(seq 0 1);
    do
      switch_gpio ${CANDLE_TO_USE[$i]} on
    done
elif [ $TODAY -ge ${ADVENT[2]} ] && [ $TODAY -lt ${ADVENT[3]} ] ; then
  if [ -n "$DEBUG" ]; then debug "dritte Adventswoche :-)"; fi
  for i in $(seq 0 2);
    do
      switch_gpio ${CANDLE_TO_USE[$i]} on
    done
elif [ $TODAY -ge ${ADVENT[3]} ] && [ $TODAY -le $CHRISTMAS ] ; then
  if [ -n "$DEBUG" ]; then debug "vierte Adventswoche :-)"; fi
  for i in $(seq 0 3);
    do
      switch_gpio ${CANDLE_TO_USE[$i]} on
    done
elif [ $TODAY -gt $CHRISTMAS ] ; then
  if [ -n "$DEBUG" ]; then debug "Weihnachten ist vorbei :-("; fi
  if [ -n "$DEBUG" ]; then debug "Trotzdem alle Kerzen an! ;-)"; fi
    for i in $(seq 0 3);
    do
      switch_gpio ${CANDLE_TO_USE[$i]} on
    done
fi
}
 
###### Main
#
# Check, if debugging is enabled:
if [ "$1" = "debug" ]; then
  DEBUG="true"
fi
 
if [ -n "$DEBUG" ]; then debug "Today: $TODAY"; fi
if [ -n "$DEBUG" ]; then debug "Year: $CURRENT_YEAR"; fi
if [ -n "$DEBUG" ]; then debug "Three Kings day: $TREE_KINGS"; fi
if [ -n "$DEBUG" ]; then debug "Christmas: $CHRISTMAS"; fi
 
#if [ $TODAY -lt ${ADVENT[0]} ] ; then
 
  preset_candles
  get_advent_days
  print_advent_days
  random_candles
  switch_candles
#echo "Zufallszahl: $rand"

Damit das Shell Script vom Webserver gestartet werden kann muss es ausführbar gemacht werden.

sudo touch /var/www/html/kerzeneinschalten.sh && chmod +x /var/www/html/kerzeneinschalten.sh

Aktuell wird das Script kerzeneinschalten.sh nur einmalig beim Systemstart ausgeführt. Läuft der Raspberry jedoch über den Tageswechsel oder sogar über den Wechsel Sa./So., muss also täglich um 00:00 Uhr geprüft werden, ob zusätzliche Lichter am Adventskranz einzuschalten sind. Folgender Eintrag in der Datei /etc/crontab erstellt einen sog. CRON-Job. Dieser startet stets um 00:00 Uhr das Script kerzeneinschalten.sh und schaltet somit die richte Anzahl LEDs ein.

sudo su
nano /etc/crontab
0 0   * * *   www-data  /var/www/html/kerzeneinschalten.sh

Die HTML-Seite

Der Speicherort für die Webseite sowie alle PHP-Dateien und das Kerzen-Schalt-Script /ist var/www/html/. Mit Hilfe der folgenden HTML-Seite können die vier Kerzen jeweils einzeln ein und wieder aus geschaltet werden. Auch das Setzen von Datum und Uhrzeit des R-Pi ist darüber möglich.

index.html
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<script type='text/javascript' src='jquery-1.12.4.min.js'></script>
<script type='text/javascript' src='jquery.mobile-1.4.5.js'></script>
<script type='text/javascript' src='jqm-datebox-1.4.5.all.js'></script>
<link href="jquery.mobile-1.4.5.css" rel="stylesheet" />
 
<script type='text/javascript' src='GPIOson.js'></script>
 
<script>
  $(document).ready(function() {
    $("#settimedate").click(function(){
      $.post("settimedate.php",
      { time: $("#notifTime").val(),
        date: $("#notifDate").val()},
        function(data, status){
        window.location.reload(true)
        });
    });
  });
</script>
 
<script>
  $(document).ready(function() {
    $("#resetcandles").click(function(){
      $.post("resetcandles.php",
      {},
        function(){
        window.location.reload(true)
        });
    });
  });
</script>
 
<script>
  $(document).ready(function() {
    $("#reboot").click(function(){
      $.post("reboot.php",
      {},
        function(){
        window.location.reload(true)
        });
    });
  });
</script>
 
<script>
function displaytime(){
 $.ajax({
    url: "gettimedate.php",
    type: "POST",
    data: "",
    success: function(response) {
      var json = response;
      var obj = JSON.parse(json);
      document.getElementById("serverdatetime").innerHTML= obj.time + " - " + obj.date;
    }
 });
}
</script>
 
<script>
window.onload=function(){
setInterval("displaytime()", 1000);
};
</script>
 
<style type="text/css">
    .ui-header .ui-title {margin: 0 10%}
</style>
 
 
</head>
 
<body>
<div data-role="page" id="Kerzensteuerung">
  <div data-role="header">
   <h2 >Adventskranzsteuerung</h2>
    <div data-role="navbar">
      <ul>
        <li><a href="#timedate">Datum / Uhrzeit</a></li>
        <li><a href="#about">Über...</a></li>
      </ul>
    </div>
  </div>
 
<!--  <div data-role="main" class="ui-content"> -->
  <div data-role="main">
<!--<fieldset> -->
<!--<div data-role="fieldcontain"> -->
<label style="display:inline" for="checkbox-based-flipswitch">1. Kerze (GPIO 17):  </label>
<input type="checkbox" id="GPIO17" data-role="flipswitch" onchange="switchValue(17)">
<!--</div> -->
<!--</fieldset> -->
 
<hr>
 
<!--<fieldset>-->
<!--<div data-role="fieldcontain">-->
<label style="display:inline" for="checkbox-based-flipswitch">2. Kerze (GPIO 18):</label>
<input type="checkbox" id="GPIO18" data-role="flipswitch" onchange="switchValue(18)" >
<!--</div>-->
<!--</fieldset>-->
 
<hr>
 
<!--<fieldset> -->
<!--<div data-role="fieldcontain"> -->
<label style="display:inline" for="checkbox-based-flipswitch">3. Kerze (GPIO 27):</label>
<input type="checkbox" id="GPIO27" data-role="flipswitch" onchange="switchValue(27)" >
<!--</div> -->
<!--</fieldset> -->
 
<hr>
 
<!--<fieldset> -->
<!--<div data-role="fieldcontain"> -->
<label style="display:inline" for="checkbox-based-flipswitch">4. Kerze (GPIO 22):</label>
<input type="checkbox" id="GPIO22" data-role="flipswitch" onchange="switchValue(22)" >
<!--</div> -->
<!--</fieldset> -->
 
<hr>
 
<!--<fieldset> -->
<!--<div data-role="fieldcontain"> -->
<button id="resetcandles">Reset Kerzen</button>
<!--</div> -->
<!--</fieldset> -->
 
<hr>
 
<!--<fieldset> -->
<!--<div data-role="fieldcontain"> -->
<button id="reboot">Reboot System</button>
<!--</div> -->
<!--</fieldset> -->
 
<hr>
 
  </div>
 
  <div data-role="footer">
    <h2>made by ChrvTh</h2>
  </div>
</div> 
 
<div data-role="page" id="timedate">
  <div data-role="header">
    <h2>Systemzeit- und Datum einstellen:</h2>
  </div>
  <div data-role="navbar">
      <ul>
        <li><a href="#Kerzensteuerung">Zurück</a></li>
      </ul>
  </div>
  <div data-role="main">
    <br>
    <b>Systemzeit / Datum:</b> <p style="display:inline" id="serverdatetime"> </p>
 
    <div data-role="content">
 
<!--    <div class="ui-field-contain"> -->
      <label for="notifTime">Systemzeit einstellen:</label>
      <input name="notifTime" id="notifTime" type="text" data-role="datebox" data-options='{"mode":"timebox", "useClearButton":true, "useLang":"de", "useNewStyle":true, "overrideTimeFormat": 24, "themeButton": "b", "themeInput": "a", "theme": "b", "themeHeader": "b"}' />
<!--    </div> -->
<!--    <div class="ui-field-contain"> -->
     <label for="notifDate">Systemdatum einstellen:</label>
     <input name="notifDate" id="notifDate" type="text" data-role="datebox" data-options='{"mode":"datebox", "useClearButton":true, "overrideDateFormat":"%d.%m.%Y"   ,  "useNewStyle":true,  "themeButton": "b", "themeInput": "a", "theme": "b", "themeHeader": "b"}' />
<!--    </div> -->
<!--    <form> -->
     <button id="settimedate">Uhrzeit und Datum übernehmen</button>
<!--    </form> -->
    </div>
 
  </div>
</div>
 
<div data-role="page" id="about">
  <div data-role="header">
    <h2>Über diese Seite ...</h2>
  </div>
    <div data-role="navbar">
      <ul>
        <li><a href="#Kerzensteuerung">Zurück</a></li>
      </ul>
    </div>
  <div data-role="main"> <!-- class="ui-content"> -->
    <p>Webseite zur Steuerung eines Adventskranzes mit vier elektrischen Kerzen.<br>
       <br>
       Entwickelt von:<br>
       Christoph von Thülen<br>
       Einumerstr. 15<br>
       31135 Hildesheim<br> 
       E-Mail:<a href="mailto:Christoph@von-Thuelen.de">Christoph@von-Thuelen.de </a>
    </p>
  </div>
 
</div>
 
</body>
</html>

/var/www/html/settimedate.php

settimedate.php
<?php
$result='';
if(count($_POST) > 0){
 
$date = $_POST['date'];
$time = $_POST['time'];
 
if($date == '') {$date = date("d.m.Y");}
if($time == '') {$time = date("H:i");}
 
$hour = '';
$minute = '';
$day = '';
$month = '';
$year = '';
 
$hour = substr($time, 0, strpos($time, ':'));
$minute = substr($time, (strpos($time, ':') + "1" ), strlen($time));
 
$day = substr($date, 0, strpos($date, '.'));
$date = substr($date, (strpos($date, '.') + "1" ), strlen($date));
$month = substr($date, 0, strpos($date, '.'));
$year = substr($date, (strpos($date, '.') + "1" ), strlen($date));
 
/*
exec('/bin/echo ' . '"Neue Stunde: ' . $hour . '"' . ' >> /var/tmp/debug.log');
exec('/bin/echo ' . '"Neue Minuten: ' . $minute . '"' . ' >> /var/tmp/debug.log');
exec('/bin/echo ' . '"Neuer Tag: ' . $day . '"' . ' >> /var/tmp/debug.log');
exec('/bin/echo ' . '"Neuer Monat: ' . $month . '"' . ' >> /var/tmp/debug.log');
exec('/bin/echo ' . '"Neues Jahr: ' . $year . '"' . ' >> /var/tmp/debug.log');
*/
//exec('/bin/echo ' . '"Neue Uhrzeit: ' . $_POST['time'] . '"' . ' >> /var/tmp/debug.log');
//exec('/bin/echo ' . '"Neues Datum: ' . $_POST['date'] . '"' . ' >> /var/tmp/debug.log');
 
//exec('sudo /bin/echo ' . '"date ' . $month . $day . $hour . $minute . $year . '"' . '>> /var/tmp/debug.log');
exec('sudo /bin/date ' . $month . $day . $hour . $minute . $year);
exec('sudo /sbin/hwclock -w');
exec('sudo /var/www/html/kerzeneinschalten.sh');
 
$result = 'Neue Uhrzeit: ' . $_POST['time'] . ';' . 'Neues Datum: ' . $_POST['date'];
}
echo json_encode($result);
?>

/var/www/html/gettimedate.php

gettimedate.php
<?php
$date = date("d.m.Y");
$time = date("H:i:s");
$result = array("date" => $date, "time" => $time);
echo json_encode($result);
?>

/var/www/html/resetcandles.php

resetcandles.php
<?php
exec('sudo /var/www/html/kerzeneinschalten.sh');
echo json_encode();
?>

/var/www/html/reboot.php

reboot.php
<?php
exec('sudo shutdown -r now');
echo json_encode();
?>

/var/www/html/GPIOson.js

GPIOson.js
var g_GpioPins = [
{
gpio: '17', mode: 'out', value: 1
},
{
gpio: '18', mode: 'out', value: 1
},
{
gpio: '27', mode: 'out', value: 1
},
{
gpio: '22', mode: 'out', value: 1
},
{
gpio: '24', mode: 'in', value: 0
}
];
 
var g_RefreshTimer = null;
 
function debug(debug_data) {
  $.ajax({
    url: 'debug.php',
    type: 'post',
    datatype: 'json',
    data: debug_data,
    success: function(result) {
      // Do something with data that came back.
      var objData = jQuery.parseJSON(result);
      $('#UpdateResult').html(objData.status);
    }
  });
}
 
function getSetPin(pinData) {
  $.ajax({
    url: 'gpio.php',
    type: 'post',
    datatype: 'json',
    data: pinData,
    success: function(result) {
      // Do something with data that came back.
      var objData = jQuery.parseJSON(result);
      $('#UpdateResult').html(objData.status);
    }
  });
}
 
function switchValue(gpio) {
  for (var i_Pin in g_GpioPins) {
    if (g_GpioPins[i_Pin].gpio == gpio) {
      switch (g_GpioPins[i_Pin].mode) {
      case 'out':
        switch (g_GpioPins[i_Pin].value) {
          case 0:
            g_GpioPins[i_Pin].value = 1;
          break;
          case 1:
            g_GpioPins[i_Pin].value = 0;
          break;
        }
      break;
      case 'in':
        console.log('auslesen' + g_GpioPins[i_Pin].gpio);
      break;
      }
      getSetPin(g_GpioPins[i_Pin]);
      break;
    }
  }
  debug(gpio);
}
 
function autoRefresh() {
  //console.log($('#AutoRefresh').val());
  if ($('#AutoRefresh').val() == 'On') {
    autoRefreshStart();
  }
  else {
    autoRefreshStop();
  }
}
 
function autoRefreshStop() {
  //console.log('Auto OFF!');
  clearInterval(g_RefreshTimer);
  g_RefreshTimer = null;
}
 
function autoRefreshStart() {
  //console.log('Auto On!');
  g_RefreshTimer = setInterval('getSetPin(g_GpioPins[1])', 100);
  getSetPin(g_GpioPins[1]);
}

/var/www/html/gpio.php

gpio.php
<?php
if(count($_POST) > 0){
  $result=array();
  switch ($_POST['mode']){
   case 'out':
     exec('/usr/local/bin/gpio -g ' . 'mode ' . $_POST['gpio'] . ' out');
     exec('/usr/local/bin/gpio -g ' . 'write ' . $_POST['gpio'] . ' ' . $_POST['value'],$gpioValue);
     //$result ='Success: Pin ' . $_POST['gpio'];
     $result['value'] = ($gpioValue);
   break;
   case 'in':
     exec('/usr/local/bin/gpio -g ' . 'mode ' . $_POST['gpio'] . ' in');
     exec('/usr/local/bin/gpio -g ' . 'read ' . $_POST['gpio'],$gpioValue);
     //$result['value'] = ($gpioValue[0]);
     $result=array(status => $gpioValue[0], gpio=>$_POST['gpio']);
   break;
   default:
     $result='Error:wrong mode';
  }
}
else{
  $result='Error:';
}
echo json_encode($result);
?>
sudo su
ln -s /usr/bin/gpio /usr/local/bin/gpio
cd /var/www/html/
chown -R root:www-data *
sudo su
cd /
echo "www-data ALL=(ALL) NOPASSWD: /bin/date" >> /etc/sudoers
echo "www-data ALL=(ALL) NOPASSWD: /bin/echo" >> /etc/sudoers
echo "www-data ALL=(ALL) NOPASSWD: /sbin/hwclock" >> /etc/sudoers
echo "www-data ALL=(ALL) NOPASSWD: /sbin/shutdown" >> /etc/sudoers
echo "www-data ALL=(ALL) NOPASSWD: /usr/bin/gpio" >> /etc/sudoers
echo "www-data ALL=(ALL) NOPASSWD: /var/www/html/kerzeneinschalten.sh" >> /etc/sudoers

R-Pi absichern (bei Stromausfall)

sudo su
apt-get remove --purge wolfram-engine triggerhappy logrotate dphys-swapfile fake-hwclock
apt-get autoremove --purge
apt-get install busybox-syslogd
dpkg --purge rsyslog
# !ACHTUNG!: Syslog ab jetzt nur noch per "logread -f" lesbar
sudo su
cat /boot/cmdline.txt
dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait
vi /boot/cmdline.txt
dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait fastboot noswap ro
sudo su
rm -rf /var/lib/dhcp/ /var/run /var/spool /var/lock /var/lib/misc/ /var/lib/ntp
ln -s /tmp /var/lib/dhcp; ln -s /tmp /var/run; ln -s /tmp /var/spool; ln -s /tmp /var/lock; ln -s /tmp /var/lib/misc; ln -s /tmp /var/lib/ntp
sudo su
rm /var/lib/systemd/random-seed
ln -s /tmp/random-seed /var/lib/systemd/random-seed
nano /lib/systemd/system/systemd-random-seed.service
# add before "ExecStart=/lib/systemd/systemd-random-seed load"
ExecStartPre=/bin/echo "" >/tmp/random-seed
# reload services:
systemctl daemon-reload
sudo su
nano /etc/ntp.conf
# change "driftfile /var/lib/ntp/ntp.drift" to "driftfile /var/tmp/ntp.drift"
sudo su
insserv -r bootlogs
insserv -r console-setup
sudo su
# change ''/etc/fstab'' from:
proc            /proc           proc    defaults          0       0
/dev/mmcblk0p1  /boot           vfat    defaults          0       2
/dev/mmcblk0p2  /               ext4    defaults,noatime  0       1
# to:
proc            /proc           proc    defaults             0       0
/dev/mmcblk0p1  /boot           vfat    defaults,ro          0       2
/dev/mmcblk0p2  /               ext4    defaults,noatime,ro  0       1
 
# For Debian Jessie
tmpfs           /tmp            tmpfs   nosuid,nodev         0       0
tmpfs           /var/log        tmpfs   nosuid,nodev         0       0
tmpfs           /var/tmp        tmpfs   nosuid,nodev         0       0
sudo su
nano /root/.bashrc
######
add below:
######
# set variable identifying the filesystem you work in (used in the prompt below)
fs_mode=$(mount | sed -n -e "s/^.* on \/ .*(\(r[w|o]\).*/\1/p")
# alias ro/rw
alias ro='mount -o remount,ro / ; fs_mode=$(mount | sed -n -e "s/^.* on \/ .*(\(r[w|o]\).*/\1/p")'
alias rw='mount -o remount,rw / ; fs_mode=$(mount | sed -n -e "s/^.* on \/ .*(\(r[w|o]\).*/\1/p")'
# setup fancy prompt
export PS1='\[\033[01;32m\]\u@\h${fs_mode:+($fs_mode)}\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
# aliases for mounting boot volume
alias roboot='mount -o remount,ro /boot'
alias rwboot='mount -o remount,rw /boot'
 
finish() {
#echo "exec on exit"
mount -o remount,rw /
history -a
hwclock -w
mount -o remount,ro /
mount -o remount,ro /boot
}
 
trap finish EXIT
######
sudo su
touch /etc/bash.bash_logout
nano /etc/bash.bash_logout
# add:
mount -o remount,rw /
history -a
mount -o remount,ro /
mount -o remount,ro /boot
sudo su
nano /etc/apache2/envvars
# add below "export APACHE_LOG_DIR=/var/log/apache2$SUFFIX"
mkdir -p /var/log/apache2

Informationsquellen

GPI/Os ansteuern

Webseite, PHP, Java Script und JQuery

Date und Co.

Access Point

Absichern gegen Stromausfall

alter Kram - nicht mehr verwendet!

#NTP Dienst abstellen und deinstallieren, alternativ ''ntpdate'' installieren um per Netzwerk/Internet die Systemzeit aktualisieren zu können.:
#root@raspberrypi2:~# update-rc.d ntp disable
#root@raspberrypi2:~# update-rc.d fake-hwclock disable
#apt-get remove fake-hwclock
#rm /etc/cron.hourly/fake-hwclock
#rm /etc/init.d/fake-hwclock
#apt-get install ntpdate
#update-rc.d hwclock.sh enable

Test:

root@raspberrypi2:~# date -s "Jan 01 2016 12:00:00"
root@raspberrypi2:~# date
root@raspberrypi2:~# hwclock -w
root@raspberrypi2:~# hwclock -r
root@raspberrypi2:~# reboot
root@raspberrypi2:~# hwclock -r

Manuelles Synchronisieren der Systemzeit:

#root@raspberrypi2:~# ntpdate ptbtime1.ptb.de

QR-Code
QR-Code elektronische Adventskranzkerzen-Steuerung (erstellt für aktuelle Seite)