Wetterstation in die Visualisierung einbinden - Mokonas Technik-Ecke (2024)

Da viele Funktionen im und am Haus vom Wetter abhängig sind, haben wir überlegt, wie wir die Wetterdaten am besten bekommen können. Die eine Überlegung war es, aus dem Internet die entsprechenden Daten zu parsen. Leider sind die Daten doch recht ungenau, da die nächste offizielle Wetterstation sehr weit entfernt ist. Also musste es eine eigene Wetterstation sein. Die Anforderung war dabei, dass wir sie in unser Eco-System einbinden können.

Wetterstation Renkforce WH2600

Nach einiger Recherche sind wir auf die Wetterstation Renkforce WH2600 von Conrad gestoßen. Diese bringt einen kleinen Empfänger mit, der eine Webseite mit den Wetterdaten bereitstellt. das klang nach einer einfachen Möglichkeit an die Wetterdaten zu kommen.

Wetterstation in die Visualisierung einbinden - Mokonas Technik-Ecke (1)

Die Wetterstation wurden also im Garten aufgebaut und die kleine Empfangsstation an Netzwerk im Haus angebunden. Sofort konnten wir uns die Wetterdaten ansehen, die auf der internen Webseite zur Verfügung standen.

Update der Firmware

Leider war die ausgelieferte Firmware nicht allzu stabil. Vor allem fehlte ihr aber die Anbindung an WeatherUnderground, welches wir auch gerne anbinden wollten. Deswegen haben wir recherchiert und herausgefunden, dass die Wetterstation auch mit der Firmware von Ambient Weather kompatibel sein soll. Also haben wir es gewagt und das Update eingespielt. Die folgende Anleitung bezieht sich dabei auf die Firmware 4.5.8.

Daten auslesen und in die Datenbank speichern

Die Wetterstation stellt eine Webseite zur Verfügung die wie folgt aussieht:

Wetterstation in die Visualisierung einbinden - Mokonas Technik-Ecke (2)

Wie man sehen kann, werden die Daten in schreibgeschützen Input-Feldern dargestellt. Mit der Untersuchen Funktion des Browsers kann man sehr einfach den Namen der Felder herausfinden. So hat das Feld „Wind Direction“ den Namen „windir„.

Diese Information hilft uns, einen kleinen Parser zu schreiben, der alle Felder ausliest. Als erstes parsen wir dazu die Webseite mit Hilfe von urllib.

import urllib.requestURL_FOR_DATA = 'http://192.168.178.251/livedata.htm' with urllib.request.urlopen(URL_FOR_DATA) as response: html = response.read()

Weiterhin benötigen wir für jedes Feld eine Regular Expression um es auslesen zu können. Das sieht dann ungefähr so aus:

regex_temp = re.compile('<input name="outTemp".*?value="(.*?)".*?>')

Eine kleine Hilfsfunktion hilft uns dabei die Daten zu parsen.

 def _get_value(self, text, regex): match = re.search(regex, str(text)) if match: if match.group(1) in ('----', '--'): return -99 return match.group(1) else: return 0

Damit können wir jetzt die HTML Seite durchsuchen und den gefunden Wert parsen.

temp = _get_value(html, regex_temp)

Damit ist das schwerste schon erledigt. Denn so kommen wir einfach an alle Daten der Wetterstation. Jetzt liegen noch zwei Aufgaben vor uns: Zum einen wollen wir die Daten visualisieren und zum Anderen wollen wir sie regelmäßig für eine Statistik in die Datenbank packen.

Daten der Wetterstation in die Datenbank schreiben

Als erstes schreiben wir die Daten in die Datenbank. Dazu nutzen wir die Mechanismen von Django aus. Dazu benötigen wir als erstes ein Model, dass die Struktur der Datenbank abbildet. Das Model sieht wie folgt aus:

