Verlauf der Wetterdaten mit Higcharts darstellen

Neben den aktuellen Wetterdaten lassen sich auch historische Werte anzeigen. Mit pywws können Datenreihen, z. B. mit den stündlichen, wöchentlichen usw. Wetterdaten erzeugt werden. Im folgenden sollen die stündlichen Werte der letzten 24 Stunden zur Anzeige gebracht werden. Dazu wird erst einmal folgendes pywws Template benötigt:

#timezone local#
#roundtime True#
#hourly#
#jump -23#
#loop 24#
#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#

Das muss natürlich in pywws in der Konfiguration für den stündlichen Lauf eingetragen werden. Dazu den obigen Inhalt z. B. als "24hrs.log" im Templates Verzeichnis von pywws ablegen. Anschliessend muss noch die Datei in der pywws Konfiguration eingetragen werden und danach neu gestartet werden:

[hourly]
services = []
yowindow =
twitter = []
text = ['24hrs.log']
plot = []

Wenn pywws die Daten verarbeitet hat, sollte im Verzeichnis "pywws-data" die Datei "24hrs.log" liegen und in etwa so aussehen:

09.05.2013 09:59 982.9 1019.6 28.4 42 29.7 28.4 14.2 0.2 6.1 158 SSE 0.0
09.05.2013 10:59 982.4 1019.1 30.3 37 31.5 30.3 14.0 0.5 7.2 90 E 0.0
09.05.2013 11:59 982.0 1018.7 32.0 33 33.0 32.0 13.7 1.0 8.6 112 ESE 0.0
09.05.2013 12:51 981.4 1018.1 32.3 31 33.0 32.3 13.0 1.0 7.2 135 SE 0.0
09.05.2013 13:59 980.8 1017.5 31.9 28 32.1 31.9 11.1 0.7 7.2 68 ENE 0.0
09.05.2013 14:59 980.2 1016.9 32.8 29 33.5 32.8 12.4 0.4 8.6 90 E 0.0
09.05.2013 15:59 979.6 1016.3 32.0 28 32.3 32.0 11.2 0.6 12.2 135 SE 0.0
09.05.2013 16:59 979.1 1015.8 30.4 32 30.9 30.4 11.8 0.4 7.2 90 E 0.0
09.05.2013 17:59 978.5 1015.2 28.1 38 28.8 28.1 12.4 0.0 5.0 315 NW 0.0
09.05.2013 18:44 978.4 1015.1 0.0 0.0 0.0 0.0 0.0 0.0 2.5 180 S 0.0
09.05.2013 19:44 978.2 1014.9 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 - 0.0
09.05.2013 20:59 978.6 1015.3 23.4 53 24.4 23.4 13.3 0.0 1.1 180 S 0.0
09.05.2013 21:55 978.7 1015.4 22.4 58 23.6 22.4 13.7 0.0 2.5 180 S 0.0
09.05.2013 22:59 978.6 1015.3 21.0 64 22.2 21.0 13.9 0.0 2.5 180 S 0.0
09.05.2013 23:59 978.5 1015.2 19.4 70 20.6 19.4 13.8 0.0 2.5 180 S 0.0
09.06.2013 00:59 978.5 1015.2 18.4 75 19.6 18.4 13.9 0.0 1.1 180 S 0.0
09.06.2013 01:59 978.0 1014.7 17.0 80 18.1 17.0 13.5 0.0 1.1 180 S 0.0
09.06.2013 02:59 977.6 1014.3 16.3 84 17.4 16.3 13.6 0.0 2.5 180 S 0.0
09.06.2013 03:59 977.5 1014.2 15.9 84 16.9 15.9 13.2 0.0 2.5 180 S 0.0
09.06.2013 04:59 977.2 1013.9 15.2 86 16.1 15.2 12.9 0.0 0.0 180 S 0.0
09.06.2013 05:59 977.0 1013.7 14.5 89 15.3 14.5 12.7 0.0 0.0 180 S 0.0
09.06.2013 06:59 977.3 1014.0 14.0 90 14.7 14.0 12.4 0.0 0.0 180 S 0.0
09.06.2013 07:55 977.3 1014.0 20.6 63 21.6 20.6 13.3 0.0 2.5 45 NE 0.0

Wer genau hinsieht, wird bemerken, dass im Gegensatz zu den Live Daten keine JSON Formatierung vorliegt. Es werden einfach die einzelnen Werte wie in einer CSV Datei mit Leerzeichen getrennt in eine Zeile geschrieben. Jede Zeile ist ein Wertesatz für eine Stunde.

Das Umformatieren in das JSON Format wird von der PHP Datei erledigt, welche die Datei mit den Wetterdaten einliest und dann an den Browser auf Anfrage von diesem liefert. Die PHP Datei zum Lesen der Datei "24hrs.log" basiert dabei zu über 90% auf der Datei "realtimeLogParser.php"  von hier: http://wiki.sandaysoft.com/a/Highcharts_-_Realtime.

In meiner Variante heisst diese "realtimeLogParser24hrs.php" und wird im Unterverzeichnis "php-scripts" mit folgendem Inhalt abgelegt:

<?php
//-----------------------------------------------------------------
// Parse a Cumulus realtime log file and return the requested fields
// along with the time stamps in a JSON format suitable for use with
// the Highcharts graphing package.
// Author: Mark Crossley
//
// Version 0.1 - 29 Nov 2012
//
// Call this script as e.g. ...realtimeLogParser.php?count=N&temp&dew
//  Where count=N returns the last N rows worth of data from the log file
//    if the count parameter is omitted all available records are returned.
//  Where &temp&dew returns the temperature & dew data, concatenate as
//    many record types as you wish.
//  The data arrays are returned in an object with the key name equal to
//  the param name supplied in the URL. In the example above the returned
//  object will be: {"temp": [[t0,v0],[t0,v0],...],
//                   "dew": [[t0,v0],[t1,v1],...]}
//-----------------------------------------------------------------

