diff --git a/.gitignore b/.gitignore index 9bea433..d974273 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,7 @@ .DS_Store +_Bugs +_SVGs +_climacons-master +_112082-weather-linear +cron_kindle-wetter_preprocess_defs.txt diff --git a/Kindle/180405/weatherdata-bad.png b/Kindle/180405/weatherdata-bad.png new file mode 100644 index 0000000..ac2d5e0 Binary files /dev/null and b/Kindle/180405/weatherdata-bad.png differ diff --git a/Kindle/180405/weatherdata-wohnzimmer.png b/Kindle/180405/weatherdata-wohnzimmer.png new file mode 100644 index 0000000..7fe37bf Binary files /dev/null and b/Kindle/180405/weatherdata-wohnzimmer.png differ diff --git a/Kindle/weatherbattery.png b/Kindle/weatherbattery.png index 646ba74..e70d702 100644 Binary files a/Kindle/weatherbattery.png and b/Kindle/weatherbattery.png differ diff --git a/Kindle/weatherdata-bad.png b/Kindle/weatherdata-bad.png index ac2d5e0..f63ca3b 100644 Binary files a/Kindle/weatherdata-bad.png and b/Kindle/weatherdata-bad.png differ diff --git a/Kindle/weatherdata-wohnzimmer.png b/Kindle/weatherdata-wohnzimmer.png index 7fe37bf..7dfc331 100644 Binary files a/Kindle/weatherdata-wohnzimmer.png and b/Kindle/weatherdata-wohnzimmer.png differ diff --git a/Kindle/weatherdata.png b/Kindle/weatherdata.png index f3775f6..10653b2 100755 Binary files a/Kindle/weatherdata.png and b/Kindle/weatherdata.png differ diff --git a/Kindle/weathererror.png b/Kindle/weathererror.png index dda8560..b2d079f 100644 Binary files a/Kindle/weathererror.png and b/Kindle/weathererror.png differ diff --git a/Kindle/weathererror_image.png b/Kindle/weathererror_image.png new file mode 100644 index 0000000..b2d079f Binary files /dev/null and b/Kindle/weathererror_image.png differ diff --git a/Kindle/weathererror_network.png b/Kindle/weathererror_network.png new file mode 100644 index 0000000..014099b Binary files /dev/null and b/Kindle/weathererror_network.png differ diff --git a/Kindle/weathererror_wlan.png b/Kindle/weathererror_wlan.png new file mode 100644 index 0000000..6ebee29 Binary files /dev/null and b/Kindle/weathererror_wlan.png differ diff --git a/Kindle/weatherscript.sh b/Kindle/weatherscript.sh index a045f65..8e4976e 100644 --- a/Kindle/weatherscript.sh +++ b/Kindle/weatherscript.sh @@ -5,7 +5,7 @@ ####################################################### ########### -### Install +### Install ## mkdir /mnt/us/scripts ## chmod 700 /mnt/us/scripts/weatherscript.sh ## mntroot rw @@ -15,39 +15,41 @@ # Variables NAME=weatherscript SCRIPTDIR="/mnt/us/scripts" -LOG="$SCRIPTDIR/$NAME.log" +LOG="${SCRIPTDIR}/${NAME}.log" SUSPENDFOR=900 # Default, flexibel by F5INTWORKDAY and F5INTWEEKEND NET="wlan0" -LIMG="$SCRIPTDIR/weatherdata.png" -LIMGERR="$SCRIPTDIR/weathererror.png" -LIMGBATT="$SCRIPTDIR/weatherbattery.png" +LIMG="${SCRIPTDIR}/weatherdata.png" +LIMGBATT="${SCRIPTDIR}/weatherbattery.png" +LIMGERR="${SCRIPTDIR}/weathererror_image.png" +LIMGERRWLAN="${SCRIPTDIR}/weathererror_wlan.png" +LIMGERRNET="${SCRIPTDIR}/weathererror_network.png" RSRV="192.168.1.10" -RIMG="$RSRV/kindle-weather/weatherdata.png" -RSH="$RSRV/kindle-weather/$NAME.sh" +RIMG="${RSRV}/kindle-weather/weatherdata.png" +RSH="${RSRV}/kindle-weather/${NAME}.sh" +RPATH="/var/www/html/kindle-weather" ROUTERIP="192.168.1.1" # Workaround, forget default gateway after STR -#ROUTERIP="192.168.254.254" # Workaround, forget default gateway after STR - + F5INTWORKDAY="\ -06,07,08,15,16,17,18,19|900 +06,07,08,15,16,17,18,19|900 05,09,10,11,12,13,14,20,21|1800 22,23,00,01,02,03,04|3600" # Refreshintervall for workdays = 57 Refreshes per workday - + F5INTWEEKEND="\ -06,07,08,15,16,17,18,19|900 +06,07,08,15,16,17,18,19|900 05,09,10,11,12,13,14,20,21|1800 22,23,00,01,02,03,04|3600" # Refreshintervall for weekends = 57 Refreshes per weekend day SMSACTIV=1 PLAYSMSUSER="admin" -PLAYSMSPW="abcdef0123456789abcdef0123456789" -PLAYSMSURL="https://192.168.1.10/playsms/index.php" +PLAYSMSPW="00998877665544332211ffeeddccbbaa" +PLAYSMSURL="http://192.168.1.10/playsms/index.php" CONTACTPAGERS="\ -0049171XXXXXXX|Nico -0049151XXXXXXXX|Michele" +0049123456789|Nico +0049987654321|Michele" ############## @@ -71,14 +73,14 @@ wait_wlan() { } send_sms () { - for LINE in $CONTACTPAGERS; do - CONTACTPAGER=`echo $LINE | awk -F\| '{print $1}'` - CONTACTPAGERNAME=`echo $LINE | awk -F\| '{print $2}'` + for LINE in ${CONTACTPAGERS}; do + CONTACTPAGER=`echo ${LINE} | awk -F\| '{print $1}'` + CONTACTPAGERNAME=`echo ${LINE} | awk -F\| '{print $2}'` SMSTEST=`echo ${MESSAGE} | sed 's/ /%20/g'` - #curl -s "${SMSURL_START}&text=${SMSTEST}&${SMSURL_END}&to=${CONTACTPAGER}" > /dev/null - curl -s -k "${PLAYSMSURL}?app=ws&u=${PLAYSMSUSER}&h=${PLAYSMSPW}&op=pv&to=${CONTACTPAGER}&msg=${SMSTEST}" > /dev/null - echo "`date '+%Y-%m-%d_%H:%M:%S'` | SMS an ${CONTACTPAGERNAME} versendet!" + #curl --silent --insecure "${PLAYSMSURL}?app=ws&u=${PLAYSMSUSER}&h=${PLAYSMSPW}&op=pv&to=${CONTACTPAGER}&msg=${SMSTEST}" > /dev/null + curl --silent "${PLAYSMSURL}?app=ws&u=${PLAYSMSUSER}&h=${PLAYSMSPW}&op=pv&to=${CONTACTPAGER}&msg=${SMSTEST}" > /dev/null + echo "`date '+%Y-%m-%d_%H:%M:%S'` | ${HOSTNAME} | SMS an ${CONTACTPAGERNAME} versendet!" >> ${LOG} 2>&1 done } @@ -90,6 +92,12 @@ send_sms () { NOTIFYBATTERY=0 REFRESHCOUNTER=0 +IP=`ifconfig ${NET} | grep "inet addr" | cut -d':' -f2 | awk '{print $1}'` +HOSTNAME=`nslookup ${IP} | grep Address | grep ${IP} | awk '{print $4}' | awk -F. '{print $1}'` +if [ -z "${HOSTNAME}" ]; then + HOSTNAME="recently-reboot" +fi + ### Kill Kindle processes kill_kindle @@ -97,144 +105,177 @@ kill_kindle while true; do ### Start - echo "================================================" >> $LOG 2>&1 - - ### Check Batterystate - CHECKBATTERY=`gasgauge-info -s` - echo "`date '+%Y-%m-%d_%H:%M:%S'` | Batteriezustand: $CHECKBATTERY%" >> $LOG 2>&1 - if [ ${CHECKBATTERY} -le 5 ] && [ ${NOTIFYBATTERY} -eq 0 ]; then - NOTIFYBATTERY=1 - if [ ${SMSACTIV} -eq 1 ]; then - echo "`date '+%Y-%m-%d_%H:%M:%S'` | Batteriezustand kritisch, SMS werden verschickt!" >> $LOG 2>&1 - MESSAGE="Der Batteriezustand von $HOSTNAME ist kritisch ($CHECKBATTERY) - bitte laden!" - send_sms - else - echo "`date '+%Y-%m-%d_%H:%M:%S'` | Batteriezustand kritisch" >> $LOG 2>&1 - fi - fi - if [ ${CHECKBATTERY} -gt 80 ]; then - NOTIFYBATTERY=0 - fi - if [ ${CHECKBATTERY} -eq 1 ]; then - eips -f -g "$LIMGBATT" - echo "mem" > /sys/power/state - fi + echo "================================================" >> ${LOG} 2>&1 ### Enable CPU Powersave - CHECKCPUMODE=`cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor | grep -i "powersave"` + CHECKCPUMODE=`cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor | grep -i "powersave"` if [ ${CHECKCPUMODE} -eq 0 ]; then echo powersave > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor - echo "`date '+%Y-%m-%d_%H:%M:%S'` | CPU runtergetaktet" >> $LOG 2>&1 - fi + echo "`date '+%Y-%m-%d_%H:%M:%S'` | ${HOSTNAME} | CPU runtergetaktet." >> ${LOG} 2>&1 + fi - ### Disable Screensaver, no energysaving by powerd + ### Disable Screensaver, no energysaving by powerd # powerd buggy since 5.4.5 - https://www.mobileread.com/forums/showthread.php?t=235821 CHECKSAVER=`lipc-get-prop com.lab126.powerd status | grep -i "prevent_screen_saver:0"` if [ ${CHECKSAVER} -eq 0 ]; then - lipc-set-prop com.lab126.powerd preventScreenSaver 1 >> $LOG 2>&1 - echo "`date '+%Y-%m-%d_%H:%M:%S'` | Standard Energiesparmodus deaktiviert" >> $LOG 2>&1 - fi - - ### Enable WLAN - lipc-set-prop com.lab126.wifid enable 1 >> $LOG 2>&1 - - ### Wait on WLAN - WLANCOUNTER=0 - while wait_wlan; do - if [ ${WLANCOUNTER} -gt 30 ]; then - echo "`date '+%Y-%m-%d_%H:%M:%S'` | Leider kein bekanntes WLAN verfügbar" >> $LOG 2>&1 - break - fi - let WLANCOUNTER=WLANCOUNTER+1 - sleep 1 - done - - ### Workaround Default Gateway after STR - GATEWAY=`ip route | grep default | grep $NET | awk '{print $3}'` - if [ -z "$GATEWAY" ]; then - route add default gw $ROUTERIP >> $LOG 2>&1 + lipc-set-prop com.lab126.powerd preventScreenSaver 1 >> ${LOG} 2>&1 + echo "`date '+%Y-%m-%d_%H:%M:%S'` | ${HOSTNAME} | Standard Energiesparmodus deaktiviert." >> ${LOG} 2>&1 fi - ### Check new Script - # wget (-N) can't https - LMTIMESH=`stat -c %Y "$SCRIPTDIR/$NAME.sh"` - curl --silent --time-cond "$SCRIPTDIR/$NAME.sh" --output "$SCRIPTDIR/$NAME.sh" http://$RSH - RMTIMESH=`stat -c %Y "$SCRIPTDIR/$NAME.sh"` - if [ $RMTIMESH -gt $LMTIMESH ]; then - echo "`date '+%Y-%m-%d_%H:%M:%S'` | Skript aktualisiert, Neustart durchführen" >> $LOG 2>&1 - chmod 777 "$SCRIPTDIR/$NAME.sh" - reboot - exit - fi - - ### HOSTNAME & IP - IP=`ifconfig $NET | grep "inet addr" | cut -d':' -f2 | awk '{print $1}'` - HOSTNAME=`nslookup $IP | grep Address | grep $IP | awk '{print $4}' | awk -F. '{print $1}'` - - ### Get new Weatherdata - # wget can't https - if [ "${HOSTNAME}" = "kindle-kt3-schwarz" ]; then - RIMG="$RSRV/kindle-weather/weatherdata-bad.png" - fi - if [ "${HOSTNAME}" = "kindle-kt3-weiss" ]; then - RIMG="$RSRV/kindle-weather/weatherdata-wohnzimmer.png" + ### Check Batterystate + CHECKBATTERY=`gasgauge-info -s` + echo "`date '+%Y-%m-%d_%H:%M:%S'` | ${HOSTNAME} | Batteriezustand: ${CHECKBATTERY}%" >> ${LOG} 2>&1 + if [ ${CHECKBATTERY} -gt 80 ]; then + NOTIFYBATTERY=0 fi - - let REFRESHCOUNTER=REFRESHCOUNTER+1 - if curl --silent --output "$LIMG" "http://$RIMG"; then - if [ ${REFRESHCOUNTER} -ne 5 ]; then - eips -g "$LIMG" - echo "`date '+%Y-%m-%d_%H:%M:%S'` | Wetterbild aktualisiert" >> $LOG 2>&1 - else - eips -f -g "$LIMG" - echo "`date '+%Y-%m-%d_%H:%M:%S'` | Wetterbild und E-Ink aktualisiert" >> $LOG 2>&1 - REFRESHCOUNTER=0 - fi - else - eips -f -g "$LIMGERR" - echo "`date '+%Y-%m-%d_%H:%M:%S'` | Wetterbild nicht aktualisiert" >> $LOG 2>&1 + if [ ${CHECKBATTERY} -le 1 ]; then + echo "`date '+%Y-%m-%d_%H:%M:%S'` | ${HOSTNAME} | Batteriezustand 1%, statisches Batteriezustandsbild gesetzt, WLAN deaktivert, Ruhezustand!" >> ${LOG} 2>&1 + eips -f -g "${LIMGBATT}" + lipc-set-prop com.lab126.wifid enable 0 + echo 0 > /sys/class/rtc/rtc0/wakealarm + echo "mem" > /sys/power/state fi - ### Disable WLAN - # No stable "wakealarm" with enabled WLAN - lipc-set-prop com.lab126.wifid enable 0 >> $LOG 2>&1 - ### Set SUSPENDFOR - # no regex in if with /bin/sh + # no regex in if with /bin/sh DAYOFWEEK=`date +%u` # 1=Monday HOURNOW=`date +%H` # Hour # Workdays if [ ${DAYOFWEEK} -ge 1 ] && [ ${DAYOFWEEK} -le 5 ]; then - for LINE in $F5INTWORKDAY; do - HOURS=`echo $LINE | awk -F\| '{print $1}'` + for LINE in ${F5INTWORKDAY}; do + HOURS=`echo ${LINE} | awk -F\| '{print $1}'` echo "${HOURS}" | grep ${HOURNOW} > /dev/null 2>&1 if [ $? -eq 0 ]; then - SUSPENDFOR=`echo $LINE | awk -F\| '{print $2}'` - echo "$SUSPENDFOR" - echo "`date '+%Y-%m-%d_%H:%M:%S'` | Aufwachintervall auf $SUSPENDFOR gesetzt" >> $LOG 2>&1 + SUSPENDFOR=`echo ${LINE} | awk -F\| '{print $2}'` + echo "${SUSPENDFOR}" + echo "`date '+%Y-%m-%d_%H:%M:%S'` | ${HOSTNAME} | Aufwachintervall für den nächsten Ruhezustand auf ${SUSPENDFOR} gesetzt." >> ${LOG} 2>&1 fi done fi # Weekend if [ ${DAYOFWEEK} -ge 6 ] && [ ${DAYOFWEEK} -le 7 ]; then - for LINE in $F5INTWEEKEND; do - HOURS=`echo $LINE | awk -F\| '{print $1}'` + for LINE in ${F5INTWEEKEND}; do + HOURS=`echo ${LINE} | awk -F\| '{print $1}'` echo "${HOURS}" | grep ${HOURNOW} > /dev/null 2>&1 if [ $? -eq 0 ]; then - SUSPENDFOR=`echo $LINE | awk -F\| '{print $2}'` - echo "`date '+%Y-%m-%d_%H:%M:%S'` | Aufwachintervall auf $SUSPENDFOR gesetzt" >> $LOG 2>&1 + SUSPENDFOR=`echo ${LINE} | awk -F\| '{print $2}'` + echo "`date '+%Y-%m-%d_%H:%M:%S'` | ${HOSTNAME} | Aufwachintervall für den nächsten Ruhezustand auf ${SUSPENDFOR} gesetzt." >> ${LOG} 2>&1 fi done fi - # Set wakealarm - WAKEUPTIMER=$(( `date +%s` + $SUSPENDFOR )) - echo "`date '+%Y-%m-%d_%H:%M:%S'` | Aufwachzeitpunkt `date -d @$WAKEUPTIMER '+%Y-%m-%d_%H:%M:%S'`" >> $LOG 2>&1 + ### Calculation WAKEUPTIMER + WAKEUPTIMER=$(( `date +%s` + ${SUSPENDFOR} )) + echo "`date '+%Y-%m-%d_%H:%M:%S'` | ${HOSTNAME} | Aufwachzeitpunkt für den nächsten Ruhezustand `date -d @${WAKEUPTIMER} '+%Y-%m-%d_%H:%M:%S'`." >> ${LOG} 2>&1 + + ### Enable WLAN + lipc-set-prop com.lab126.wifid enable 1 >> ${LOG} 2>&1 + echo "`date '+%Y-%m-%d_%H:%M:%S'` | ${HOSTNAME} | WLAN aktivieren." >> ${LOG} 2>&1 + + ### Wait on WLAN + WLANNOTCONNECTED=0 + WLANCOUNTER=0 + while wait_wlan; do + if [ ${WLANCOUNTER} -gt 30 ]; then + echo "`date '+%Y-%m-%d_%H:%M:%S'` | ${HOSTNAME} | Leider kein bekanntes WLAN verfügbar." >> ${LOG} 2>&1 + eips -f -g "${LIMGERRWLAN}" + WLANNOTCONNECTED=1 + break + fi + let WLANCOUNTER=WLANCOUNTER+1 + echo "`date '+%Y-%m-%d_%H:%M:%S'` | ${HOSTNAME} | Warte auf WLAN (Versuch ${WLANCOUNTER})." >> ${LOG} 2>&1 + sleep 1 + done + + ### Connected with WLAN? + if [ ${WLANNOTCONNECTED} -eq 0 ]; then + + ### Workaround Default Gateway after STR + GATEWAY=`ip route | grep default | grep ${NET} | awk '{print $3}'` + if [ -z "${GATEWAY}" ]; then + route add default gw ${ROUTERIP} >> ${LOG} 2>&1 + fi + + ### Batterystate critical? SMS! + if [ ${CHECKBATTERY} -le 5 ] && [ ${NOTIFYBATTERY} -eq 0 ]; then + NOTIFYBATTERY=1 + if [ ${SMSACTIV} -eq 1 ]; then + echo "`date '+%Y-%m-%d_%H:%M:%S'` | ${HOSTNAME} | Batteriezustand kritisch, SMS werden verschickt!" >> ${LOG} 2>&1 + MESSAGE="Der Batteriezustand von ${HOSTNAME} ist kritisch (${CHECKBATTERY}%) - bitte laden!" + send_sms + else + echo "`date '+%Y-%m-%d_%H:%M:%S'` | ${HOSTNAME} | Batteriezustand kritisch." >> ${LOG} 2>&1 + fi + fi + + ### Check new Script + # wget (-N) can't https + RSTATUSSH=`curl --silent --head "http://${RSH}" | head -n 1 | cut -d$' ' -f2` + if [ ${RSTATUSSH} -eq 200 ]; then + LMTIMESH=`stat -c %Y "${SCRIPTDIR}/${NAME}.sh"` + curl --silent --time-cond "${SCRIPTDIR}/${NAME}.sh" --output "${SCRIPTDIR}/${NAME}.sh" "http://${RSH}" + RMTIMESH=`stat -c %Y "${SCRIPTDIR}/${NAME}.sh"` + if [ ${RMTIMESH} -gt ${LMTIMESH} ]; then + echo "`date '+%Y-%m-%d_%H:%M:%S'` | ${HOSTNAME} | Skript aktualisiert, Neustart durchführen." >> ${LOG} 2>&1 + chmod 777 "${SCRIPTDIR}/${NAME}.sh" + reboot + exit + fi + else + echo "`date '+%Y-%m-%d_%H:%M:%S'` | ${HOSTNAME} | Skript nicht gefunden (HTTP-Status ${RSTATUSSH})." >> ${LOG} 2>&1 + fi + + ### Get new Weatherdata + # wget can't https + if [ "${HOSTNAME}" = "kindle-kt3-schwarz" ]; then + RIMG="${RSRV}/kindle-weather/weatherdata-bad.png" + fi + if [ "${HOSTNAME}" = "kindle-kt3-weiss" ]; then + RIMG="${RSRV}/kindle-weather/weatherdata-wohnzimmer.png" + fi + + let REFRESHCOUNTER=REFRESHCOUNTER+1 + RSTATUSIMG=`curl --silent --head "http://${RIMG}" | head -n 1 | cut -d$' ' -f2` + if [ ${RSTATUSIMG} -eq 200 ]; then + curl --silent --output "$LIMG" "http://${RIMG}" + if [ ${REFRESHCOUNTER} -ne 5 ]; then + eips -g "$LIMG" + echo "`date '+%Y-%m-%d_%H:%M:%S'` | ${HOSTNAME} | Wetterbild aktualisiert." >> ${LOG} 2>&1 + else + eips -f -g "$LIMG" + echo "`date '+%Y-%m-%d_%H:%M:%S'` | ${HOSTNAME} | Wetterbild und E-Ink aktualisiert." >> ${LOG} 2>&1 + REFRESHCOUNTER=0 + fi + elif [ -z "${RSTATUSIMG}" ]; then + eips -f -g "$LIMGERRNET" + echo "`date '+%Y-%m-%d_%H:%M:%S'` | ${HOSTNAME} | Webserver reagiert nicht. Webserver läuft? Server erreichbar? Kindle mit dem WLAN verbunden?" >> ${LOG} 2>&1 + else + eips -f -g "$LIMGERR" + echo "`date '+%Y-%m-%d_%H:%M:%S'` | ${HOSTNAME} | Wetterbild auf Webserver nicht gefunden (HTTP-Status ${RSTATUSSH})." >> ${LOG} 2>&1 + fi + + ### Copy log by ssh + cat ${LOG} | ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i /mnt/us/scripts/id_rsa_kindle -l kindle ${RSRV} "cat >> ${RPATH}/${NAME}_${HOSTNAME}.log" > /dev/null 2>&1 + if [ $? -eq 0 ]; then + rm ${LOG} + echo "`date '+%Y-%m-%d_%H:%M:%S'` | ${HOSTNAME} | Log per SSH an Remote-Server übergeben und lokal gelöscht." >> ${LOG} 2>&1 + else + echo "`date '+%Y-%m-%d_%H:%M:%S'` | ${HOSTNAME} | Log konnte nicht an den Remote-Server übergeben werden." >> ${LOG} 2>&1 + fi + + fi + + ### Disable WLAN + # No stable "wakealarm" with enabled WLAN + lipc-set-prop com.lab126.wifid enable 0 + echo "`date '+%Y-%m-%d_%H:%M:%S'` | ${HOSTNAME} | WLAN deaktivieren." >> ${LOG} 2>&1 + ### Set wakealarm echo 0 > /sys/class/rtc/rtc0/wakealarm - echo $WAKEUPTIMER > /sys/class/rtc/rtc0/wakealarm + echo ${WAKEUPTIMER} > /sys/class/rtc/rtc0/wakealarm - # Go into Suspend to Memory (STR) + ### Go into Suspend to Memory (STR) + echo "`date '+%Y-%m-%d_%H:%M:%S'` | ${HOSTNAME} | Ruhezustand starten." >> ${LOG} 2>&1 echo "mem" > /sys/power/state done diff --git a/README.jpg b/README.jpg index 356ea0d..6b7773d 100644 Binary files a/README.jpg and b/README.jpg differ diff --git a/README.md b/README.md index e18cebf..62eaf21 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,8 @@ ## Kindle KT3 als Wetterstation -Gleich erst mal zu Beginn: -Schlagt es euch gleich erst mal aus dem Kopf, wenn ihr denkt, ihr haut das Skript auf einen Server im LAN und die Dateien auf das Kindle, fertig. So wird das nichts! Die beiden Skripts, vor allem aber `cron_kindle-wetter.py` (Server), welches für die Erstellung der PNG-Datei verantwortlich ist, ist extrem auf meine Bedürfnisse angepasst und muss von euch, an eure Geräte und Bedürfnisse, angepasst werden. +Gleich erst mal zu Beginn: +Schlagt es euch gleich erst mal aus dem Kopf, wenn ihr denkt, ihr haut das Skript auf einen Server im LAN und die Dateien auf das Kindle, fertig. So wird das nichts! Die beiden Skripts, vor allem aber `cron_kindle-wetter.py` (Server), welches für die Erstellung der PNG-Datei verantwortlich ist, ist extrem auf meine Bedürfnisse angepasst und muss von euch, an eure Geräte und Bedürfnisse, angepasst werden. Ohne Basic-Kenntnisse im Skripting: **FINGER WEG!** @@ -107,6 +107,8 @@ Wenn ihr Mal mehr Zeit in der üblichen Kindle-UI benötigt oder es euch nicht m ## Versionsverlauf +2018-07-23 - neues Layout und Umstellung auf DarkSky API (alte Version in den "180405" Ordnern), Fehlerbehebungen +2018-04-05 - Fehlerbehebungen 2018-03-24 - Skripts veröffentlicht diff --git a/README_180405.jpg b/README_180405.jpg new file mode 100644 index 0000000..b211ce0 Binary files /dev/null and b/README_180405.jpg differ diff --git a/README_180405.md b/README_180405.md new file mode 100644 index 0000000..df303e4 --- /dev/null +++ b/README_180405.md @@ -0,0 +1,136 @@ + +# kindle-kt3_weatherdisplay_battery-optimized + +## Kindle KT3 als Wetterstation + +Gleich erst mal zu Beginn: +Schlagt es euch gleich erst mal aus dem Kopf, wenn ihr denkt, ihr haut das Skript auf einen Server im LAN und die Dateien auf das Kindle, fertig. So wird das nichts! Die beiden Skripts, vor allem aber `cron_kindle-wetter.py` (Server), welches für die Erstellung der PNG-Datei verantwortlich ist, ist extrem auf meine Bedürfnisse angepasst und muss von euch, an eure Geräte und Bedürfnisse, angepasst werden. + +Ohne Basic-Kenntnisse im Skripting: **FINGER WEG!** + +Zwei Kindle KT3 als Wetterstation + +## Batterie / Akku + +Das Kindle-Skript `weatherscript.sh` ist auf möglichst lange Akkulaufzeit optimiert! + +* Kindle Dienste werden beendet. +* CPU wird in den "Powersave-Mode" versetzt. +* WLAN nur kurz aktiv. +* E-INK-Display wird nicht immer vollständig aktualisiert. +* Individuellen Aufwachintervall nach Wochentag und Stunde. +* Suspend-to-RAM / Suspend-to-Memory (STR). + +In der aktuellen Konfiguration (57 Änderungen am Tag) hält der Akku des KT3 **ca. 30-35 Tage**. + + +## Vorbereitungen + +Natürlich ist es keine Standardfunktionalität, das Wetter auf einem Kindle als Bildschirmschoner anzeigen zu lassen, aus diesem Grund muss das Kindle gejailbreakt und SSH aktiviert werden. + +**Ein paar Fakten:** +* Jailbreak funktioniert nur, wenn sich auf dem Kindle eine Firmware 5.8.7 oder älter befindet. +* Jailbreak muss "persistend" / "dauerhaft" gemacht werden. + - Firmware-Updates (nicht OTA > BIN-Datei per USB) können eingespielt werden - der Jailbreak bleibt, nach aktuellem Stand (2018-03-08 | Firmware 5.9.4) weiterhin bestehen. + - Es könnte aber mit jeder neueren Version Schluss sein - also Obacht und vorher in der [Community](https://www.mobileread.com/forums/forumdisplay.php?f=150) informieren! +* USB-Networking (usbnet) muss installiert werden, um dann über ein paar Anpassungen der Konfigurationsdateien (Kindle-Laufwerk) SSH zu aktivieren. + +**Übliche Fragen:** +- [Welchen Kindle (Typ) habe ich?](https://wiki.mobileread.com/wiki/Kindle_Serial_Numbers) +- [Wie jailbreake ich mein Kindle?](https://wiki.mobileread.com/wiki/5_x_Jailbreak) + +**Fragen zum Jailbreak werden von mir nicht beantwortet!** + + +## Funktionsweise / Logik / Features + +Auf einem Server im LAN, sucht sich das Skript `cron_kindle-wetter.py`, bei mir alle 10 Minuten, die Wetterdaten zusammen. + +* Innenraumtemperaturen und Luftfeuchten holt es sich aus meiner HomeMatic CCU2 ([XML-API Addon](https://www.homematic-inside.de/software/xml-api)) von zwei [HmIP-STH](https://www.amazon.de/Homematic-IP-Temperatur-Luftfeuchtigkeitssensor-150181A1/dp/B01MQECR9R/ref=as_li_ss_tl?_encoding=UTF8&psc=1&refRID=X07WWNTM8YPT09RJ0JJX&linkCode=ll1&tag=logdemacosxli-21&linkId=2675c7ae97bda525ebb2694284611493). Zusätzlich werden die Werte in eine MySQL-Datenbank geschrieben, damit ich die MIN- / MAX-Werte anzeigen kann. + - Warum zwei [HmIP-STH](https://www.amazon.de/Homematic-IP-Temperatur-Luftfeuchtigkeitssensor-150181A1/dp/B01MQECR9R/ref=as_li_ss_tl?_encoding=UTF8&psc=1&refRID=X07WWNTM8YPT09RJ0JJX&linkCode=ll1&tag=logdemacosxli-21&linkId=2675c7ae97bda525ebb2694284611493)? Ich unterscheide, aufgrund von einem Kindle KT3 im Bad (Schwarz) und einen im Wohnzimmer (Weiß), zwischen Bad und Wohnzimmer. Es werden auch zwei, geringfügig unterschiedliche PNGs erzeugt. +* Luftqualität ist aktuell noch hart codiert, da mir hier noch der passende Sensor fehlt. +* Bezeichnung der aktuellen Wetterlage (sunny, rain, etc.) holt es sich über die "Weather Underground API". +* Außentemperatur, Luftfeuchte, Windgeschwindigkeit, -Richtung und Regenmenge holt er sich aus meiner HomeMatic CCU2 ([XML-API Addon](https://www.homematic-inside.de/software/xml-api)) von einem [HmIP-SWO-PR](https://www.amazon.de/Homematic-IP-Wettersensor-Pro-151821A0/dp/B07589Q8FH/ref=as_li_ss_tl?s=diy&ie=UTF8&qid=1521926725&sr=1-1&keywords=hmip%20swo%20pro&linkCode=ll1&tag=logdemacosxli-21&linkId=865a8f2b0656b22db5582e7592e85f7e). Zusätzlich werden die Werte in eine MySQL-Datenbank geschrieben, damit ich die MIN- / MAX-Werte anzeigen kann. +* 3-Tages-Vorhersage holt es sich über die "Weather Underground API". +* Sonnenauf- und Sonnenuntergang holt es sich auch über die WU API. + +Hat der Server alle Wetterdaten zusammen, lädt er sich die SVG-Datei `cron_kindle-wetter_preprocess.svg` und tauscht die für den Bereich definierten Variablen mit den echten und aktuellen Wetterdaten aus. Hier werden durch eine Logik sogar zwei Dateien `weatherdata-bad.png` und `weatherdata-wohnzimmer.png` erzeugt, welche dann im Webserver-Verzeichnis, des Servers, abgelegt werden. + +          + +Das Skript `weatherscript.sh` gehört auf das Kindle, bei mir `/mnt/us/scripts/`. Dieses Skript startet in der Regel 60 Sekunden nach dem Starten des Kindles und beendet dann erst mal alle Kindle üblichen Dienste, um Ressourcen / Akkukapazität zu sparen. Dann läuft das Skript in eine Schleife, die dauerhaft, immer und immer wieder, abgearbeitet wird. Pausiert wird das Skript durch ein STR (Suspend-to-RAM/ Suspend-to-Memory). Vor dem STR wird noch ein Wecker gestellt, der der Kindle-Hardware sagt, wann das Kindle wieder aufwachen soll. Dann, wenn der Wecker klingelt, läuft das Skript weiter, führt ein paar Befehle aus, holt sich das neue PNG mit den Wetterinformationen und verabschiedet sich für einen dynamischen Intervall wieder in den STR. + +* Beendet unwichtige Kindle Dienste. +* Prüft den Batteriestatus. + * ... wenn 5% oder weniger, bekomme ich und meine Frau eine SMS. + * ... bei 1% wird ein statisches Bild mit "battery low" geladen. + * ... das Bild wird so lange angezeigt, bis das Kindle am Strom angeschlossen wird und über Powertaste wieder aufgeweckt wird. +* CPU wird runtergetackte und in den "Powersave-Mode" versetzt. +* Standard Bildschirmschoner wird deaktiviert. +* WLAN wird aktiviert. + * ... es wird gewartet, bis eine WLAN-Verbindung aufgebaut wurde. +* Standard-Gateway wird erneut gesetzt (Workaround). +* Hostname und IP-Adresse wird ermittelt. + * ... je nach Hostname wird nun ein bestimmtes PNG-Bild von meinem Webserver geladen (welches von `cron_kindle-wetter.py` erzeugt wurde). +* Das PNG-Bild wird jetzt auf dem E-INK Display angezeigt. + * ... nur bei jedem fünften Mal wird eine Komplettaktualisierung des Displays gemacht. + * ... alle anderen Male nur eine Teilaktualisierung (dadurch können Schatten entstehen). +* WLAN wird deaktiviert. +* Aufwachintervall wird gesetzt, siehe `F5INTWORKDAY` und `F5INTWEEKEND`. + * ... an einem Wochentag um 1 Uhr, egal wie viele Minuten, wird der Aufwachintervall auf 3600 Sekunden gesetzt, also eine Stunde. + * ... an einem Wochentag um 15 Uhr wird der Aufwachintervall auf 900 Sekunden gesetzt, also 15 Minuten. + * ... am Wochenende ... +* Suspend-to-RAM / Suspend-to-Memory (STR) wird ausgeführt. + + +## Installation + +### Server + +* Variablen im Skript `cron_kindle-wetter.py` anpassen, ggf. das ganze Skript. +* Skript `cron_kindle-wetter.py` und SVG `cron_kindle-wetter_preprocess.svg` übertragen. +* Skript ausführbar machen `chmod 744 cron_kindle-wetter.py`. +* Skript regelmäßig über Crontab ausführen. + +### Kindle + +* Variablen im Skript `weatherscript.sh` anpassen, ggf. das ganze Skript. +* Skript `weatherscript.sh`, Upstart-Datei `weather.conf` und die 5 PNGs auf Kindle übertragen - bei mir `/mnt/us/scripts/`. +* Skript ausführbar machen `chmod 744 weatherscript.sh`. +* Upstart-Datei kopieren, vorher Kindle-Filesystem schreibbar machen `mntroot rw && cp /mnt/us/scripts/wetter.conf /etc/upstart/wetter.conf` +* Nach einem Neustart des Kindles dauert es nun 60 Sekunden, bis das Skript `weatherscript.sh` startet und das PNG anzeigt. + +#### Info + +Wenn ihr Mal mehr Zeit in der üblichen Kindle-UI benötigt oder es euch nicht mehr gefällt, startet das Kindle neu - ca. 20-30 Sekunden Powertaste drücken. Wenn auf dem Boot-Screen, im Fortschrittsbalken, noch ca. 1cm fehlen, kann man per SSH auf das Kindle zugreifen und mit `kill` den `sleep` und das `weatherscript.sh` beenden oder die Upstart-Datei `/etc/upstart/wetter.conf` löschen und so den Autostart zukünftig verhindern. SCHNELL, MAN HAT NUR 60 SEKUNDEN ZEIT! + + +## Versionsverlauf + +2018-03-24 - Skripts veröffentlicht + + +## Lizenz + +The MIT License (MIT) + +Copyright (c) 2018 Nico Hartung + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/Server/180405/cron_kindle-wetter_180405.py b/Server/180405/cron_kindle-wetter_180405.py new file mode 100644 index 0000000..ba58b67 --- /dev/null +++ b/Server/180405/cron_kindle-wetter_180405.py @@ -0,0 +1,322 @@ +#!/usr/bin/python3 + +####################################################### +### Autor: Nico Hartung # +####################################################### + +############## +# Bibliotheken +import os +import datetime +import codecs +import urllib.request +import json +import untangle +import MySQLdb + + +########### +# Variablen +WEATHER_URL = "http://api.wunderground.com/api/" +WEATHER_KEY = "f1ab87d880075ea6" # 500 quests per day +CITY = "Münchberg, Bayern, DE" +LATITUDE = "50.192900" +LONGTITUDE = "11.8035702" + +PATH = "/root/Scripts" +OUTPUT = "/var/www/html/kindle-weather/weatherdata.png" +SVG_FILE = "%s/cron_kindle-wetter_preprocess.svg" % PATH +SVG_OUTPUT = "%s/cron_kindle-wetter_output.svg" % PATH +TMP_OUTPUT = "%s/cron_kindle-wetter_tmp.png" % PATH + +ROOMS = ["Bad", "Wohnzimmer"] + +HOMEMATICIP = "192.168.137.66" +DEVICES = 2390,2465,2541 # Wohnzimmer (Temp), Bad (Temp), Garten (Wettersensor) + +SQLHOST = "localhost" +SQLUSER = "weatherdata" +SQLPW = "weatherdata" +SQLDB = "weatherdata" +SQLTAB = "homematic" + + +############ +# Funktionen +def _exec(cmd): + rc = os.system(cmd) + if (rc != 0): + print("`%s` failed with error %d" % (cmd, rc)) + exit(rc) + +def sqlinsert(cursor, DEVICE, datapoint, datapointid, value): + sql = "INSERT INTO %s (deviceid, datapointid, datapoint, value) VALUES ('%s', '%s', '%s', '%s')" % (SQLTAB, DEVICE, datapointid, datapoint, value) + cursor.execute(sql) + db.commit() + +def sqlminmax(cursor, datapointid, sort, decimal): + cursor.execute( + "SELECT value FROM %s WHERE datapointid = %s AND DATE(timestamp) = DATE(NOW()) ORDER BY value + 0 %s LIMIT 1" % + (SQLTAB, datapointid, sort)) + for select in cursor.fetchall(): + #return('%.%sf' % (float(select[0]), decimal)) + return('%.{0}f'.format(decimal) % select[0]) + + +##################### +# Aktuelle Wetterlage +# http://api.wunderground.com/api/f1ab87d880075ea6/conditions/q/50.192900,11.8035702.json +conditions = urllib.request.urlopen( + "%s/%s/conditions/q/%s,%s.json" % + (WEATHER_URL, WEATHER_KEY, LATITUDE, LONGTITUDE)) +json_conditions = conditions.read().decode('utf-8') +parsed_conditions = json.loads(json_conditions) + + +############ +# Astronomie +# http://api.wunderground.com/api/f1ab87d880075ea6/astronomy/q/50.192900,11.8035702.json +astronomy = urllib.request.urlopen( + "%s/%s/astronomy/q/%s,%s.json" % + (WEATHER_URL, WEATHER_KEY, LATITUDE, LONGTITUDE)) +json_astronomy = astronomy.read().decode('utf-8') +parsed_astronomy = json.loads(json_astronomy) + + +################## +# Wettervorhersage +# http://api.wunderground.com/api/f1ab87d880075ea6/forecast/q/50.192900,11.8035702.json +forecast = urllib.request.urlopen( + "%s/%s/forecast/q/%s,%s.json" % + (WEATHER_URL, WEATHER_KEY, LATITUDE, LONGTITUDE)) +json_forecast = forecast.read().decode('utf-8') +parsed_forecast = json.loads(json_forecast) +forecast_list = [] +for forecast_data in parsed_forecast['forecast']['simpleforecast']['forecastday']: + forecast_perday = [ + forecast_data['date']['weekday'] + .replace('Monday', 'Montag') + .replace('Tuesday', 'Dienstag') + .replace('Wednesday', 'Mittwoch') + .replace('Thursday', 'Donnerstag') + .replace('Friday', 'Freitag') + .replace('Saturday', 'Samstag') + .replace('Sunday', 'Sonntag'), + forecast_data['icon'], + forecast_data['high']['celsius'], + forecast_data['low']['celsius'] + ] + forecast_list.append(forecast_perday) + # # 0=today, 1=tomorrow, etc. + # forecast_list[1][2] = temp high for tomorrow + + +################ +# Homematic CCU2 +# http://192.168.137.66/addons/xmlapi/state.cgi?device_id=2390,2465 +db = MySQLdb.connect( + SQLHOST, + SQLUSER, + SQLPW, + SQLDB) +cursor = db.cursor() + +for DEVICE in DEVICES: + + xmldoc = untangle.parse( + "http://%s/addons/xmlapi/state.cgi?device_id=%s" % + (HOMEMATICIP, DEVICE)) + + for ITEMS in xmldoc.state.device.channel: + if ITEMS.get_elements('datapoint'): + for DATA in ITEMS.datapoint: + datapointname = DATA['name'] + + ### Temperatur + if datapointname.endswith('.ACTUAL_TEMPERATURE'): + datapointid = DATA['ise_id'] + datapoint = DATA['name'] + value = DATA['value'] + + sqlinsert(cursor, DEVICE, datapoint, datapointid, value) + + # WZ + if DEVICE == 2390: + wzt = '%.1f' % float(value) + wth = sqlminmax(cursor, datapointid, "DESC", 1) + wtl = sqlminmax(cursor, datapointid, "ASC", 1) + + # Bad + if DEVICE == 2465: + bat = '%.1f' % float(value) + bth = sqlminmax(cursor, datapointid, "DESC", 1) + btl = sqlminmax(cursor, datapointid, "ASC", 1) + + # Garten + if DEVICE == 2541: + gtt = '%.1f' % float(value) + gth = sqlminmax(cursor, datapointid, "DESC", 1) + gtl = sqlminmax(cursor, datapointid, "ASC", 1) + + ### Luftfeuchtigkeit + if datapointname.endswith('.HUMIDITY'): + datapointid = DATA['ise_id'] + datapoint = DATA['name'] + value = DATA['value'] + + sqlinsert(cursor, DEVICE, datapoint, datapointid, value) + + # WZ + if DEVICE == 2390: + wzh = '%.0f' % float(value) + whh = sqlminmax(cursor, datapointid, "DESC", 0) + whl = sqlminmax(cursor, datapointid, "ASC", 0) + + # Bad + if DEVICE == 2465: + bah = '%.0f' % float(value) + bhh = sqlminmax(cursor, datapointid, "DESC", 0) + bhl = sqlminmax(cursor, datapointid, "ASC", 0) + + # Garten + if DEVICE == 2541: + gah = '%.0f' % float(value) + ghh = sqlminmax(cursor, datapointid, "DESC", 0) + ghl = sqlminmax(cursor, datapointid, "ASC", 0) + + ### Niederschlagsmenge + # Ohne "Reset" wird die Niederschlagsmenge immer zum letzten Wert addiert - wächst immer weiter an, wird nicht auf 0 gesetzt. + if datapointname.endswith('.RAIN_COUNTER'): + datapointid = DATA['ise_id'] + datapoint = DATA['name'] + value = DATA['value'] + + sqlinsert(cursor, DEVICE, datapoint, datapointid, value) + + # Garten + if DEVICE == 2541: + cursor.execute( + "SELECT maxi-mini FROM (SELECT MIN(value) mini, MAX(value) maxi FROM (SELECT value FROM %s WHERE datapointid = %s AND timestamp >= NOW() - INTERVAL 1 DAY ) mm1) mm2" % + (SQLTAB, datapointid)) + for select in cursor.fetchall(): + grr = '%.1f' % float(select[0]) + + ### Windrichtung + if datapointname.endswith('.WIND_DIR'): + datapointid = DATA['ise_id'] + datapoint = DATA['name'] + value = DATA['value'] + + sqlinsert(cursor, DEVICE, datapoint, datapointid, value) + + # Garten + if DEVICE == 2541: + gwdtemp = '%.1f' % float(value) + + if 0 <= float(gwdtemp) <= 22.4: + gwd = "N" + elif 22.5 <= float(gwdtemp) <= 67.4: + gwd = "NO" + elif 67.5 <= float(gwdtemp) <= 112.4: + gwd = "O" + elif 112.5 <= float(gwdtemp) <= 157.4: + gwd = "SO" + elif 157.5 <= float(gwdtemp) <= 202.4: + gwd = "S" + elif 202.5 <= float(gwdtemp) <= 247.4: + gwd = "SW" + elif 247.5 <= float(gwdtemp) <= 292.4: + gwd = "W" + elif 292.5 <= float(gwdtemp) <= 337.4: + gwd = "NW" + elif 337.5 <= float(gwdtemp) <= 360: + gwd = "N" + + ### Windgeschwindigkeit + if datapointname.endswith('.WIND_SPEED'): + datapointid = DATA['ise_id'] + datapoint = DATA['name'] + value = DATA['value'] + + sqlinsert(cursor, DEVICE, datapoint, datapointid, value) + + # Garten + if DEVICE == 2541: + gws = '%.1f' % float(value) + + cursor.execute( + "SELECT value FROM %s WHERE datapointid = %s AND DATE(timestamp) = DATE(NOW()) ORDER BY value + 0 DESC LIMIT 1" % + (SQLTAB, datapointid)) + for select in cursor.fetchall(): + gwh = '%.0f' % float(select[0]) + + +############################################################ +# SVG einlesen, Output zusammensuchen und SVG/PNG generieren +### http://www.svgminify.com > then copy/paste "defs" + +for ROOM in ROOMS: + + OUTPUT = "/var/www/html/kindle-weather/weatherdata-%s.png" % (ROOM.lower()) + ROOM1 = "Innen (%s)" % (ROOM) + + output = codecs.open(SVG_FILE, "r", encoding="utf-8").read() + + output = output.replace("$TIME", datetime.datetime.now().strftime("%Y-%m-%d %H:%M")) + output = output.replace("$LOC", str(CITY)) + output = output.replace("$I0", str(parsed_conditions['current_observation']['icon'])) + output = output.replace("$CT", str(gtt)) + output = output.replace("$CHH", str(gth)) + output = output.replace("$CHL", str(gtl)) + output = output.replace("$CL", str(gah)) + output = output.replace("$CAH", str(ghh)) + output = output.replace("$CAL", str(ghl)) + output = output.replace("$CW", str(gws)) + output = output.replace("$CD", str(gwd)) + output = output.replace("$CHW", str(gwh)) + output = output.replace("$AQ", str("1234")) + output = output.replace("$QL", str("546")) + output = output.replace("$QH", str("2345")) + output = output.replace("$CR", str(grr)) + output = output.replace("$D1", str("Heute")) + output = output.replace("$I1", str(forecast_list[0][1])) + output = output.replace("$L1", str(forecast_list[0][3])) + output = output.replace("$H1", str(forecast_list[0][2])) + output = output.replace("$D2", str("Morgen")) + output = output.replace("$I2", str(forecast_list[1][1])) + output = output.replace("$L2", str(forecast_list[1][3])) + output = output.replace("$H2", str(forecast_list[1][2])) + output = output.replace("$D3", str(forecast_list[2][0])) + output = output.replace("$I3", str(forecast_list[2][1])) + output = output.replace("$L3", str(forecast_list[2][3])) + output = output.replace("$H3", str(forecast_list[2][2])) + output = output.replace("$sunrise", str("%s:%s" % (parsed_astronomy['sun_phase']['sunrise']['hour'], parsed_astronomy['sun_phase']['sunrise']['minute']))) + output = output.replace("$sunset", str("%s:%s" % (parsed_astronomy['sun_phase']['sunset']['hour'], parsed_astronomy['sun_phase']['sunset']['minute']))) + + if ROOM == "Bad": + ROOM2 = "Wohnzimmer" + output = output.replace("$ROOM1", str(ROOM1)) + output = output.replace("$ROOM2", str(ROOM2)) + output = output.replace("$BT", str(bat)) + output = output.replace("$BSL", str(btl)) + output = output.replace("$BSH", str(bth)) + output = output.replace("$BH", str(bah)) + output = output.replace("$BBH", str(bhh)) + output = output.replace("$BBL", str(bhl)) + + if ROOM == "Wohnzimmer": + ROOM2 = "" + output = output.replace("$ROOM1", str(ROOM1)) + output = output.replace("$ROOM2", str(ROOM2)) + output = output.replace("$BT", str(wzt)) + output = output.replace("$BSL", str(wtl)) + output = output.replace("$BSH", str(wth)) + output = output.replace("$BH", str(wzh)) + output = output.replace("$BBH", str(whh)) + output = output.replace("$BBL", str(whl)) + + codecs.open(SVG_OUTPUT, "w", encoding="utf-8").write(output) + _exec("rsvg-convert --background-color=white -o %s %s" % (TMP_OUTPUT, SVG_OUTPUT)) + _exec("pngcrush -c 0 -ow %s 1>/dev/null 2>&1" % TMP_OUTPUT) + _exec("mv -f '%s' '%s'" % (TMP_OUTPUT, OUTPUT)) + _exec("rm -f '%s'" % SVG_OUTPUT) \ No newline at end of file diff --git a/Server/180405/cron_kindle-wetter_preprocess_180405.svg b/Server/180405/cron_kindle-wetter_preprocess_180405.svg new file mode 100644 index 0000000..030840b --- /dev/null +++ b/Server/180405/cron_kindle-wetter_preprocess_180405.svg @@ -0,0 +1,220 @@ + + + + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +$ROOM1 +$ROOM2 + + + +MIN + +$BBL + +MAX + +$BBH + +$BH + +in % + + + + +$QH + +MAX + +$QL + +MIN + + +$AQ + +in ppm + + + + + + +$BSH + +MAX + +$BSL + +MIN + + +$BT + +in °C + + + + + + +Außen + + + +MIN + +$CAL + +MAX + +$CAH + +$CL + +in % + + + + + + + +MAX + + +$CHW + + +$CW +$CD + + +in km/h + + +$CR + +in mm/24h + + + + + + + +$CHL +MAX +$CHH + +MIN + + +$CT + +in °C + + + +$L1 + + +$H1 + + +MIN + + +°C + + +MAX + + + +$D1 + + +$L2 + + +$H2 + + +MIN + + +°C + + +MAX + + + +$D2 + +$L3 +$H3 + +MIN + + +°C + + +MAX + + + +$D3 + + + + + +$sunrise +$sunset + + + +$TIME +$LOC + + diff --git a/Server/180405/weatherdata-bad_180405.png b/Server/180405/weatherdata-bad_180405.png new file mode 100644 index 0000000..ac2d5e0 Binary files /dev/null and b/Server/180405/weatherdata-bad_180405.png differ diff --git a/Server/180405/weatherdata-wohnzimmer_180405.png b/Server/180405/weatherdata-wohnzimmer_180405.png new file mode 100644 index 0000000..7fe37bf Binary files /dev/null and b/Server/180405/weatherdata-wohnzimmer_180405.png differ diff --git a/Server/cron_kindle-wetter.py b/Server/cron_kindle-wetter.py index a54483f..d318da3 100755 --- a/Server/cron_kindle-wetter.py +++ b/Server/cron_kindle-wetter.py @@ -4,26 +4,38 @@ ### Autor: Nico Hartung # ####################################################### +# Weather Underground API Changes +# https://apicommunity.wunderground.com/weatherapi/topics/weather-underground-api-changes + ############## # Bibliotheken +import logging +import time import os import datetime +import locale import codecs -import urllib.request +import urllib.request import json import untangle import MySQLdb +###################### +# Deutsches Zeitformat +locale.setlocale(locale.LC_TIME, "de_DE.UTF-8") + + ########### # Variablen -WEATHER_URL = "http://api.wunderground.com/api/" -WEATHER_KEY = "abcdef0123456789" # 500 quests per day +WEATHER_URL = "https://api.darksky.net/forecast" +WEATHER_KEY = "aabbccddeeff11223344556677889900" CITY = "Münchberg, Bayern, DE" LATITUDE = "50.192900" LONGTITUDE = "11.8035702" PATH = "/root/Scripts" +LOG = "log/cron_kindle-wetter.log" OUTPUT = "/var/www/html/kindle-weather/weatherdata.png" SVG_FILE = "%s/cron_kindle-wetter_preprocess.svg" % PATH SVG_OUTPUT = "%s/cron_kindle-wetter_output.svg" % PATH @@ -32,7 +44,7 @@ ROOMS = ["Bad", "Wohnzimmer"] HOMEMATICIP = "192.168.1.66" -DEVICES = 2390,2465,2541 # Wohnzimmer (Temp), Bad (Temp), Garten (Wettersensor) +DEVICES = 2390,2465,7404 # Wohnzimmer (Temp), Bad (Temp), Garten (Wettersensor) SQLHOST = "localhost" SQLUSER = "weatherdata" @@ -41,214 +53,310 @@ SQLTAB = "homematic" +################# +# Protokollierung +logging.basicConfig( + filename=PATH + '/' + LOG, + level=logging.INFO, + #level=logging.WARNING, + format= '[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s', + #datefmt='%H:%M:%S' +) +console = logging.StreamHandler() +console.setLevel(logging.ERROR) +logging.getLogger('').addHandler(console) +logger = logging.getLogger(__name__) +logging.info("SCRIPT START") + + ############ # Funktionen def _exec(cmd): - rc = os.system(cmd) - if (rc != 0): - print("`%s` failed with error %d" % (cmd, rc)) - exit(rc) + rc = os.system(cmd) + if (rc != 0): + print("`%s` failed with error %d" % (cmd, rc)) + exit(rc) + +def asInteger(output, id, data, addi): + output = output.replace(id, str('%.0f%s' % (float(data), addi))) + return(output) + +def asIntegerTenOrMinusTen(output, id, data, addi): + if float(data) <= -10 or float(data) >= 10: + output = output.replace(id, str('%.0f%s' % (float(data), addi))) + else: + output = output.replace(id, str('%s%s' % (data, addi))) + return(output) + +def replace_daily(output, id, dataday, dataicon, datalow, datahigh, datawind, datarain, datarainint): + output = output.replace("$D" + id, str(dataday + ".")) + output = output.replace("$I" + id, str(dataicon)) + output = output.replace("$L" + id, str('%.0f%s' % (float(datalow), "°"))) + output = output.replace("$H" + id, str('%.0f%s' % (float(datahigh), "°"))) + output = output.replace("$W" + id, str('%.0f' % (float(datawind)))) + #output = output.replace("$P" + id, str('%.2d' % (float(datarain)))) + output = output.replace("$P" + id, str('%.0f' % (float(datarain)))) + output = output.replace("$M" + id, str('%.1f' % (float(datarainint)))) + return(output) + +def replace_hourly(output, id, datatime, dataicon, datarain, datatemp): + output = output.replace("$K" + id, str(datatime)) + output = output.replace("$J" + id, str(dataicon)) + output = output.replace("$T" + id, str('%.0f%s' % (float(datatemp), "°"))) + if datarain >= 30 or dataicon == "rain": + output = output.replace("$R" + id, str('%.0f%s' % (float(datarain), "%"))) + else: + output = output.replace("$R" + id, str("")) + return(output) def sqlinsert(cursor, DEVICE, datapoint, datapointid, value): - sql = "INSERT INTO %s (deviceid, datapointid, datapoint, value) VALUES ('%s', '%s', '%s', '%s')" % (SQLTAB, DEVICE, datapointid, datapoint, value) - cursor.execute(sql) - db.commit() + sql = "INSERT INTO %s (deviceid, datapointid, datapoint, value) VALUES ('%s', '%s', '%s', '%s')" % (SQLTAB, DEVICE, datapointid, datapoint, value) + cursor.execute(sql) + db.commit() def sqlminmax(cursor, datapointid, sort, decimal): - cursor.execute( - "SELECT value FROM %s WHERE datapointid = %s AND DATE(timestamp) = DATE(NOW()) ORDER BY value + 0 %s LIMIT 1" % - (SQLTAB, datapointid, sort)) - for select in cursor.fetchall(): - #return('%.%sf' % (float(select[0]), decimal)) - return('%.{0}f'.format(decimal) % select[0]) + cursor.execute( + "SELECT value FROM %s WHERE datapointid = %s AND DATE(timestamp) = DATE(NOW()) ORDER BY value + 0 %s LIMIT 1" % + (SQLTAB, datapointid, sort)) + for select in cursor.fetchall(): + #return('%.%sf' % (float(select[0]), decimal)) + return('%.{0}f'.format(decimal) % select[0]) ##################### -# Aktuelle Wetterlage -# http://api.wunderground.com/api/abcdef0123456789/conditions/q/50.192900,11.8035702.json -conditions = urllib.request.urlopen( - "%s/%s/conditions/q/%s,%s.json" % - (WEATHER_URL, WEATHER_KEY, LATITUDE, LONGTITUDE)) -json_conditions = conditions.read().decode('utf-8') -parsed_conditions = json.loads(json_conditions) - - -############ -# Astronomie -# http://api.wunderground.com/api/abcdef0123456789/astronomy/q/50.192900,11.8035702.json -astronomy = urllib.request.urlopen( - "%s/%s/astronomy/q/%s,%s.json" % - (WEATHER_URL, WEATHER_KEY, LATITUDE, LONGTITUDE)) -json_astronomy = astronomy.read().decode('utf-8') -parsed_astronomy = json.loads(json_astronomy) - - -################## -# Wettervorhersage -# http://api.wunderground.com/api/abcdef0123456789/forecast/q/50.192900,11.8035702.json -forecast = urllib.request.urlopen( - "%s/%s/forecast/q/%s,%s.json" % - (WEATHER_URL, WEATHER_KEY, LATITUDE, LONGTITUDE)) -json_forecast = forecast.read().decode('utf-8') -parsed_forecast = json.loads(json_forecast) -forecast_list = [] -for forecast_data in parsed_forecast['forecast']['simpleforecast']['forecastday']: - forecast_perday = [ - forecast_data['date']['weekday'] - .replace('Monday', 'Montag') - .replace('Tuesday', 'Dienstag') - .replace('Wednesday', 'Mittwoch') - .replace('Thursday', 'Donnerstag') - .replace('Friday', 'Freitag') - .replace('Saturday', 'Samstag') - .replace('Sunday', 'Sonntag'), - forecast_data['icon'], - forecast_data['high']['celsius'], - forecast_data['low']['celsius'] - ] - forecast_list.append(forecast_perday) - # # 0=today, 1=tomorrow, etc. - # forecast_list[1][2] = temp high for tomorrow +# API-Abfrage +# https://api.darksky.net/forecast/44d7d38433d8bb43f54895bdd65aa32d/50.192900,11.8035702?&units=ca&lang=de +tries = 0 +max_tries = 5 +while tries < max_tries: + try: + apidata = urllib.request.urlopen( + "%s/%s/%s,%s?&units=ca&lang=de" % + (WEATHER_URL, WEATHER_KEY, LATITUDE, LONGTITUDE)) + json_apidata = apidata.read().decode('utf-8') + parsed_apidata = json.loads(json_apidata) + logging.info("OK | dark sky api quest successfully") + + + # Now + weatherdata_now_text = parsed_apidata['currently']['summary'][:20] + (parsed_apidata['currently']['summary'][20:] and '...') + weatherdata_now_icon = parsed_apidata['currently']['icon'] + logging.info("- weatherdata_now | summary: %s" % (weatherdata_now_text)) + logging.info("- weatherdata_now | icon: %s" % (weatherdata_now_icon)) + + + # Astronomie + astronomy_today_sunrise = datetime.datetime.fromtimestamp(int(parsed_apidata['daily']['data'][0]['sunriseTime'])).strftime("%H:%M") + astronomy_today_sunset = datetime.datetime.fromtimestamp(int(parsed_apidata['daily']['data'][0]['sunsetTime'])).strftime("%H:%M") + astronomy_today_moonphase = parsed_apidata['daily']['data'][0]['moonPhase']*100 + + if float(astronomy_today_moonphase) <= 2 or float(astronomy_today_moonphase) >= 98: + astronomy_today_moonphase_icon = "moon-0" + if float(astronomy_today_moonphase) >= 3 and float(astronomy_today_moonphase) <= 17: + astronomy_today_moonphase_icon = "moon-waxing-25" + if float(astronomy_today_moonphase) >= 18 and float(astronomy_today_moonphase) <= 32: + astronomy_today_moonphase_icon = "moon-waxing-50" + if float(astronomy_today_moonphase) >= 33 and float(astronomy_today_moonphase) <= 47: + astronomy_today_moonphase_icon = "moon-waxing-75" + if float(astronomy_today_moonphase) >= 48 and float(astronomy_today_moonphase) <= 52: + astronomy_today_moonphase_icon = "moon-100" + if float(astronomy_today_moonphase) >= 53 and float(astronomy_today_moonphase) <= 67: + astronomy_today_moonphase_icon = "moon-waning-75" + if float(astronomy_today_moonphase) >= 68 and float(astronomy_today_moonphase) <= 82: + astronomy_today_moonphase_icon = "moon-waning-50" + if float(astronomy_today_moonphase) >= 83 and float(astronomy_today_moonphase) <= 97: + astronomy_today_moonphase_icon = "moon-waning-25" + + logging.info("- astronomy_today | sunrise: %s, sunset %s" % (astronomy_today_sunrise, astronomy_today_sunset)) + logging.info("- astronomy_today | moonphase_icon: %s, moonphase: %s%%" % (astronomy_today_moonphase_icon, astronomy_today_moonphase)) + + + # Forecast Daily + weatherdata_forecast_date = [] + weatherdata_forecast_weekday = [] + weatherdata_forecast_icon = [] + weatherdata_forecast_temphigh = [] + weatherdata_forecast_templow = [] + weatherdata_forecast_wind = [] + weatherdata_forecast_rain = [] + weatherdata_forecast_rainint= [] + for i in range(0, 3): + weatherdata_forecast_date.append(datetime.datetime.fromtimestamp(int(parsed_apidata['daily']['data'][i]['time'])).strftime("%d.%m.")) + weatherdata_forecast_weekday.append(datetime.datetime.fromtimestamp(int(parsed_apidata['daily']['data'][i]['time'])).strftime("%a")) + weatherdata_forecast_icon.append(parsed_apidata['daily']['data'][i]['icon']) + weatherdata_forecast_temphigh.append(parsed_apidata['daily']['data'][i]['temperatureHigh']) + weatherdata_forecast_templow.append(parsed_apidata['daily']['data'][i]['temperatureLow']) + weatherdata_forecast_wind.append(parsed_apidata['daily']['data'][i]['windGust']) + weatherdata_forecast_rain.append(parsed_apidata['daily']['data'][i]['precipProbability']*100) + weatherdata_forecast_rainint.append(parsed_apidata['daily']['data'][i]['precipIntensityMax']) + logging.info("- forecast_daily | today: %s, %s, icon: %s, high: %s, low: %s, wind: %s km/h, pop: %s%%, rain: %s mm" % (weatherdata_forecast_weekday[i], weatherdata_forecast_date[i], weatherdata_forecast_icon[i], weatherdata_forecast_temphigh[i], weatherdata_forecast_templow[i], weatherdata_forecast_wind[i], weatherdata_forecast_rain[i], weatherdata_forecast_rainint[i])) + + + # Forecast Hourly + weatherdata_hourly_time = [] + weatherdata_hourly_icon = [] + weatherdata_hourly_temp = [] + weatherdata_hourly_wind = [] + weatherdata_hourly_rain = [] + for i in range(0, 24): + weatherdata_hourly_time.append(datetime.datetime.fromtimestamp(int(parsed_apidata['hourly']['data'][i]['time'])).strftime("%H")) + weatherdata_hourly_icon.append(parsed_apidata['hourly']['data'][i]['icon']) + weatherdata_hourly_temp.append(parsed_apidata['hourly']['data'][i]['temperature']) + weatherdata_hourly_wind.append(parsed_apidata['hourly']['data'][i]['windGust']) + weatherdata_hourly_rain.append(parsed_apidata['hourly']['data'][i]['precipProbability']*100) + logging.info("- weatherdata_hourly | hour: %s, icon: %s, temp: %s, wind: %s km/h, pop: %s%%" % (weatherdata_hourly_time[i], weatherdata_hourly_icon[i], weatherdata_hourly_temp[i], weatherdata_hourly_wind[i], weatherdata_hourly_rain[i])) + + except urllib.error.HTTPError as e: + tries = tries + 1 + logging.warn("WARN | dark sky api quest not successfully - error <%s> on trial no %s" % (e.code, tries)) + time.sleep(10) + continue + + else: + break + +else: + logging.error("FAIL |  dark sky api quest failed") ################ # Homematic CCU2 # http://192.168.1.66/addons/xmlapi/state.cgi?device_id=2390,2465 db = MySQLdb.connect( - SQLHOST, - SQLUSER, - SQLPW, - SQLDB) + SQLHOST, + SQLUSER, + SQLPW, + SQLDB) cursor = db.cursor() for DEVICE in DEVICES: - xmldoc = untangle.parse( - "http://%s/addons/xmlapi/state.cgi?device_id=%s" % - (HOMEMATICIP, DEVICE)) - - for ITEMS in xmldoc.state.device.channel: - if ITEMS.get_elements('datapoint'): - for DATA in ITEMS.datapoint: - datapointname = DATA['name'] - - ### Temperatur - if datapointname.endswith('.ACTUAL_TEMPERATURE'): - datapointid = DATA['ise_id'] - datapoint = DATA['name'] - value = DATA['value'] - - sqlinsert(cursor, DEVICE, datapoint, datapointid, value) - - # WZ - if DEVICE == 2390: - wzt = '%.1f' % float(value) - wth = sqlminmax(cursor, datapointid, "DESC", 1) - wtl = sqlminmax(cursor, datapointid, "ASC", 1) - - # Bad - if DEVICE == 2465: - bat = '%.1f' % float(value) - bth = sqlminmax(cursor, datapointid, "DESC", 1) - btl = sqlminmax(cursor, datapointid, "ASC", 1) - - # Garten - if DEVICE == 2541: - gtt = '%.1f' % float(value) - gth = sqlminmax(cursor, datapointid, "DESC", 1) - gtl = sqlminmax(cursor, datapointid, "ASC", 1) - - ### Luftfeuchtigkeit - if datapointname.endswith('.HUMIDITY'): - datapointid = DATA['ise_id'] - datapoint = DATA['name'] - value = DATA['value'] - - sqlinsert(cursor, DEVICE, datapoint, datapointid, value) - - # WZ - if DEVICE == 2390: - wzh = '%.0f' % float(value) - whh = sqlminmax(cursor, datapointid, "DESC", 0) - whl = sqlminmax(cursor, datapointid, "ASC", 0) - - # Bad - if DEVICE == 2465: - bah = '%.0f' % float(value) - bhh = sqlminmax(cursor, datapointid, "DESC", 0) - bhl = sqlminmax(cursor, datapointid, "ASC", 0) - - # Garten - if DEVICE == 2541: - gah = '%.0f' % float(value) - ghh = sqlminmax(cursor, datapointid, "DESC", 0) - ghl = sqlminmax(cursor, datapointid, "ASC", 0) - - ### Niederschlagsmenge - # Ohne "Reset" wird die Niederschlagsmenge immer zum letzten Wert addiert - wächst immer weiter an, wird nicht auf 0 gesetzt. - if datapointname.endswith('.RAIN_COUNTER'): - datapointid = DATA['ise_id'] - datapoint = DATA['name'] - value = DATA['value'] - - sqlinsert(cursor, DEVICE, datapoint, datapointid, value) - - # Garten - if DEVICE == 2541: - cursor.execute( - "SELECT maxi-mini FROM (SELECT MIN(value) mini, MAX(value) maxi FROM (SELECT value FROM %s WHERE datapointid = %s AND timestamp >= NOW() - INTERVAL 1 DAY ) mm1) mm2" % - (SQLTAB, datapointid)) - for select in cursor.fetchall(): - grr = '%.1f' % float(select[0]) - - ### Windrichtung - if datapointname.endswith('.WIND_DIR'): - datapointid = DATA['ise_id'] - datapoint = DATA['name'] - value = DATA['value'] - - sqlinsert(cursor, DEVICE, datapoint, datapointid, value) - - # Garten - if DEVICE == 2541: - gwdtemp = '%.1f' % float(value) - - if 0 <= float(gwdtemp) <= 22.4: - gwd = "N" - elif 22.5 <= float(gwdtemp) <= 67.4: - gwd = "NO" - elif 67.5 <= float(gwdtemp) <= 112.4: - gwd = "O" - elif 112.5 <= float(gwdtemp) <= 157.4: - gwd = "SO" - elif 157.5 <= float(gwdtemp) <= 202.4: - gwd = "S" - elif 202.5 <= float(gwdtemp) <= 247.4: - gwd = "SW" - elif 247.5 <= float(gwdtemp) <= 292.4: - gwd = "W" - elif 292.5 <= float(gwdtemp) <= 337.4: - gwd = "NW" - elif 337.5 <= float(gwdtemp) <= 360: - gwd = "N" - - ### Windgeschwindigkeit - if datapointname.endswith('.WIND_SPEED'): - datapointid = DATA['ise_id'] - datapoint = DATA['name'] - value = DATA['value'] - - sqlinsert(cursor, DEVICE, datapoint, datapointid, value) - - # Garten - if DEVICE == 2541: - gws = '%.1f' % float(value) - - cursor.execute( - "SELECT value FROM %s WHERE datapointid = %s AND DATE(timestamp) = DATE(NOW()) ORDER BY value + 0 DESC LIMIT 1" % - (SQLTAB, datapointid)) - for select in cursor.fetchall(): - gwh = '%.0f' % float(select[0]) + xmldoc = untangle.parse( + "http://%s/addons/xmlapi/state.cgi?device_id=%s" % + (HOMEMATICIP, DEVICE)) + + for ITEMS in xmldoc.state.device.channel: + if ITEMS.get_elements('datapoint'): + for DATA in ITEMS.datapoint: + datapointname = DATA['name'] + + ### Temperatur + if datapointname.endswith('.ACTUAL_TEMPERATURE'): + datapointid = DATA['ise_id'] + datapoint = DATA['name'] + value = DATA['value'] + + sqlinsert(cursor, DEVICE, datapoint, datapointid, value) + + # WZ + if DEVICE == 2390: + wzt = '%.1f' % float(value) + wth = sqlminmax(cursor, datapointid, "DESC", 1) + wtl = sqlminmax(cursor, datapointid, "ASC", 1) + + # Bad + if DEVICE == 2465: + bat = '%.1f' % float(value) + bth = sqlminmax(cursor, datapointid, "DESC", 1) + btl = sqlminmax(cursor, datapointid, "ASC", 1) + + # Garten + if DEVICE == 7404: + gtt = '%.1f' % float(value) + gth = sqlminmax(cursor, datapointid, "DESC", 1) + gtl = sqlminmax(cursor, datapointid, "ASC", 1) + + ### Luftfeuchtigkeit + if datapointname.endswith('.HUMIDITY'): + datapointid = DATA['ise_id'] + datapoint = DATA['name'] + value = DATA['value'] + + sqlinsert(cursor, DEVICE, datapoint, datapointid, value) + + # WZ + if DEVICE == 2390: + wzh = '%.0f' % float(value) + whh = sqlminmax(cursor, datapointid, "DESC", 0) + whl = sqlminmax(cursor, datapointid, "ASC", 0) + + # Bad + if DEVICE == 2465: + bah = '%.0f' % float(value) + bhh = sqlminmax(cursor, datapointid, "DESC", 0) + bhl = sqlminmax(cursor, datapointid, "ASC", 0) + + # Garten + if DEVICE == 7404: + gah = '%.0f' % float(value) + ghh = sqlminmax(cursor, datapointid, "DESC", 0) + ghl = sqlminmax(cursor, datapointid, "ASC", 0) + + ### Niederschlagsmenge + # Ohne "Reset" wird die Niederschlagsmenge immer zum letzten Wert addiert - wächst immer weiter an, wird nicht auf 0 gesetzt. + if datapointname.endswith('.RAIN_COUNTER'): + datapointid = DATA['ise_id'] + datapoint = DATA['name'] + value = DATA['value'] + + sqlinsert(cursor, DEVICE, datapoint, datapointid, value) + + # Garten + if DEVICE == 7404: + cursor.execute( + "SELECT maxi-mini FROM (SELECT MIN(value) mini, MAX(value) maxi FROM (SELECT value FROM %s WHERE datapointid = %s AND timestamp >= NOW() - INTERVAL 1 DAY ) mm1) mm2" % + (SQLTAB, datapointid)) + for select in cursor.fetchall(): + grr = '%.1f' % float(select[0]) + + ### Windrichtung + if datapointname.endswith('.WIND_DIR'): + datapointid = DATA['ise_id'] + datapoint = DATA['name'] + value = DATA['value'] + + sqlinsert(cursor, DEVICE, datapoint, datapointid, value) + + # Garten + if DEVICE == 7404: + gwdtemp = '%.1f' % float(value) + + if 0 <= float(gwdtemp) <= 22.4: + gwd = "N" + elif 22.5 <= float(gwdtemp) <= 67.4: + gwd = "NO" + elif 67.5 <= float(gwdtemp) <= 112.4: + gwd = "O" + elif 112.5 <= float(gwdtemp) <= 157.4: + gwd = "SO" + elif 157.5 <= float(gwdtemp) <= 202.4: + gwd = "S" + elif 202.5 <= float(gwdtemp) <= 247.4: + gwd = "SW" + elif 247.5 <= float(gwdtemp) <= 292.4: + gwd = "W" + elif 292.5 <= float(gwdtemp) <= 337.4: + gwd = "NW" + elif 337.5 <= float(gwdtemp) <= 360: + gwd = "N" + + ### Windgeschwindigkeit + if datapointname.endswith('.WIND_SPEED'): + datapointid = DATA['ise_id'] + datapoint = DATA['name'] + value = DATA['value'] + + sqlinsert(cursor, DEVICE, datapoint, datapointid, value) + + # Garten + if DEVICE == 7404: + gws = '%.1f' % float(value) + + cursor.execute( + "SELECT value FROM %s WHERE datapointid = %s AND DATE(timestamp) = DATE(NOW()) ORDER BY value + 0 DESC LIMIT 1" % + (SQLTAB, datapointid)) + for select in cursor.fetchall(): + gwh = '%.0f' % float(select[0]) ############################################################ @@ -257,66 +365,71 @@ def sqlminmax(cursor, datapointid, sort, decimal): for ROOM in ROOMS: - OUTPUT = "/var/www/html/kindle-weather/weatherdata-%s.png" % (ROOM.lower()) - ROOM1 = "Innen (%s)" % (ROOM) - - output = codecs.open(SVG_FILE, "r", encoding="utf-8").read() - - output = output.replace("$TIME", datetime.datetime.now().strftime("%Y-%m-%d %H:%M")) - output = output.replace("$LOC", str(CITY)) - output = output.replace("$I0", str(parsed_conditions['current_observation']['icon'])) - output = output.replace("$CT", str(gtt)) - output = output.replace("$CHH", str(gth)) - output = output.replace("$CHL", str(gtl)) - output = output.replace("$CL", str(gah)) - output = output.replace("$CAH", str(ghh)) - output = output.replace("$CAL", str(ghl)) - output = output.replace("$CW", str(gws)) - output = output.replace("$CD", str(gwd)) - output = output.replace("$CHW", str(gwh)) - output = output.replace("$AQ", str("1234")) - output = output.replace("$QL", str("546")) - output = output.replace("$QH", str("2345")) - output = output.replace("$CR", str(grr)) - output = output.replace("$D1", str("Heute")) - output = output.replace("$I1", str(forecast_list[0][1])) - output = output.replace("$L1", str(forecast_list[0][3])) - output = output.replace("$H1", str(forecast_list[0][2])) - output = output.replace("$D2", str("Morgen")) - output = output.replace("$I2", str(forecast_list[1][1])) - output = output.replace("$L2", str(forecast_list[1][3])) - output = output.replace("$H2", str(forecast_list[1][2])) - output = output.replace("$D3", str(forecast_list[2][0])) - output = output.replace("$I3", str(forecast_list[2][1])) - output = output.replace("$L3", str(forecast_list[2][3])) - output = output.replace("$H3", str(forecast_list[2][2])) - output = output.replace("$sunrise", str("%s:%s" % (parsed_astronomy['sun_phase']['sunrise']['hour'], parsed_astronomy['sun_phase']['sunrise']['minute']))) - output = output.replace("$sunset", str("%s:%s" % (parsed_astronomy['sun_phase']['sunset']['hour'], parsed_astronomy['sun_phase']['sunset']['minute']))) - - if ROOM == "Bad": - ROOM2 = "Wohnzimmer" - output = output.replace("$ROOM1", str(ROOM1)) - output = output.replace("$ROOM2", str(ROOM2)) - output = output.replace("$BT", str(bat)) - output = output.replace("$BSL", str(btl)) - output = output.replace("$BSH", str(bth)) - output = output.replace("$BH", str(bah)) - output = output.replace("$BBH", str(bhh)) - output = output.replace("$BBL", str(bhl)) - - if ROOM == "Wohnzimmer": - ROOM2 = "" - output = output.replace("$ROOM1", str(ROOM1)) - output = output.replace("$ROOM2", str(ROOM2)) - output = output.replace("$BT", str(wzt)) - output = output.replace("$BSL", str(wtl)) - output = output.replace("$BSH", str(wth)) - output = output.replace("$BH", str(wzh)) - output = output.replace("$BBH", str(whh)) - output = output.replace("$BBL", str(whl)) - - codecs.open(SVG_OUTPUT, "w", encoding="utf-8").write(output) - _exec("rsvg-convert --background-color=white -o %s %s" % (TMP_OUTPUT, SVG_OUTPUT)) - _exec("pngcrush -c 0 -ow %s 1>/dev/null 2>&1" % TMP_OUTPUT) - _exec("mv -f '%s' '%s'" % (TMP_OUTPUT, OUTPUT)) - _exec("rm -f '%s'" % SVG_OUTPUT) + OUTPUT = "/var/www/html/kindle-weather/weatherdata-%s.png" % (ROOM.lower()) + ROOM1 = "Innen (%s)" % (ROOM) + + output = codecs.open(SVG_FILE, "r", encoding="utf-8").read() + + output = output.replace("$TEXT", str(weatherdata_now_text)) + output = output.replace("$I0", str(weatherdata_now_icon)) + output = asInteger(output, "$CT", gtt, "°") + output = output.replace("$CHH", str(gth + "°")) + output = output.replace("$CHL", str(gtl + "°")) + output = output.replace("$CL", str(gah + "")) + output = output.replace("$CAH", str(ghh + "")) + output = output.replace("$CAL", str(ghl + "")) + output = asInteger(output, "$CW", gws, "") + output = output.replace("$CD", str(gwd)) + output = output.replace("$CHW", str(gwh)) + output = output.replace("$CR", str(grr)) + output = output.replace("$sunrise", str(astronomy_today_sunrise)) + output = output.replace("$sunset", str(astronomy_today_sunset)) + output = output.replace("$MO", str('%.2d' % (float(astronomy_today_moonphase)))) + output = output.replace("$MI", str(astronomy_today_moonphase_icon)) + + output = output.replace("$AQ", str("1234")) + output = output.replace("$QL", str("546")) + output = output.replace("$QH", str("2345")) + + output = output.replace("$TIME", datetime.datetime.now().strftime("%Y-%m-%d %H:%M")) + output = output.replace("$LOC", str(CITY)) + + for i in range(0, 3): + output = replace_daily(output, str(i+1), weatherdata_forecast_weekday[i], weatherdata_forecast_icon[i], weatherdata_forecast_templow[i], weatherdata_forecast_temphigh[i], weatherdata_forecast_wind[i], weatherdata_forecast_rain[i], weatherdata_forecast_rainint[i]) + + for i in range(0, 24): + output = replace_hourly(output, str(i+1).zfill(2), weatherdata_hourly_time[i], weatherdata_hourly_icon[i], weatherdata_hourly_rain[i], weatherdata_hourly_temp[i]) + + if ROOM == "Bad": + ROOM2 = "Wohnzimmer" + output = output.replace("$ROOM1", str(ROOM1)) + output = output.replace("$ROOM2", str(ROOM2)) + output = output.replace("$BT", str(bat + "°")) + output = output.replace("$BSL", str(btl + "°")) + output = output.replace("$BSH", str(bth + "°")) + #output = asIntegerTenOrMinusTen(output, "$BSL", btl, "°") + #output = asIntegerTenOrMinusTen(output, "$BSH", bth, "°") + output = output.replace("$BH", str(bah + "")) + output = output.replace("$BBH", str(bhh + "")) + output = output.replace("$BBL", str(bhl + "")) + + if ROOM == "Wohnzimmer": + ROOM2 = "" + output = output.replace("$ROOM1", str(ROOM1)) + output = output.replace("$ROOM2", str(ROOM2)) + output = output.replace("$BT", str(wzt + "°")) + output = output.replace("$BSL", str(wtl + "°")) + output = output.replace("$BSH", str(wth + "°")) + #output = asIntegerTenOrMinusTen(output, "$BSL", wtl, "°") + #output = asIntegerTenOrMinusTen(output, "$BSH", wth, "°") + output = output.replace("$BH", str(wzh + "")) + output = output.replace("$BBH", str(whh + "")) + output = output.replace("$BBL", str(whl + "")) + + codecs.open(SVG_OUTPUT, "w", encoding="utf-8").write(output) + _exec("rsvg-convert --background-color=white -o %s %s" % (TMP_OUTPUT, SVG_OUTPUT)) + _exec("pngcrush -c 0 -ow %s 1>/dev/null 2>&1" % TMP_OUTPUT) + _exec("mv -f '%s' '%s'" % (TMP_OUTPUT, OUTPUT)) + _exec("rm -f '%s'" % SVG_OUTPUT) + +logging.info("SCRIPT END\n") diff --git a/Server/cron_kindle-wetter_preprocess.svg b/Server/cron_kindle-wetter_preprocess.svg index 030840b..e3973e8 100644 --- a/Server/cron_kindle-wetter_preprocess.svg +++ b/Server/cron_kindle-wetter_preprocess.svg @@ -10,211 +10,406 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - -$ROOM1 -$ROOM2 - - - -MIN - -$BBL - -MAX - -$BBH - -$BH - -in % - - - - -$QH - -MAX - -$QL - -MIN - - +$ROOM1 +$ROOM2 + +MIN + +$BBL% + +MAX + +$BBH% + +$BH +% + + +Luftfeuchtigkeit (%) + +$QH + +MAX + +$QL + +MIN + + $AQ -in ppm - - - - - - -$BSH - -MAX - -$BSL - -MIN - - + +Luftqualität (ppm) + +$BSH + +MAX + +$BSL + +MIN + + $BT -in °C - - - - - - -Außen - - - -MIN - -$CAL - -MAX - -$CAH - -$CL - -in % - - - - - - - -MAX - - -$CHW - - -$CW -$CD - - -in km/h - - -$CR - -in mm/24h - - - - - - - -$CHL -MAX -$CHH - + +Temperatur (°C) + + + +MAX + + +$CHW + + + +$CW +$CD + + +Windgeschw. (km/h) + + +$CR +¤ + + +Regenmenge (mm/24h) + +$CHL +MAX +$CHH + MIN - + $CT -in °C - - - -$L1 + + + + + + + + + + + + + + + +$sunrise +$sunset + +$TIME + +$LOC + + + +$K03 Uhr + + +$K02 Uhr + + +$K05 Uhr + + +$K11 Uhr + + +$K07 Uhr + + +$K09 Uhr + + +$K12 Uhr + + +$K08 Uhr + + +$K10 Uhr + + +$K06 Uhr + + +$K04 Uhr + + +$K01 Uhr + + +$T03 + + +$T02 + + +$T05 + + +$T11 + + +$T07 + + +$T09 + + +$T12 + + +$T08 + + +$T10 + + +$T06 + + +$T04 + + +$T01 + + +$R01 + + +$R11 + + +$R12 + + +$R09 + + +$R08 + + +$R06 + + +$R05 + + +$R04 + + +$R03 + + +$R02 + + +$R10 + + +$R07 + + + + + + + + + + + + + + +$K15 Uhr + + +$K14 Uhr + + +$K17 Uhr + + +$K23 Uhr + + +$K19 Uhr + + +$K21 Uhr + + +$K24 Uhr + + +$K20 Uhr + + +$K22 Uhr + + +$K18 Uhr + + +$K16 Uhr + + +$K13 Uhr + + +$T15 + + +$T14 + + +$T17 + + +$T23 + + +$T19 + + +$T21 + + +$T24 + + +$T20 + + +$T22 + + +$T18 + + +$T16 + + +$T13 - -$H1 + +$R13 - -MIN + +$R23 - -°C + +$R24 - -MAX + +$R21 - - -$D1 + +$R20 + + +$R18 + + +$R17 - -$L2 + +$R16 - -$H2 + +$R15 - -MIN + +$R14 - -°C + +$R22 - -MAX + +$R19 - - -$D2 + +$CAH% + +MAX -$L3 -$H3 - -MIN +$CAL% + +MIN - -°C + +$CL +% - -MAX + +Luftfeuchtigkeit (%) - - -$D3 + +$D1 +$H1 +$L1 +$P1% +$W1 +$M1¤ + +DarkSky API + HomematicIP Wettersensor Pro + + +Wochentag +Höchsttemp-eratur (°C) +Tiefsttemp-eratur (°C) +Windgeschw.(km/h) +Regen-wsh. (%) +Regenmenge(mm) + +$D2 +$H2 +$L2 +$P2% +$W2 +$M2¤ + +$D3 +$H3 +$L3 +$P3% +$W3 +$M3¤ + +$MO% +$TEXT bei +Heute + + - - - - -$sunrise -$sunset - - - -$TIME -$LOC -