from django.db import modelsclass WeatherData(models.Model): timestamp = models.DateTimeField(editable=False, primary_key=True) absolute_pressure = models.FloatField(editable=False) relative_pressure = models.FloatField(editable=False) temperature = models.FloatField(editable=False) humidity = models.FloatField(editable=False) wind_direction = models.FloatField(editable=False) wind_speed = models.FloatField(editable=False) wind_gust = models.FloatField(editable=False) solar_radiation = models.FloatField(editable=False) uv = models.FloatField(editable=False) uv1 = models.FloatField(editable=False) hourly_rain_rate = models.FloatField(editable=False) daily_rain_rate = models.FloatField(editable=False)

Jetzt können wir Daten in die Datenbank packen, indem wir den Save-Befehl für das Datenobjekt verwenden,. Das sieht dann wie folgt aus:

from homeautomation.outdoor_weather.models import WeatherDatadata = WeatherData(timestamp=timezone.now(), temperature=temp, absolute_pressure=abs_press, relative_pressure=rel_press, humidity=hum, wind_direction=wind_dir, wind_speed=wind_speed, wind_gust=wind_gust, solar_radiation=solar, uv=uv, uv1=uv1, hourly_rain_rate=rain_hour, daily_rain_rate=rain_day)data.save()

Damit fehlt nur noch der Teil, diese Aufgabe regelmäßig zu tun. Für Django gibt es ein kleines AddOn, das diese Aufgabe übernehmen kann. Die Bilbliothek heißt django_cron. Mit dieser Bibliothek kann man sehr einfach Cron-Jobs in Django steuern.

Dazu sollte als erstes die settings.py um zwei Einträge erweitert werden. Der erste Eintrag dient dazu, dass unsere Datenbank nicht überfüllt, indem die Logs nach 3 Tagen gelöscht werden. Der zweite Eintrag meldet unsere Cron-Klasse an.

DJANGO_CRON_DELETE_LOGS_OLDER_THAN = 3CRON_CLASSES = [ "homeautomation.crons.weather.WeatherJob",]

Nun muss natürlich noch die Cron-Klasse hinzugefügt werden. Diese besteht aus den oben beschriebenen Funktionen. Zusätzlich wird über die Parameter gesteuert, wie häufig der Job laufen soll.

from django_cron import CronJobBase, Schedulefrom django.utils import timezonefrom homeautomation.outdoor_weather.models import WeatherDataimport urllib.requestimport reclass WeatherJob(CronJobBase): RUN_EVERY_MINS = 1 ALLOW_PARALLEL_RUNS = False schedule = Schedule(run_every_mins=RUN_EVERY_MINS) code = 'homeautomation.WeatherJob' URL_FOR_DATA = 'http://192.168.178.251/livedata.htm' def _get_value(self, text, regex): match = re.search(regex, str(text)) if match: if match.group(1) in ('----', '--'): return -99 return match.group(1) else: return 0 def parse_url(self): with urllib.request.urlopen(self.URL_FOR_DATA) as response: html = response.read() return html def do(self): text = self.parse_url() regex_temp = re.compile('<input name="outTemp".*?value="(.*?)".*?>') regex_abs = re.compile('<input name="AbsPress".*?value="(.*?)".*?>') regex_rel = re.compile('<input name="RelPress".*?value="(.*?)".*?>') regex_hum = re.compile('<input name="outHumi".*?value="(.*?)".*?>') regex_winddir = re.compile('<input name="windir".*?value="(.*?)".*?>') regex_windspeed = re.compile('<input name="windspeed".*?value="(.*?)".*?>') regex_windgust = re.compile('<input name="gustspeed".*?value="(.*?)".*?>') regex_solar = re.compile('<input name="solarrad".*?value="(.*?)".*?>') regex_uv = re.compile('<input name="uv".*?value="(.*?)".*?>') regex_uv1 = re.compile('<input name="uvi".*?value="(.*?)".*?>') regex_hourrain = re.compile('<input name="rainofhourly".*?value="(.*?)".*?>') regex_dailyrain = re.compile('<input name="rainofdaily".*?value="(.*?)".*?>') temp = self._get_value(text, regex_temp) abs_press = self._get_value(text, regex_abs) rel_press = self._get_value(text, regex_rel) hum = self._get_value(text, regex_hum) wind_dir = self._get_value(text, regex_winddir) wind_speed = self._get_value(text, regex_windspeed) wind_gust = self._get_value(text, regex_windgust) solar = self._get_value(text, regex_solar) uv = self._get_value(text, regex_uv) uv1 = self._get_value(text, regex_uv1) rain_hour = self._get_value(text, regex_hourrain) rain_day = self._get_value(text, regex_dailyrain) data = WeatherData(timestamp=timezone.now(), temperature=temp, absolute_pressure=abs_press, relative_pressure=rel_press, humidity=hum, wind_direction=wind_dir, wind_speed=wind_speed, wind_gust=wind_gust, solar_radiation=solar, uv=uv, uv1=uv1, hourly_rain_rate=rain_hour, daily_rain_rate=rain_day) data.save()

