Anleitung:
Raspberry Pi vorbereiten:
- Gruppe für die Wetteranwendung erstellen und User hinzufügen
sudo groupadd weather
sudo adduser pi weather
- Installation der benötigten Libraries
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install python3-pip
pip install pyusb --pre
mkdir ~/weather_data
cd ~/weather_data
sudo pip install pywws
- Station testen
sudo python -m pywws.TestWeatherStation
- Weitere Konfigurationsschritte
Sollen die Wetterdaten möglichst zeitnah in der Zentraleinheit gelogged werden (Minimum ist 1 Minute) und dementsprechend auch von pywws ausgelesen werden, dann lässt sich das Speicherintervall mit folgendem Befehl auf 1 Minute einstellen:
sudo python -m pywws.SetWeatherStation -r 1
Wenn die Wetterstation erst kurz in Betrieb ist, dann kann es sein, dass der DCF Empfänger die Zeit noch nicht synchronisiert hat. Mit dem folgenden Befehl kann man versuchen, die Zeit mit dem Raspberry abzugleichen:
sudo python -m pywws.SetWeatherStation -c
- Damit später für eine eventuelle Datensicherung alles kompakt beianander liegt sollen in dem Unterverzeichnis folgende Dinge landen:
die Konfigurationsdatei für die Verarbeitung der Daten
die aus der Wetterstation ausgelesenen Daten
die von pywws verarbeiteten Daten (stündlich, täglich, monatilche Summen)
die Templates für die Ausgabe der Daten
cd ~
cd weather_data/
mkdir templates
mkdir log
mkdir tmp
mkdir results
exit
Mit dem folgenden Befehl wird pywws das erste mal gestartet. Dabei legt pywws im Datenverzeichnis die Konfigurationsdateien an:
sudo python -m pywws.LiveLog -vvv /home/pi/weather_data
Nachdem pywws kurz gelaufen ist (nur ca. 10 - 20 Sekunden) wird es mit CTRL-C wieder gestoppt.
Im Verzeichnis /home/mypywws/weather_data sollten jetzt die Dateien status.ini und weather.ini liegen. Da pywws mit sudo gestartet wurde, gehören die beiden Dateien dem User root. Für’s Erste ist das in Ordnung, das muss jedoch später noch korrigiert werden. Dies kann aber erst gemacht werden, wenn auch der User „Pi“ auf den USB Port zugreifen darf. Dies wird weiter unten noch beschrieben, Stichwort „UDEV“.
Als nächstes werden die Templates aus dem Verzeichnis /usr/local/share/pywws/examples in das Datenverzeichnis kopiert:
sudo cp -r /usr/local/lib/python2.7/dist-packages/pywws/examples/templates /home/pi/weather_data
Jetzt muss die pywws Konfigurationsdatei weather.ini angepasst werden. In früheren Versionen von pywws wurde durch den ersten Start eine Beispieldatei angelegt, welche die wichtigsten Einträge schon hatte. Mit der aktuellen Version wird jedoch nur eine minimale Datei angelegt. D. h. jetzt muss erst einmal die Datei im Editor geöffnet werden.
cd ~/weather_data/
sudo nano weather.ini
Die Datei sieht erst einmal so aus
[config]
ws type = Unknown
usb activity margin = 3.0
pressure offset = 263.7
Ok, das ist erst einmal etwas dünn, hier müssen noch etliche Einträge rein. Das sollte eigentlich so aussehen:
[config]
ws type = 1080
logdata sync = 1
day end hour = 0
rain day threshold = 0.2
template encoding = iso-8859-1
gnuplot encoding = iso_8859_1
language = en
usb activity margin = 3.0
pressure offset = 13.5
asynchronous = False
frequent writes = False
gnuplot version = 4.2
[paths]
work = /home/pi/weather_data/tmp/
templates = /home/pi/weather_data/templates/
graph_templates = /home/pi/weather_data/templates/graph_templates/
local_files = /home/pi/weather_data/results/
[live]
services = []
yowindow =
twitter = []
plot = []
text = []
[logged]
services = []
yowindow =
twitter = []
text = ['livedata.log', '2hrs.log']
plot = []
[hourly]
services = []
yowindow =
twitter = []
text = ['24hrs.txt']
plot = []
[12 hourly]
services = []
yowindow =
twitter = []
text = []
plot = []
[daily]
services = []
yowindow =
twitter = []
text = []
plot = []
[ftp]
local site = True
secure = False
site = ftp.username.your_isp.co.uk
user = username
password = secret
directory = /var/www/html/
[Zambretti]
north = True
baro upper = 1050.0
baro lower = 950.0
- Konfiguration der Startumgebung
Nach der Installation hat nur der Root User zugriff auf das USB-Device für die Wetterstation. Damit aber „normale“ Nutzer auch das Device ansprechen können, muss noch eine Regel für UDEV erstellt werden. Dazu wird im Verzeichnis /etc/udev/rules.d/ eine neue Datei angelegt. In der Datei wird der Gruppe „weather“ der Zugriff auf das Device erlaubt.
sudo vi /etc/udev/rules.d/38-weather-station.rules
Diese bekommt folgenden Inhalt:
# WH-1080 Weather Station
ACTION!="add|change", GOTO="weather_station_end"
SUBSYSTEM=="usb", ATTRS{idVendor}=="1941", ATTRS{idProduct}=="8021", GROUP="weather"
LABEL="weather_station_end"
Nach dem Neustart des Raspberry Pi darf der User Pi die pywws Software auch ohne vorangestelltes „sudo“ starten
sudo reboot
Bevor geprüft werden kann, ob der User „Pi“ jetzt auch Zugriff auf die Wetterstation hat, muss noch der Owner für die Daten im seinem Home-Verzeichnis geändert werden:
sudo chown -R pi:weather /home/pi/weather_data/
Jetzt sollte sich pywws vom User „Pi“ auch ohne „sudo“ starten lassen:
python -m pywws.LiveLog -vvv ~/weather_data/
- Bereitstellen der Daten aus pywws
cd weather_data/templates/
nano 2hrs.log
#timezone local#
#roundtime True#
#raw#
#jump -119#
#loop 120#
#idx "%m.%d.%Y %H:%M"# #abs_pressure "%.1f" "1013"# #rel_pressure "%.1f" "1013"# #temp_out "%.1f" "0.0"# #hum_out "%.0f" "0.0"# #calc "apparent_temp(data['temp_out'], data['hum_out'], data['wind_ave'])" "%.1f" "0.0"# #calc "wind_chill(data['temp_out'], data['wind_ave'])" "%.1f" "0.0"# #calc "dew_point(data['temp_out'], data['hum_out'])" "%.1f" "0.0"# #wind_ave "%.1f" "0.0" "wind_kmph(x)"# #wind_gust "%.1f" "0.0" "wind_kmph(x)"# #wind_dir "%.0f" "0.0" "winddir_degrees(x)"# #wind_dir "%s" "-" "winddir_text(x)"# #calc "data['rain']-prevdata['rain']" "%0.1f" "0.0"#
#jump 1#
#endloop#
nano livedata.log
#timezone local#
[
{
#raw#
"DATE": "#idx "%d.%m.%Y %H:%M"#",
"TIME": "#idx "%H:%M %Z"#",
"HUMID_OUT": #hum_out "%.1f" "0.0"#,
"WIND_AVG": #wind_ave "%.1f" "0.0" "wind_kmph(x)"#,
"WIND_GUST": #wind_gust "%.1f" "0.0" "wind_kmph(x)"#,
"WIND_DIR": #wind_dir "%.0f" "0.0" "winddir_degrees(x)"#,
"ABS_PRESSURE": #abs_pressure "%.1f" "0.0"#,
"REL_PRESSURE": #rel_pressure "%.1f" "0.0"#,
"TEMP_OUT": #temp_out "%.1f" "0.0"#,
"TEMP_FEEL": #calc "apparent_temp(data['temp_out'], data['hum_out'], data['wind_ave'])" "%.1f" "0.0"#,
"DEW_POINT": #calc "dew_point(data['temp_out'], data['hum_out'])" "%.1f" "0.0"#,
"WIND_CHILL": #calc "wind_chill(data['temp_out'], data['wind_ave'])" "%.1f" "0.0"#,
#hourly#
#jump -1#
#loop 1#
"RAIN": #calc "data['rain']-prevdata['rain']" "%0.1f"#,
#jump 1#
#endloop#
"WIND_DIR_HOUR": #wind_dir "%.0f" "0.0" "winddir_degrees(x)"#,
"WIND_GUST_HOUR": #wind_gust "%.1f" "0.0" "wind_kmph(x)"#,
"WIND_AVG_HOUR": #wind_ave "%.1f" "0.0" "wind_kmph(x)"#,
"PRESSURE_TREND": #pressure_trend "%s" "0.0" "x"#,
"RAIN_HOUR": #rain "%0.1f" "0.0"#,
#daily#
"TEMP_OUT_MIN_DAY": #temp_out_min "%.1f" "0.0"#,
"TEMP_OUT_MAX_DAY": #temp_out_max "%.1f" "0.0"#
}
]
Das Ergbnis sollte dann nach Ausführung von
python -m pywws.LiveLog -vvv ~/weather_data/ & disown
unter der http://ip_Raspi/livedata.log abrufbar sein.
- Abfragen der Daten in IP Symcon
<?
$content = Sys_GetURLContent("http://192.168.1.XX/livedata.log");
$json = json_decode($content);
//=============================================================================
$parent = IPS_GetParent($_IPS['SELF']);
$check = IPS_GetObjectIDByIdent("date", $parent);
$old = getvalue($check);
$new = $json[0]->DATE;
//=============================================================================
switch ($_IPS['SENDER'])
{
//=============================================================================
case 'WebFront':
break;
//=============================================================================
case 'TimerEvent':
if ($old < $new)
{
SetValueString(GetOrCreateVariable("date", "Stand", 3, "~String", 2), $json[0]->DATE);
SetValueFloat(GetOrCreateVariable("humid_out", "Luftfeuchtigkeit (aussen)", 2, "~Humidity.F", 2), $humid_out = $json[0]->HUMID_OUT);
SetValueFloat(GetOrCreateVariable("humid_in", "Luftfeuchtigkeit (innen)", 2, "~Humidity.F", 2), $humid_in = $json[0]->HUMID_IN);
SetValueFloat(GetOrCreateVariable("wind_avg", "Windgeschwindikeit (Ø)", 2, "~WindSpeed.kmh", 2), $wind_avg = $json[0]->WIND_AVG);
SetValueFloat(GetOrCreateVariable("wind_gust", "Windgeschwindikeit", 2, "~WindSpeed.kmh", 2), $wind_gust = $json[0]->WIND_GUST);
SetValueFloat(GetOrCreateVariable("abs_pressure", "absoluter Luftdruck", 2, "~AirPressure.F", 2), $abs_pressure = $json[0]->ABS_PRESSURE);
SetValueFloat(GetOrCreateVariable("rel_pressure", "relativer Luftdruck", 2, "~AirPressure.F", 2), $rel_pressure = $json[0]->REL_PRESSURE);
SetValueFloat(GetOrCreateVariable("temp_out", "Temeperatur (aussen)", 2, "~Temperature", 2), $temp_out = $json[0]->TEMP_OUT);
SetValueFloat(GetOrCreateVariable("temp_in", "Temeperatur (innen)", 2, "~Temperature", 2), $temp_in = $json[0]->TEMP_IN);
SetValueFloat(GetOrCreateVariable("temp_feel", "gefühlte Temperatur (aussen)", 2, "~Temperature", 2), $temp_feel = $json[0]->TEMP_FEEL);
SetValueFloat(GetOrCreateVariable("dew_point", "Taupunkt", 2, "~Temperature", 2), $dew_point = $json[0]->DEW_POINT);
SetValueFloat(GetOrCreateVariable("wind_chill", "Windkühle", 2, "~Temperature", 2), $wind_chill = $json[0]->WIND_CHILL);
SetValueFloat(GetOrCreateVariable("rain", "Regen", 2, "~Rainfall", 2), $rain = $json[0]->RAIN);
SetValueString(GetOrCreateVariable("wind_dir_hour", "Windrichtung (Stunde)", 3, "~String", 2), $wind_dir_hour = $json[0]->WIND_DIR_HOUR);
SetValueFloat(GetOrCreateVariable("wind_gust_hour", "Windgeschwindigkeit (Stunde)", 2, "~WindSpeed.kmh", 2), $wind_gust_hour = $json[0]->WIND_GUST_HOUR);
SetValueFloat(GetOrCreateVariable("wind_avg_hour", "Windgeschwindigkeit (Ø Stunde)", 2, "~WindSpeed.kmh", 2), $wind_avg_hour = $json[0]->WIND_AVG_HOUR);
SetValueFloat(GetOrCreateVariable("pressure_trend", "Luftdruck (Trend)", 2, "~AirPressure.F", 2), $pressure_trend = $json[0]->PRESSURE_TREND);
SetValueFloat(GetOrCreateVariable("rain_hour", "Regen (Stunde)", 2, "~Rainfall", 2), $rain_hour = $json[0]->RAIN_HOUR);
SetValueFloat(GetOrCreateVariable("temp_out_min_day", "Minimaltemperatur (aussen)", 2, "~Temperature", 2), $temp_out_min_day = $json[0]->TEMP_OUT_MIN_DAY);
SetValueFloat(GetOrCreateVariable("temp_out_max_day", "Maximaltemperatur (aussen)", 2, "~Temperature", 2), $temp_out_max_day = $json[0]->TEMP_OUT_MAX_DAY);
SetValueFloat(GetOrCreateVariable("temp_in_min_day", "Minimaltemperatur (innen)", 2, "~Temperature", 2), $temp_in_min_day = $json[0]->TEMP_IN_MIN_DAY);
SetValueFloat(GetOrCreateVariable("temp_in_max_day", "Maximaltemperatur (innen)", 2, "~Temperature", 2), $temp_in_max_day = $json[0]->TEMP_IN_MAX_DAY);
$wind_dir = $json[0]->WIND_DIR;
if (($wind_dir < 22.5) and($wind_dir >= 0)) $w_text = "N";
if (($wind_dir < 67.5) and($wind_dir >= 22.5)) $w_text = "NO";
if (($wind_dir < 125.5) and($wind_dir >= 67.5)) $w_text = "O";
if (($wind_dir < 157.5) and($wind_dir >= 125.5)) $w_text = "SO";
if (($wind_dir < 202.5) and($wind_dir >= 157.5)) $w_text = "S";
if (($wind_dir < 247.5) and($wind_dir >= 202.5)) $w_text = "SW";
if (($wind_dir < 292.5) and($wind_dir >= 247.5)) $w_text = "W";
if (($wind_dir < 337.5) and($wind_dir >= 292.5)) $w_text = "NW";
if (($wind_dir < 360 ) and($wind_dir >= 337.5)) $w_text = "N";
SetValueString(GetOrCreateVariable("wind_dir_msg", "Windrichtung", 3, "~String", 2) ,"$wind_dir ° - $w_text");
if (($wind_gust < 1) and($wind_gust >= 0)) $bft_text = "0 - Windstille";
if (($wind_gust < 6) and($wind_gust >= 1)) $bft_text = "1 - Leiser Zug";
if (($wind_gust < 13) and($wind_gust >= 6)) $bft_text = "2 - Leichte Brise";
if (($wind_gust < 20) and($wind_gust >= 13)) $bft_text = "3 - schwache Brise";
if (($wind_gust < 29) and($wind_gust >= 20)) $bft_text = "4 - mäßige Brise";
if (($wind_gust < 39) and($wind_gust >= 29)) $bft_text = "5 - frische Brise";
if (($wind_gust < 51) and($wind_gust >= 39)) $bft_text = "6 - starker Wind";
if (($wind_gust < 62) and($wind_gust >= 51)) $bft_text = "7 - steifer Wind";
if (($wind_gust < 75) and($wind_gust >= 62)) $bft_text = "8 - stürmischer Wind";
if (($wind_gust < 89) and($wind_gust >= 75)) $bft_text = "9 - Sturm";
if (($wind_gust < 103) and($wind_gust >= 89)) $bft_text = "10 - schwerer Sturm";
if (($wind_gust < 118) and($wind_gust >= 103)) $bft_text = "11 - orkanartiger Sturm";
if (($wind_gust < 132.9) and($wind_gust >= 118)) $bft_text = "12 - Orkan";
SetValueString(GetOrCreateVariable("wind_gust_msg", "Windstärke", 3, "~String", 2), "$bft_text");
}
break;
//=============================================================================
case 'Execute':
SetValueString(GetOrCreateVariable("date", "Stand", 3, "~String", 2), $data = $json[0]->DATE);
SetValueFloat(GetOrCreateVariable("humid_out", "Luftfeuchtigkeit (aussen)", 2, "~Humidity.F", 2), $humid_out = $json[0]->HUMID_OUT);
SetValueFloat(GetOrCreateVariable("humid_in", "Luftfeuchtigkeit (innen)", 2, "~Humidity.F", 2), $humid_in = $json[0]->HUMID_IN);
SetValueFloat(GetOrCreateVariable("wind_avg", "Windgeschwindikeit (Ø)", 2, "~WindSpeed.kmh", 2), $wind_avg = $json[0]->WIND_AVG);
SetValueFloat(GetOrCreateVariable("wind_gust", "Windgeschwindikeit", 2, "~WindSpeed.kmh", 2), $wind_gust = $json[0]->WIND_GUST);
SetValueFloat(GetOrCreateVariable("abs_pressure", "absoluter Luftdruck", 2, "~AirPressure.F", 2), $abs_pressure = $json[0]->ABS_PRESSURE);
SetValueFloat(GetOrCreateVariable("rel_pressure", "relativer Luftdruck", 2, "~AirPressure.F", 2), $rel_pressure = $json[0]->REL_PRESSURE);
SetValueFloat(GetOrCreateVariable("temp_out", "Temeperatur (aussen)", 2, "~Temperature", 2), $temp_out = $json[0]->TEMP_OUT);
SetValueFloat(GetOrCreateVariable("temp_in", "Temeperatur (innen)", 2, "~Temperature", 2), $temp_in = $json[0]->TEMP_IN);
SetValueFloat(GetOrCreateVariable("temp_feel", "gefühlte Temperatur (aussen)", 2, "~Temperature", 2), $temp_feel = $json[0]->TEMP_FEEL);
SetValueFloat(GetOrCreateVariable("dew_point", "Taupunkt", 2, "~Temperature", 2), $dew_point = $json[0]->DEW_POINT);
SetValueFloat(GetOrCreateVariable("wind_chill", "Windkühle", 2, "~Temperature", 2), $wind_chill = $json[0]->WIND_CHILL);
SetValueFloat(GetOrCreateVariable("rain", "Regen", 2, "~Rainfall", 2), $rain = $json[0]->RAIN);
SetValueString(GetOrCreateVariable("wind_dir_hour", "Windrichtung (Stunde)", 3, "~String", 2), $wind_dir_hour = $json[0]->WIND_DIR_HOUR);
SetValueFloat(GetOrCreateVariable("wind_gust_hour", "Windgeschwindigkeit (Stunde)", 2, "~WindSpeed.kmh", 2), $wind_gust_hour = $json[0]->WIND_GUST_HOUR);
SetValueFloat(GetOrCreateVariable("wind_avg_hour", "Windgeschwindigkeit (Ø Stunde)", 2, "~WindSpeed.kmh", 2), $wind_avg_hour = $json[0]->WIND_AVG_HOUR);
SetValueFloat(GetOrCreateVariable("pressure_trend", "Luftdruck (Trend)", 2, "~AirPressure.F", 2), $pressure_trend = $json[0]->PRESSURE_TREND);
SetValueFloat(GetOrCreateVariable("rain_hour", "Regen (Stunde)", 2, "~Rainfall", 2), $rain_hour = $json[0]->RAIN_HOUR);
SetValueFloat(GetOrCreateVariable("temp_out_min_day", "Minimaltemperatur (aussen)", 2, "~Temperature", 2), $temp_out_min_day = $json[0]->TEMP_OUT_MIN_DAY);
SetValueFloat(GetOrCreateVariable("temp_out_max_day", "Maximaltemperatur (aussen)", 2, "~Temperature", 2), $temp_out_max_day = $json[0]->TEMP_OUT_MAX_DAY);
SetValueFloat(GetOrCreateVariable("temp_in_min_day", "Minimaltemperatur (innen)", 2, "~Temperature", 2), $temp_in_min_day = $json[0]->TEMP_IN_MIN_DAY);
SetValueFloat(GetOrCreateVariable("temp_in_max_day", "Maximaltemperatur (innen)", 2, "~Temperature", 2), $temp_in_max_day = $json[0]->TEMP_IN_MAX_DAY);
$wind_dir = $json[0]->WIND_DIR;
if (($wind_dir < 22.5) and($wind_dir >= 0)) $w_text = "N";
if (($wind_dir < 67.5) and($wind_dir >= 22.5)) $w_text = "NO";
if (($wind_dir < 125.5) and($wind_dir >= 67.5)) $w_text = "O";
if (($wind_dir < 157.5) and($wind_dir >= 125.5)) $w_text = "SO";
if (($wind_dir < 202.5) and($wind_dir >= 157.5)) $w_text = "S";
if (($wind_dir < 247.5) and($wind_dir >= 202.5)) $w_text = "SW";
if (($wind_dir < 292.5) and($wind_dir >= 247.5)) $w_text = "W";
if (($wind_dir < 337.5) and($wind_dir >= 292.5)) $w_text = "NW";
if (($wind_dir < 360 ) and($wind_dir >= 337.5)) $w_text = "N";
SetValueString(GetOrCreateVariable("wind_dir_msg", "Windrichtung", 3, "~String", 2) ,"$wind_dir ° - $w_text");
if (($wind_gust < 1) and($wind_gust >= 0)) $bft_text = "0 - Windstille";
if (($wind_gust < 6) and($wind_gust >= 1)) $bft_text = "1 - Leiser Zug";
if (($wind_gust < 13) and($wind_gust >= 6)) $bft_text = "2 - Leichte Brise";
if (($wind_gust < 20) and($wind_gust >= 13)) $bft_text = "3 - schwache Brise";
if (($wind_gust < 29) and($wind_gust >= 20)) $bft_text = "4 - mäßige Brise";
if (($wind_gust < 39) and($wind_gust >= 29)) $bft_text = "5 - frische Brise";
if (($wind_gust < 51) and($wind_gust >= 39)) $bft_text = "6 - starker Wind";
if (($wind_gust < 62) and($wind_gust >= 51)) $bft_text = "7 - steifer Wind";
if (($wind_gust < 75) and($wind_gust >= 62)) $bft_text = "8 - stürmischer Wind";
if (($wind_gust < 89) and($wind_gust >= 75)) $bft_text = "9 - Sturm";
if (($wind_gust < 103) and($wind_gust >= 89)) $bft_text = "10 - schwerer Sturm";
if (($wind_gust < 118) and($wind_gust >= 103)) $bft_text = "11 - orkanartiger Sturm";
if (($wind_gust < 132.9) and($wind_gust >= 118)) $bft_text = "12 - Orkan";
SetValueString(GetOrCreateVariable("wind_gust_msg", "Windstärke", 3, "~String", 2), "$bft_text");
break;
}
//=============================================================================
function GetOrCreateVariable($Ident, $Name, $Type, $Profile = "", $Position = 0)
{
if (!isset($_IPS))
global $_IPS;
$parentID = IPS_GetParent($_IPS['SELF']);
$vid = @IPS_GetObjectIDByIdent($Ident, $parentID);
if ($vid > 0)
{
if (IPS_GetVariable($vid)["VariableType"] != $Type)
{
IPS_DeleteVariable($vid);
$vid = 0;
}
}
if ($vid < 1)
{
$vid = IPS_CreateVariable($Type);
IPS_SetParent($vid, $parentID);
IPS_SetIdent($vid, $Ident);
IPS_SetName($vid, $Name);
IPS_SetPosition($vid, $Position);
}
IPS_SetVariableCustomProfile($vid, $Profile);
return $vid;
}
?>