// The name of your realtime.txt log file
$logfile = '../pywws-data/24hrs.log';
// The various delimiters used in your version of realtime.txt
$field_delimiter = ' ';
$date_delimiter = '.';
$time_delimiter = ':';

//-----------------------------------------------------------------

// Fields of realtime.txt file
// Use the same names as the corresponding web tags
$rfields = array(	"date", 
					"time", 
					"abs_pressure", 
					"rel_pressure", 
					"temp_out", 
					"hum_out", 
					"apparent_temp", 
					"wind_chill", 
					"dew_point",
					"wind_ave",
					"wind_gust",
					"wind_dir",
					"wind_dir_text",
					"rain"
				);

// Return the array position of the variable
function ret_rval($lookup) {
    global $rfields;
    $rtn = array_search($lookup, $rfields);

    if ($rtn !== FALSE) {
        return($rtn);
    } else {
        return("");
    }
}

function readLogfile($file, $delimiter) {
    $data = array();
    $handle =  @ fopen($file, "r");
    if ($handle) {
        while (!feof($handle)) {
            $buffer = fgets($handle);
            $buf_arr = explode($delimiter, $buffer);
            if ($buf_arr[0] != "") {
                $data[] = $buf_arr;
            }
        }
        fclose($handle);
    } else {
        echo "Failed to open log file.";
    }
    return $data;
}

// Strip any Byte order marker from UTF-8 format files
function rmBOM($string) {
    if (substr($string, 0, 3) == pack('CCC', 0xef, 0xbb, 0xbf)) {
        $string = substr($string, 3);
    }
    return $string;
}

// ============= Start it off... ============

// Read data into array
$DATA = readLogfile($logfile, ' ');

// How many records?
$total_records = count($DATA);

// Default to returning all the data rows in the log file
$records = $total_records;

// Process the script arguments
$dataTypes = array();
foreach($_GET as $key => $value) {
    if ($key == 'count') {
        $records = $value;
    } elseif (in_array($key, $rfields)) {
        $dataTypes[] = $key;
    }
}

// Did we get any valid parameters?
if (count($dataTypes) == 0) {
    echo "No valid data types supplied";
    exit;
}

// Remove any BOM
rmBOM($DATA[0][0]);

// Read the required fields from $data into a series of arrays...
//
// for each required line in the data file
for ($i = max(0, $total_records - $records); $i < $total_records; $i++) {
    // send the date time to the client as Javascript millisecs since 1970 - as if it were UTC
    $t = explode($time_delimiter, $DATA[$i][1]);
    $d = explode($date_delimiter, $DATA[$i][0]);
    // PHP time is in seconds, multiply by 1000 to get millisecs for Javascript
    $tim = gmmktime($t[0], $t[1], 0, $d[0], $d[1], $d[2]) * 1000;
    // for each required data element
    foreach($dataTypes as $key) {
		if ($key == 'wind_dir_text')
		{
			${"arr_" . $key}[]  = array($tim, $DATA[$i][ret_rval($key)]);
		}
		else
		{
			${"arr_" . $key}[]  = array($tim, (float)$DATA[$i][ret_rval($key)]);
		}
    }
}

foreach($dataTypes as $key) {
    $return[$key] = ${'arr_' . $key};
}

header('Cache-Control: private');
header('Cache-Control: no-cache, must-revalidate');
header('Content-type: text/json');

echo json_encode($return);

// ========== End of Module ===========
?>
 

Gegenüber der Originalversion ist diese an folgenden Stellen verändert worden:


1) Der Pfad zu den Wetterdaten ist fest verdrahtet und die Delimiter angepasst:

// The name of your realtime.txt log file
$logfile = '../pywws-data/24hrs.log';
// The various delimiters used in your version of realtime.txt
$field_delimiter = ' ';
$date_delimiter = '.';
$time_delimiter = ':';

2) Der Aufbau der JSON Daten sind an mein pywws Template angepasst worden:

// Fields of realtime.txt file
// Use the same names as the corresponding web tags
$rfields = array(	"date", 
					"time", 
					"abs_pressure", 
					"rel_pressure", 
					"temp_out", 
					"hum_out", 
					"apparent_temp", 
					"wind_chill", 
					"dew_point",
					"wind_ave",
					"wind_gust",
					"wind_dir",
					"wind_dir_text",
					"rain"
				);

3) die Funktion zur Ausgabe des Source Codes der Datei wurde komplett entfernt (don't do such stupid things!). Auch wenn der Code frei im Netz verfügbar ist, so würde ich keinem diesen zeigen. Derjenige der grad versucht meine Website zu hacken braucht nicht noch extra eingeladen werden. ;-). Dazu habe ich die nachfolgende Funktion aus dem Original komplett entfernt:

// Standard Source view option check
function check_sourceview () {
    global $SITE;

    if ( isset($_GET['view']) && $_GET['view'] == 'sce' ) {
        $filenameReal = __FILE__;
        $download_size = filesize($filenameReal);
        header('Pragma: public');
        header('Cache-Control: private');
        header('Cache-Control: no-cache, must-revalidate');
        header("Content-type: text/plain");
        header("Accept-Ranges: bytes");
        header("Content-Length: $download_size");
        header('Connection: close');
        readfile($filenameReal);
        exit;
    }
}

und folgende Zeile entfernt:

// Just list the PHP source?
check_sourceview();

Damit sind die Vorbereitungen zur Datenbereitstellung abgeschlossen.