Wichtig ist es jetzt nur noch, dass der Cron-Job auch regelmäßig getriggert wird. Dazu auf dem Server am besten in die Crontabs der Befehl manage.py runcrons mit den entsprechenden Pfaden eingebaut. Am besten liest man dazu die Dokumentation von django-crons und schaut sich an, wie solche Aufgaben auf dem eigenen Betriebssystem gestartet werden.

Der Befehl manage.py runcrons hilft aber auch dabei, den eigenen Cron-Job zu testen.

Jetzt sind die aktuellen Daten in der Datenbank. Nun müssen wir sie nur noch darstellen.

Visualisierung der Daten der Wetterstation

Die Daten sollen nun auf den Displays dargestellt werden. Dazu lesen wir aus der Datenbank die letzten Daten aus und übergeben diese an das Template was die Daten darstellt. Das Ergebnis sieht dann so aus:

Wetterstation in die Visualisierung einbinden - Mokonas Technik-Ecke (3)

Als erstes werden also die Daten in Django im View ausgegeben und ans Template weitergereicht. Dabei formatieren wir die Daten, vor allem splitten wir die Daten auf, um an die Kommastellen zu kommen.

class WeatherOverview(View): def get(self, request): data = WeatherData.objects.latest('timestamp') context = dict() context['data'] = data temp = data.temperature if temp < 0: temp = abs(temp) sign = -1 else: sign = 1 context['temperature'] = sign * math.floor(temp), temp % 1 # mehr Daten für den Context formatieren return render(request, 'weather.html', context)

Das Ganze wird dann im Template wie folgt verarbeitet:

 <a href="/outdoor_weather/tempstat/"> <div class="temp"> <div class="big"> <span class="right"> {{temperature.0}}. </span> </div> <div class="big"> <div class="small">°C</div> <div class="small">{{temperature.1|floatformat:2|cut:"0,"}}</div> </div> </div> </a>

Aus diesen Blöcken mit etwas CSS und netten Bildern aus dem KNX UI Iconset lassen sich dann die oben gezeigte Seite bauen.

Wetterstation in die Visualisierung einbinden - Mokonas Technik-Ecke (2024)

References

Top Articles
Latest Posts
Article information

Author: Laurine Ryan

Last Updated:

Views: 6278

Rating: 4.7 / 5 (77 voted)

Reviews: 84% of readers found this page helpful

Author information

Name: Laurine Ryan

Birthday: 1994-12-23

Address: Suite 751 871 Lissette Throughway, West Kittie, NH 41603

Phone: +2366831109631

Job: Sales Producer

Hobby: Creative writing, Motor sports, Do it yourself, Skateboarding, Coffee roasting, Calligraphy, Stand-up comedy

Introduction: My name is Laurine Ryan, I am a adorable, fair, graceful, spotless, gorgeous, homely, cooperative person who loves writing and wants to share my knowledge and understanding with you.