From 4f77e5fc357ae3bce202fe32fe4a5333aa1ee446 Mon Sep 17 00:00:00 2001
From: Dirk Koopman
Date: Fri, 19 Jul 2013 14:50:55 +0100
Subject: [PATCH] add (working) dirk.pl + other bits
---
DWeather/lib/DWeather/Debug.pm | 2 +-
DWeather/lib/DWeather/Serial.pm | 52 +-
DWeather/lib/DWeather/Station.pm | 1 +
DWeather/lib/DWeather/Station/Vantage.pm | 37 +-
DWeather/lib/DWeather/Vantage.pm | 30 -
dirk.pl | 546 ++++++++++++++++
yr.php | 763 +++++++++++++++++++++++
7 files changed, 1374 insertions(+), 57 deletions(-)
delete mode 100644 DWeather/lib/DWeather/Vantage.pm
create mode 100755 dirk.pl
create mode 100644 yr.php
diff --git a/DWeather/lib/DWeather/Debug.pm b/DWeather/lib/DWeather/Debug.pm
index 3535184..d67b702 100644
--- a/DWeather/lib/DWeather/Debug.pm
+++ b/DWeather/lib/DWeather/Debug.pm
@@ -61,7 +61,7 @@ sub dbg
chomp $r;
my @l = split /\n/, $r;
for (@l) {
- s/([\x00-\x08\x0B-\x1f\x7f-\xff])/uc sprintf("%%%02x",ord($1))/eg;
+ s/([\x00-\x1f\x7f-\xff])/uc sprintf("%%%02x",ord($1))/eg;
# print "$_\n" if defined \*STDOUT;
$fp->writeunix($t, "$ts $_");
}
diff --git a/DWeather/lib/DWeather/Serial.pm b/DWeather/lib/DWeather/Serial.pm
index 40ac160..cbd6cbe 100644
--- a/DWeather/lib/DWeather/Serial.pm
+++ b/DWeather/lib/DWeather/Serial.pm
@@ -9,30 +9,47 @@ package DWeather::Serial;
use POSIX qw(:termios_h);
use Fcntl;
-our @ISA = qw(IO::File);
+use AnyEvent;
+use base qw(AnyEvent::Handle);
-# Linux-specific Baud-Rates
+# Linux-specific Baud-Rates (for reference really)
use constant B57600 => 0010001;
use constant B115200 => 0010002;
use constant B230400 => 0010003;
use constant B460800 => 0010004;
use constant CRTSCTS => 020000000000;
+#
+# my $h = DWeather::Serial->new("/dev/ttyXXX", 19200 [,cs7] [,odd] [,rtscts]);
+#
+# all parameters are optional
+#
+# you are expected to add AE callbacks as required, all this module
+# does is create the AE::Handle and associates an IO::File handle with it
+#
+# default is /dev/ttyS0, 9600 8N1 no handshaking
+#
+# the tty is set to raw mode.
+#
+# returns a subclassed AE::Handle
+#
sub new
{
my $pkg = shift;
my $class = ref $pkg || $pkg;
my $device = shift || "/dev/ttyS0";
- my $self = $pkg->SUPER::new($device, O_RDWR|O_NOCTTY|O_EXCL|O_NDELAY) || return;
+ my $fh = IO::File->new($device, O_RDWR|O_NOCTTY|O_EXCL|O_NDELAY) || return;
+ my $self = $class->new(fh => $fh);
# get my attributes
- $$self->{ORIGTERM} = POSIX::Termios->new();
- my $term = $$self->{TERM} = POSIX::Termios->new();
- $$self->{ORIGTERM}->getattr(fileno($self));
- $term->getattr(fileno($self));
+ $self->{ORIGTERM} = POSIX::Termios->new();
+ my $term = $self->{TERM} = POSIX::Termios->new();
+ $self->{ORIGTERM} = $self->{ORIGTERM}->getattr(fileno($fh));
+ $term->getattr(fileno($fh));
my ($speed) = grep {/^\d+$/} @_;
+ $speed ||= 9600;
my $baud;
{
no strict 'refs';
@@ -62,35 +79,30 @@ sub new
$cflag |= CRTSCTS if grep /rtscts$/, $@;
$term->setcflag($cflag); $term->setlflag($lflag);
$term->setoflag($oflag); $term->setiflag($iflag);
- $term->setattr(fileno($self), TCSANOW);
+ $term->setattr(fileno($fh), TCSANOW);
+ $self->{device} = $device;
+ $self->{speed} = $speed;
return $self;
}
sub getattr
{
my $self = shift;
- $$self->{TERM}->getattr;
- return $$self->{TERM};
+ $self->{TERM}->getattr(fileno($self->fh));
+ return $self->{TERM};
}
sub setattr
{
my $self = shift;
- my $attr = shift || $$self->{TERM};
- $attr->setattr(fileno($self), &POSIX::TCSANOW);
-}
-
-sub close
-{
- my $self = shift;
- $self->setattr($$self->{ORIGTERM});
- $self->SUPER::close;
+ my $attr = shift || $self->{TERM};
+ $attr->setattr(fileno($self->fh), &POSIX::TCSANOW);
}
sub DESTROY
{
my $self = shift;
- $self->close;
+ $self->setattr($self->{ORIGTERM});
}
1;
diff --git a/DWeather/lib/DWeather/Station.pm b/DWeather/lib/DWeather/Station.pm
index f9c45fe..7d05246 100644
--- a/DWeather/lib/DWeather/Station.pm
+++ b/DWeather/lib/DWeather/Station.pm
@@ -23,4 +23,5 @@ sub new
return $self;
}
+
1;
diff --git a/DWeather/lib/DWeather/Station/Vantage.pm b/DWeather/lib/DWeather/Station/Vantage.pm
index 5f3749e..a8b91cf 100644
--- a/DWeather/lib/DWeather/Station/Vantage.pm
+++ b/DWeather/lib/DWeather/Station/Vantage.pm
@@ -18,18 +18,43 @@ sub new
my $class = ref $pkg || $pkg;
my $device = shift;
- my $d = $class->SUPER::new($device, 19200);
- return $d;
+ my $self = $class->SUPER::new($device, 19200);
+ $self->on_read(sub{$d->process});
+ return $self;
}
-sub reset
+sub process
{
-
+ my $self = shift;
+ my $data = $self->{rbuf};
+ $self->{rbuf} = '';
+
+ if (isdbg('raw')) {
+ dbg("I $self->{device} lth " . length $data);
+ dbgdump(data);
+ } elsif (isdbg('chan')) {
+ dbg("I $self->{device}: $data");
+ }
+ foreach my $ch (@ch) {
+
+ }
}
-sub poll
+sub send
{
-
+ my $self= shift;
+ my $data = shift;
+ if (isdbg('raw')) {
+ dbg("O $self->{device} lth " . length $data);
+ dbgdump(data);
+ } elsif (isdbg('chan')) {
+ dbg("O $self->{device}: $data");
+ }
+ $self->push_write($data)
}
+sub reset
+{
+
+}
1;
diff --git a/DWeather/lib/DWeather/Vantage.pm b/DWeather/lib/DWeather/Vantage.pm
deleted file mode 100644
index 54cbb4a..0000000
--- a/DWeather/lib/DWeather/Vantage.pm
+++ /dev/null
@@ -1,30 +0,0 @@
-#
-# Vantage Pro 2 interface for DWeather
-#
-#
-
-use strict;
-use warnings;
-
-use base qw(DWeather::Serial);
-use AnyEvent;
-
-sub new
-{
- my $pkg = shift;
- my $class = ref $pkg || $pkg;
- my $device = shift || '/dev/ttyS0';
-
- my $self = $class->SUPER::new($device, 19200);
- return $self;
-}
-
-sub send
-{
-
-}
-
-sub run
-{
-
-}
diff --git a/dirk.pl b/dirk.pl
new file mode 100755
index 0000000..d727057
--- /dev/null
+++ b/dirk.pl
@@ -0,0 +1,546 @@
+#!/usr/bin/perl
+
+use DBI;
+use strict;
+use Device::SerialPort;
+use Time::HiRes;
+
+my $devname = "/dev/davis";
+my $dbsort = "SQLite";
+my $db="weather.db";
+my $host="";
+my $userid="";
+my $passwd="";
+my $connectionInfo="dbi:$dbsort:$db";
+$connectionInfo .= ":$host" if $host;
+
+# make connection to database
+my %attr = ( PrintError => 0, RaiseError => 0 );
+my $dbh = DBI->connect($connectionInfo,$userid,$passwd,\%attr) or die "Couldn't connect to database: " . DBI->errstr;
+
+
+my ($count, $result);
+my %hsh;
+my @crc_table=();
+my %bar_trend=();
+load_crc_table();
+
+my $ob = Device::SerialPort->new ($devname) || die;
+
+$ob->user_msg(1); # misc. warnings
+$ob->error_msg(1); # hardware and data errors
+
+$ob->baudrate(19200);
+$ob->parity("none");
+#$ob->parity_enable(1); # for any parity except "none"
+$ob->databits(8);
+$ob->stopbits(1);
+$ob->handshake('none');
+$ob->read_const_time(15000); # ultimate timeout (15 seconds)
+$ob->write_settings||die"setting failed";
+
+my $awake=0;
+my $attempts=0;
+$ob->write("\n"); # initial wake
+
+while ($awake==0) {
+ $ob->write("\n"); # wake for real
+ $ob->read_interval(600); # wait for a max of 600ms
+ ($count, $result) = $ob->read(10); # read up to 10 chars
+ if ($result eq "\n\r") {
+ print "awoke on attempt $attempts :)\n";
+ $awake=1;
+ }
+ else {
+ print "wake error on attempt $attempts :(\n";
+ }
+ $attempts++;
+ dienice("failed to wake device - tried $attempts times") unless $attempts<6;
+}
+
+$ob->write("LAMPS 0\n");
+$ob->read_interval(300); # wait for a max of 300ms
+($count, $result) = $ob->read(8); # read up to 8 chars
+$result=~s/(\r|\n)//g;
+if ($result eq "OK") {
+ print "lamps on :)\n";
+}
+else {
+ dienice("lamp error '$result'");
+}
+
+
+
+my $ref=gettime();
+$ref->[5]+=1900;
+print "$ref->[2]:$ref->[1]:$ref->[0] $ref->[3]/$ref->[4]/$ref->[5]\n";
+
+#settime();
+
+#do_dmpaft();
+
+while (1) {
+ get_loop(); # if you do anything after here - you need to wake up the device again
+ print "** do something else\n";
+ sleep 5;
+ $ob->write("\r"); # wake
+ $ob->read_interval(500); # wait for a max of 300ms
+ my ($count, $result) = $ob->read(4096); # read any crap up to 4096 chars
+}
+
+#print "count=$count $result\n";
+#for(my $i=0; $i<$count; $i++)
+#{ printf("%02d ",ord(substr($result,$i,1))); }
+
+#$ob->write("WRD\x12\x4d\n");
+
+undef $ob;
+exit 0;
+
+sub dienice
+{
+ my $err=shift;
+ print "$err\n";
+ undef $ob;
+ exit 9;
+}
+
+sub parse_loop_blck
+{
+ my $blk = shift;
+ my $loo = substr $blk,0,3;
+ unless ( $loo eq 'LOO') {
+ warn("Block invalid loo -> $loo\n"); return "";
+ }
+ my $t;
+
+ #$hsh{'next_rec'} = unpack("s", substr $blk,5,2);
+
+ $hsh{'Barometric_Trend'} = unpack("C", substr $blk,3,1);
+ $hsh{'Barometric_Trend_txt'} = $bar_trend{$hsh{'Barometric_Trend'}};
+ $t = unpack("s", substr $blk,7,2) / 1000;
+# $hsh{'Barometric_Press_hg'} = $t;
+ $hsh{'Barometric_Press_mb'} = sprintf("%.2f",$t*33.8637526);
+
+
+ $t = unpack("s", substr $blk,9,2) / 10;
+# $hsh{'Air_Temp_Inside_f'} = $t;
+ $hsh{'Air_Temp_Inside_c'} = sprintf("%.1f",($t - 32) * 5/9);
+ my $tf = unpack("s", substr $blk,12,2) / 10;
+# $hsh{'Air_Temp_Outside_f'} = $tf;
+ $hsh{'Air_Temp_Outside_c'} = sprintf("%.1f",($tf - 32) * 5/9);
+
+ $hsh{'Wind_Speed_mph'} = unpack("C", substr $blk,14,1);
+# $hsh{'Wind_Speed_mps'} = sprintf("%.1f",$hsh{'Wind_Speed_mph'}*0.44704);
+ $hsh{'Wind_Speed_10min_Avg_mph'} = unpack("C", substr $blk,15,1);
+# $hsh{'Wind_Speed_10min_Avg_mps'} = sprintf("%.1f",$hsh{'Wind_Speed_10min_Avg_mph'}*0.44704);
+ $hsh{'Wind_Dir'} = unpack("s", substr $blk,16,2);
+
+
+ $hsh{'Humidity_Outside'} = unpack("C", substr $blk,33,1);
+ $hsh{'Humidity_Inside'} = unpack("C", substr $blk,11,1);
+ $hsh{'Dew_Point'} = dew_point($tf, $hsh{'Humidity_Outside'});
+
+# $hsh{'UV'} = unpack("C", substr $blk,43,1);
+# $hsh{'Solar'} = unpack("s", substr $blk,44,2); # watt/m**2
+
+ $hsh{'Rain_Rate'} = (unpack("s", substr $blk,41,2) / 100) * 25.4; # Inches per hr converted to mm
+ $hsh{'Rain_Storm'} = (unpack("s", substr $blk,46,2) / 100) * 25.4; # Inches per storm
+ #$hsh{'Storm_Date'} = unpack("s", substr $blk,48,2); # Need to parse data (not sure what this is)
+ $hsh{'Rain_Day'} = (unpack("s", substr $blk,50,2)/100) * 25.4;
+ $hsh{'Rain_Month'} = (unpack("s", substr $blk,52,2)/100) * 25.4;
+ $hsh{'Rain_Year'} = (unpack("s", substr $blk,54,2)/100) * 25.4;
+
+ $hsh{'ET_Day'} = unpack("s", substr $blk,56,2)/1000;
+ $hsh{'ET_Month'} = unpack("s", substr $blk,58,2)/100;
+ $hsh{'ET_Year'} = unpack("s", substr $blk,60,2)/100;
+
+ #$hsh{'Alarms_Inside'} = unpack("b8", substr $blk,70,1);
+ #$hsh{'Alarms_Rain'} = unpack("b8", substr $blk,70,1);
+ #$hsh{'Alarms_Outside'} = unpack("b8", substr $blk,70,1);
+
+ $hsh{'Batt_Transmitter'} = unpack("C", substr $blk,86,1); # * 0.005859375
+ $hsh{'Batt_Console'} = unpack("s", substr $blk,87,2) * 0.005859375;
+
+ $hsh{'Forecast_Icon'} = unpack("C", substr $blk,89,1);
+ $hsh{'Forecast_Rule'} = unpack("C", substr $blk,90,1);
+
+ $hsh{'Sunrise'} = sprintf( "%04d", unpack("S", substr $blk,91,2) );
+ $hsh{'Sunrise'} =~ s/(\d{2})(\d{2})/$1:$2/;
+ $hsh{'Sunset'} = sprintf( "%04d", unpack("S", substr $blk,93,2) );
+ $hsh{'Sunset'} =~ s/(\d{2})(\d{2})/$1:$2/;
+
+ #my $nl = ord substr $blk,95,1;
+ #my $cr = ord substr $blk,96,1;
+
+ my $crc = unpack "%n", substr($blk,97,2);
+ my $crc_calc = CRC_CCITT($blk);
+
+ if ($crc_calc==0) {
+ return 0;
+ }
+ else {
+ print "CRC check failed for LOOP data!\n";
+ return 1;
+ }
+ #delete @hsh{'crc', 'crc_calc', 'next_rec'};
+ #delete($hsh{crc})||die"cant delete crc";
+ #delete($hsh{crc_calc})||die"cant delete crc_calc";
+ #delete($hsh{next_rec})||die"cant delete next_rec";
+
+}
+
+sub dew_point
+{
+ my $temp = shift @_;
+ my $rh = shift @_;
+
+ # Using the simplified approximation for dew point
+ # Accurate to 1 degree C for humidities > 50 %
+ # http://en.wikipedia.org/wiki/Dew_point
+
+ my $dew_point = $temp - ( (100 - $rh)/5 );
+
+ return $dew_point;
+}
+
+sub CRC_CCITT
+{
+ # Expects packed data...
+ my $data_str = shift @_;
+
+ my $crc = 0;
+ my @lst = split //, $data_str;
+ foreach my $data (@lst) {
+ my $data = unpack("c",$data);
+
+ my $crc_prev = $crc;
+ my $index = $crc >> 8 ^ $data;
+ my $lhs = $crc_table[$index];
+ #print "lhs=$lhs, crc=$crc\n";
+ my $rhs = ($crc << 8) & 0xFFFF;
+ $crc = $lhs ^ $rhs;
+
+
+ }
+
+ return $crc;
+}
+
+sub load_crc_table
+{
+
+ @crc_table = (
+ 0x0, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
+ 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
+ 0x1231, 0x210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
+ 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
+ 0x2462, 0x3443, 0x420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
+ 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
+ 0x3653, 0x2672, 0x1611, 0x630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
+ 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
+ 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x840, 0x1861, 0x2802, 0x3823,
+ 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
+ 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0xa50, 0x3a33, 0x2a12,
+ 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
+ 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0xc60, 0x1c41,
+ 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
+ 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0xe70,
+ 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
+ 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
+ 0x1080, 0xa1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
+ 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
+ 0x2b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
+ 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
+ 0x34e2, 0x24c3, 0x14a0, 0x481, 0x7466, 0x6447, 0x5424, 0x4405,
+ 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
+ 0x26d3, 0x36f2, 0x691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
+ 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
+ 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x8e1, 0x3882, 0x28a3,
+ 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
+ 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0xaf1, 0x1ad0, 0x2ab3, 0x3a92,
+ 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
+ 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0xcc1,
+ 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
+ 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0xed1, 0x1ef0
+ );
+
+ $bar_trend{-60} = "Falling Rapidly";
+ $bar_trend{196} = "Falling Rapidly";
+ $bar_trend{-20} = "Falling Slowly";
+ $bar_trend{236} = "Falling Slowly";
+ $bar_trend{0} = "Steady";
+ $bar_trend{20} = "Rising Slowly";
+ $bar_trend{60} = "Rising Rapidly";
+}
+
+sub gettime
+{
+ $ob->write("GETTIME\n");
+ $ob->read_interval(200);
+ my($cnt_in, $str) = $ob->read(9);
+ if ($cnt_in==0) {
+ dienice("read error cnt_in=$cnt_in, str='$str'");
+ }
+
+ my $ck = CRC_CCITT(substr($str,1,9));
+ if ( $ck ) {
+ warn "checksum error"; return 0;
+ }
+ my @rsp_lst = split //, $str;
+ shift @rsp_lst;
+ @rsp_lst = map ord, @rsp_lst;
+ return \@rsp_lst;
+}
+
+sub settime
+{
+ my $s_time = [ localtime() ];
+ $s_time->[4] += 1;
+
+ $ob->write("SETTIME\n");
+ $ob->read_interval(300);
+ my ($cnt_in, $str) = $ob->read(1);
+ my $ack = ord $str;
+ if ( $ack != 6 ) {
+ warn "SETTIME not set ack $ack !"; return 0;
+ }
+ my ($sec, $min, $hour, $day, $mon, $yr) = @{$s_time};
+ $str = join "", map chr, ($sec, $min, $hour, $day, $mon, $yr);
+ my $ck = CRC_CCITT($str);
+ $str = $str . pack("n",$ck);
+ $ob->write($str);
+ ($cnt_in, $str) = $ob->read(1);
+ if ( ord($str) != 6 ) {
+ warn "SETTIME not set!"; return 0;
+ }
+ sleep 3; # The console seems to need to some time here...
+}
+
+sub get_loop
+{
+ print "** get loop at ", scalar localtime, "\n";
+ my $loops=1;
+ $ob->write("LOOP $loops\n");
+ $ob->read_interval(0);
+ ($count, $result) = $ob->read(1);
+ for (my $i=0; $i<$loops; $i+=1) {
+ my $rc=loop_dump();
+ if ($rc!=0) {
+ last;
+ }
+ }
+ return;
+
+}
+
+sub loop_dump
+{
+ $ob->read_interval(0);
+ ($count, $result) = $ob->read(99);
+ if ($count != 99) {
+ print "loop error - got $count bytes, expected 99\n";
+ return 1;
+ }
+ print "LOOP data received\n";
+
+ if (ord(substr($result,0,1))==6) {
+ $result=substr($result,1);
+ }
+
+ my $rc=parse_loop_blck($result);
+ if ($rc!=0) {
+ return;
+ } # bad crc so goto next
+ foreach my $key (sort keys %hsh) {
+ print "$key = $hsh{$key}\n";
+ }
+
+ my $stmt = 'INSERT INTO current (Date_Time,' . join(',', keys %hsh) . ') VALUES (NOW(),' . join(',', ('?') x keys %hsh) . ')';
+
+ $dbh->do( $stmt, undef, values %hsh);
+
+ %hsh=();
+ return 0;
+}
+
+
+sub do_dmpaft
+{
+ #my $self = shift @_;
+ open(DMP,">dump.txt");
+ my $vDateStamp = shift @_;
+ my $vTimeStamp = shift @_;
+
+ # If not date/time stamp then assume 0 which will down load the entire archive
+ unless ( $vDateStamp ) {
+ $vDateStamp = 0;
+ }
+ unless ( $vTimeStamp ) {
+ $vTimeStamp = 0;
+ }
+
+ #my $port_obj = $self->{'port_obj'};
+
+ my $datetime = pack("ss",$vDateStamp, $vTimeStamp);
+
+ my $crc = CRC_CCITT($datetime);
+ my $cmd = pack("ssn",$vDateStamp,$vTimeStamp,$crc);
+
+ #-----------------------
+ #my $str = unpack("H*", $cmd);
+ #$str =~ s/(\w{2})/$1 /g;
+ # Documentation is wrong! The example should be <0xC6><0x06><0xA2><0x03> in section X
+ #print "cmd : $str \n";exit;
+ #-----------------------
+
+ #sleep 2; # Needed after loop
+ #$self->wake_up();
+
+ # Ok let's start the communication sequence....
+ my $cnt_out = $ob->write("DMPAFT\n");
+ unless ($cnt_out) {
+ warn "write failed\n";
+ }
+ ;
+
+ $ob->read_interval(300);
+ my ($cnt_in, $str) = $ob->read(1);
+
+ my $ack = ord $str;
+ unless ($ack == 6) {
+ warn "Ack not received on DMPAFT command: $ack"; exit -1;
+ }
+
+ $cnt_out = $ob->write($cmd);
+ unless ($cnt_out) {
+ warn "write failed\n";
+ }
+ ;
+ ($cnt_in, $str) = $ob->read(7);
+
+ $ack = ord substr($str,0,1);
+
+ my $ls = unpack("H20",substr($str,1,4) );
+ $ls =~ s/(\w{2})/$1 /g;
+
+ my $pages = unpack("s",substr($str,1,2) );
+ my $rec_start = unpack("s",substr($str,3,2) );
+
+ $crc = CRC_CCITT(substr($str,1,6) );
+
+ print "Pages = $pages : rec = $rec_start Datestamp $vDateStamp $crc\n";
+
+ $cnt_out = $ob->write( pack("h", 0x06) );
+
+ #if ($pages == 513 ) { return -1 }
+
+ my @arc_rec_lst;
+ foreach my $page (1..$pages) {
+ my $page_sz = 267;
+ $ob->read_interval(0);
+ my ($cnt_in, $str) = $ob->read($page_sz); #,3
+ printf("len=%s\n",length($str));
+ if ($cnt_in!=$page_sz) {
+ dienice("hmm, dmpaft only got $cnt_in bytes. was expecting $page_sz");
+ }
+ print "Page $page\n";
+ #print DMP $str,"\n";
+ #print "ACK receipt of page $page\n";
+ #$ob->write( pack("h", 0x06) );
+ #next;
+ my $calc_crc = CRC_CCITT($str);
+ my $crc = unpack "%n", substr($str,265,2);
+ print "page crc=$crc, calc_crc=$calc_crc\n";
+ my $rec_sz = 52;
+ my $date_prev = 0;
+ my %hsh;
+
+ foreach my $rec ( 0..4 ) {
+ if ( ($page == 1) && ($rec < $rec_start ) ) {
+ next;
+ } # Find the right starting point...
+
+ my $start_ptr = 1 + ($rec * $rec_sz );
+ my $rec_str = substr($str, $start_ptr ,52);
+
+ #print "$start_ptr \t > " . unpack( "h*", $rec_str) . "\n";
+
+ my $date = substr($rec_str,0,2);
+ my $date_curr = unpack "s", $date;
+
+ # Check if we have wrapped...
+ if ( $date_curr < $date_prev ) {
+ last;
+ }
+ $date_prev = $date_curr;
+
+ $hsh{'date_stamp'} = $date_curr;
+ $hsh{'time_stamp'} = unpack "s", substr($rec_str,2,2);
+
+ $hsh{'day'} = unpack( "c", $date & pack("c",0x1F) );
+ $hsh{'month'} = ( $hsh{'date_stamp'} >> 5) & 0xF;
+ $hsh{'year'} = ( $hsh{'date_stamp'} >> 9) + 2000;
+
+ $hsh{'hour'} = sprintf("%02d", int ( $hsh{'time_stamp'} / 100 ));
+
+ $hsh{'min'} = $hsh{'time_stamp'} - ($hsh{'hour'} * 100);
+ $hsh{'min'} = sprintf("%02d", $hsh{'min'});
+
+ $hsh{'time_stamp_fmt'} = "$hsh{'hour'}:$hsh{'min'}:00";
+ $hsh{'date_stamp_fmt'} = "$hsh{'year'}_$hsh{'month'}_$hsh{'day'}";
+
+ #$hsh{'unixtime'} = timelocal(0,$hsh{min}, $hsh{hour}, $hsh{day}, $hsh{month}-1, $hsh{year}-1900);
+
+ $hsh{'Air_Temp'} = unpack("s", substr($rec_str,4,2)) / 10;
+ $hsh{'Air_Temp_Hi'} = unpack("s", substr($rec_str,6,2)) / 10;
+ $hsh{'Air_Temp_Lo'} = unpack("s", substr($rec_str,8,2)) / 10;
+ $hsh{'Rain_Clicks'} = unpack("s", substr($rec_str,10,2));
+ $hsh{'Rain_Rate'} = unpack("s", substr($rec_str,12,2)) / 100; # Inches per hour
+ $hsh{'Barometric_Press'} = unpack("s", substr $rec_str,14,2) / 1000;
+ $hsh{'Solar'} = unpack("s", substr $rec_str,16,2); # watt/m**2
+ $hsh{'Wind_Samples'} = unpack("s", substr $rec_str,18,2);
+ $hsh{'Air_Temp_Inside'} = unpack("s", substr $rec_str,20,2) / 10;
+
+ $hsh{'Relative_Humidity_Inside'} = unpack("C", substr $rec_str,22,1);
+ $hsh{'Relative_Humidity'} = unpack("C", substr $rec_str,23,1);
+
+ $hsh{'Wind_Speed'} = unpack("C", substr($rec_str,24,1));
+ $hsh{'Wind_Gust_Max'} = unpack("C", substr($rec_str,25,1));
+ $hsh{'Wind_Dir_Max'} = unpack("C", substr($rec_str,26,1));
+ $hsh{'Wind_Dir'} = unpack("C", substr($rec_str,27,1));
+
+ $hsh{'UV'} = unpack("C", substr($rec_str,28,1)) / 10;
+ $hsh{'ET'} = unpack("C", substr($rec_str,29,1)) / 1000;
+
+ $hsh{'Solar_Max'} = unpack("s", substr($rec_str,30,2));
+ $hsh{'UV_Max'} = unpack("C", substr($rec_str,32,1));
+
+ $hsh{'Forecast_Rule'} = unpack("C", substr($rec_str,33,1));
+
+# $hsh{'Dew_Point'} = _dew_point($hsh{'Air_Temp'},$hsh{'Relative_Humidity'});
+
+ # Miscellaneous others omitted for now
+
+ print "date> $hsh{'Air_Temp'} $hsh{'time_stamp'} $hsh{'time_stamp_fmt'} $hsh{'date_stamp'} $hsh{'date_stamp_fmt'}\n";
+ #print Dumper \%hsh;
+
+ push @arc_rec_lst, {%hsh};
+ }
+
+ #$in = ; # Testing step through facility
+ #if ($in =~ /q/i ) { $port_obj->write( pack("h", 0x1B) ); last; }
+ #else { $port_obj->write( pack("h", 0x06) ); }
+ print "ACK receipt of page\n";
+ $ob->write( pack("h", 0x06) );
+
+ }
+ close DMP;
+}
+
+package Device::SerialPort;
+
+sub read_interval
+{
+
+}
diff --git a/yr.php b/yr.php
new file mode 100644
index 0000000..22bb30d
--- /dev/null
+++ b/yr.php
@@ -0,0 +1,763 @@
+
+
+ ###### Changelog
+
+ Versjon: 2.6 - Lennart André Rolland (lennart.andre.rolland@nrk.no) / NRK - 2008.11.11 11:48
+ * Added option to remove banner ($yr_use_banner)
+ * Added option to allow any target for yr.no urls ($yr_link_target)
+
+ Versjon: 2.5 - Lennart André Rolland (lennart.andre.rolland@nrk.no) / NRK - 2008.09.25 09:24
+ * Cache will now update on parameter changes (cache file is prefixed with md5 digest of all relevant parameters)
+ This change will in the future make it easier to use the script for multiple locations in one go.
+ * Most relevant comments translated to english
+
+ Versjon 2.4 - Sven-Ove Bjerkan (sven-ove@smart-media.no) / Smart-Media AS - 2008.10.22 12:14
+ * Endret funksjonalitet ifbm med visning av PHP-feil (fjernet blant annet alle "@", dette styres av error_reporting())
+ * Ved feilmelding så ble denne lagret i lokal cache slik at man fikk opp feilmld hver gang inntil "$yr_maxage" inntreffer og den forsøker å laste på nytt - den cacher nå ikke hvis det oppstår en feil
+ * $yr_use_text, $yr_use_links og $yr_use_table ble overstyrt til "true" uavhengig av brukerens innstilling - rettet!
+
+ Versjon: 2.3 - Lennart André Rolland (lennart.andre.rolland@nrk.no) / NRK - 2008.09.25 09:24
+ * File permissions updated
+ * Caching is stored in HTML isntead of XML for security
+ * Other security and efficiency improvements
+
+
+
+ ###### INSTRUCTIONS:
+
+ 1. Only edit this script in editors with ISO-8859-1 or ISO-8859-15 character set.
+ 2. Edit the settings below
+ 3. Transfer the script to a folder in your webroot.
+ 4. Make sure that the webserver has write access to the folder where thsi script is placed. It will create a folder called yr-cache and place cached HTML data in that directory.
+
+ */
+
+/// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /
+/// /// /// /// /// Settings /// /// /// /// /// /// /// /// //
+// /// /// /// /// /// /// /// /// /// /// /// /// /// /// ///
+
+// 1. Lenke: Lenke til stedet på yr.no (Uten siste skråstrek. Bruk vanlig æøå i lenka )
+// Link: Link to the url for the location on yr.no (Without the last Slash.)
+$yr_url='http://www.yr.no/sted/Norge/Vest-Agder/Lyngdal/Kvås';
+$yr_url='http://www.yr.no/stad/Sverige/Jämtland/Lofsdalen';
+
+// 2. Stedsnavnet: Skriv inn navnet på stedet. La stå tom for å falle tilbake til navnet i lenken
+// Location: The name of the location. Leave empty to fallback to the location in the url.
+$yr_name='';
+
+// 3. Bruk header og footer: Velg om du vil ha med header og/eller footer
+// Use Header and footers: Select to have HTML headers/footers wrapping the content (useful for debugging)
+//PS: Header for HTML dokumentet er XHTML 1.0 Strict
+// Skrus som regel av når du inlemmer i eksisterende dokument!
+//
+$yr_use_header=$yr_use_footer=true;
+
+// 4. Deler: Velg delene av varselet du vil ta med!
+// Parts: Choose which parts of the forecast to include
+$yr_use_banner=true; //yr.no Banner
+$yr_use_text=false; //Tekstvarsel
+$yr_use_links=true; //Lenker til varsel på yr.no
+$yr_use_table=true; //Tabellen med varselet
+
+// 5. Mellomlagringstid: Antall sekunder før nytt varsel hentes fra yr.no.
+// Cachetime: Number of seconds to keep forecast in local cache
+// Den anbefalt verdien på 1200 vil oppdatere siden hver 20. minutt.
+//
+// PS: Vi ønsker at du setter 20 minutters mellomlagringstid fordi
+// det vil gi høyere ytelse, både for yr.no og deg! MEN for å få til dette
+// vil vi opprette en mappe og lagre en fil i denne mappen. Vi har gått
+// gjennom scriptet veldig nøye for å forsikre oss om at det er feilfritt.
+// Likevel er dette ikke helt uproblematisk i forhold til sikkerhet.
+// Hvis du har problemer med dette kan du sette $yr_maxage til 0 for å skru
+// av mellomlagringen helt!
+$yr_maxage=1200;
+
+// 6. Utløpstid: Denne instillingen lar deg velge hvor lenge yr.no har på å
+// levere varselet i sekunder.
+// Timeout: How long before this script gives up fetching data from yr.no
+//
+// Hvis yr.no skulle være nede eller det er
+// forstyrrelser i båndbredden ellers, vil varselet erstattes med en
+// feilmelding til situasjonen er bedret igjen. PS: gjelder kun når nytt
+// varsel hentes! Påvirker ikke varsel mens siden viser varsel fra
+// mellomlageret. Den anbefalte verdien på 10 sekunder fungerer bra.
+$yr_timeout=10;
+
+// 7. Mellomlagrinsmappe: Velg navn på mappen til mellomlagret data.
+// Cachefolder: Where to put cache data
+//
+//Dette scriptet vil forsøke å opprette mappen om den ikke finnes.
+$yr_datadir='yr_cache';
+
+
+// 8. Lenke mål: Velg hvilken target som skal brukes på lenker til yr.no
+// Link target: Choose which target to use for links to yr.no
+$yr_link_target='_top';
+
+// 9. Vis feilmeldinger: Sett til "true" hvis du vil ha feilmeldinger.
+// Show errors: Useful while debugging.
+//
+//greit ved feilsøking, men bør ikke være aktivert i drift.
+$yr_vis_php_feilmeldinger=true;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /
+/// /// /// /// /// Code /// /// /// /// /// /// /// /// /// //
+// /// /// /// /// /// /// /// /// /// /// /// /// /// /// ///
+// Skru på feilmeldinger i starten
+if($yr_vis_php_feilmeldinger) {
+ error_reporting(E_ALL);
+ ini_set('display_errors', true);
+}
+else {
+ error_reporting(0);
+ ini_set('display_errors', false);
+}
+
+//Opprett en komunikasjon med yr
+$yr_xmlparse = &new YRComms();
+//Opprett en presentasjon
+$yr_xmldisplay = &new YRDisplay();
+
+$yr_try_curl=true;
+
+//Gjenomfør oppdraget basta bom.
+die($yr_xmldisplay->generateHTMLCached($yr_url, $yr_name, $yr_xmlparse, $yr_url, $yr_try_curl, $yr_use_header, $yr_use_footer, $yr_use_banner, $yr_use_text, $yr_use_links, $yr_use_table, $yr_maxage, $yr_timeout, $yr_link_target));
+
+
+/// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /
+/// /// /// /// /// Hjelpekode starter her /// /// /// /// /// //
+// /// /// /// /// /// /// /// /// /// /// /// /// /// /// ///
+
+
+function retar($array, $html = false, $level = 0) {
+ if(is_array($array)){
+ $space = $html ? " " : " ";
+ $newline = $html ? " " : "\n";
+ $spaces='';
+ for ($i = 1; $i <= 3; $i++)$spaces .= $space;
+ $tabs=$spaces;
+ for ($i = 1; $i <= $level; $i++)$tabs .= $spaces;
+ $output = "Array(" . $newline . $newline;
+ $cnt=sizeof($array);
+ $j=0;
+ foreach($array as $key => $value) {
+ $j++;
+ if (is_array($value)) {
+ $level++;
+ $value = retar($value, $html, $level);
+ $level--;
+ }
+ else $value="'$value'";
+ $output .= "$tabs'$key'=> $value";
+ if($j<$cnt)$output .= ',';
+ $output .= $newline;
+ }
+ $output.=$tabs.')'.$newline;
+ }
+ else{
+ $output="'$array'";
+ }
+ return $output;
+}
+
+
+// Klasse for lesing og tilrettelegging av YR data
+class YRComms{
+
+ //Generer gyldig yr.no array med værdata byttet ut med en enkel feilmelding
+ private function getYrDataErrorMessage($msg="Feil"){
+ return Array(
+ '0'=> Array('tag'=> 'WEATHERDATA','type'=> 'open','level'=> '1'),
+ '1'=> Array('tag'=> 'LOCATION','type'=> 'open','level'=> '2'),
+ '2'=> Array('tag'=> 'NAME','type'=> 'complete','level'=> '3','value'=> $msg),
+ '3'=> Array('tag'=> 'LOCATION','type'=> 'complete','level'=> '3'),
+ '4'=> Array( 'tag'=> 'LOCATION', 'type'=> 'close', 'level'=> '2'),
+ '5'=> Array( 'tag'=> 'FORECAST', 'type'=> 'open', 'level'=> '2'),
+ '6'=> Array( 'tag'=> 'ERROR', 'type'=> 'complete', 'level'=> '3', 'value'=> $msg),
+ '7'=> Array( 'tag'=> 'FORECAST', 'type'=> 'close', 'level'=> '2'),
+ '8'=> Array( 'tag'=> 'WEATHERDATA', 'type'=> 'close', 'level'=> '1')
+ );
+ }
+
+ //Generer gyldig yr.no XML med værdata byttet ut med en enkel feilmelding
+ private function getYrXMLErrorMessage($msg="Feil"){
+ $msg=$this->getXMLEntities($msg);
+ //die('errmsg:'.$msg);
+ $data=<<
+
+
+ $msg
+
+
+
+
+
+
+EOT
+ ;
+ //die($data);
+ return $data;
+ }
+
+ // Sørger for å laste ned XML fra yr.no og leverer data tilbake i en streng
+ private function loadXMLData($xml_url,$try_curl=true,$timeout=10){
+ global $yr_datadir;
+ $xml_url.='/varsel.xml';
+ // Lag en timeout på contexten
+ $ctx = stream_context_create(array( 'http' => array('timeout' => $timeout)));
+
+ // Prøv å åpne direkte først
+ //NOTE: This will spew ugly errors even when they are handled later. There is no way to avoid this but prefixing with @ (slow) or turning off error reporting
+ $data=file_get_contents($xml_url,0,$ctx);
+
+ if(false!=$data){
+ //Jippi vi klarte det med vanlig fopen url wrappers!
+ }
+ // Vanlig fopen_wrapper feilet, men vi har cURL tilgjengelig
+ else if($try_curl && function_exists('curl_init')){
+ $lokal_xml_url = $yr_datadir .'/curl.temp.xml';
+ $data='';
+ $ch = curl_init($xml_url);
+ // Åpne den lokale temp filen for skrive tilgang (med cURL hooks enablet)
+ $fp = fopen($lokal_xml_url, "w");
+ // Last fra yr.no til lokal kopi med curl
+ curl_setopt($ch, CURLOPT_FILE, $fp);
+ curl_setopt($ch, CURLOPT_HEADER, 0);
+ curl_setopt($ch, CURLOPT_POSTFIELDS, '');
+ curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
+ curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
+ curl_exec($ch);
+ curl_close($ch);
+ // Lukk lokal kopi
+ fclose($fp);
+ // Åpne lokal kopi igjen og les in alt innholdet
+ $data=file_get_contents($lokal_xml_url,0,$ctx);
+ //Slett temp data
+ unlink($lokal_xml_url);
+ // Sjekk for feil
+ if(false==$data)$data=$this->getYrXMLErrorMessage('Det oppstod en feil mens værdata ble lest fra yr.no. Teknisk info: Mest antakelig: kobling feilet. Nest mest antakelig: Det mangler støtte for fopen wrapper, og cURL feilet også. Minst antakelig: cURL har ikke rettigheter til å lagre temp.xml');
+ }
+ // Vi har verken fopen_wrappers eller cURL
+ else{
+ $data=$this->getYrXMLErrorMessage('Det oppstod en feil mens værdata ble forsøkt lest fra yr.no. Teknisk info: Denne PHP-installasjon har verken URL enablede fopen_wrappers eller cURL. Dette gjør det umulig å hente ned værdata. Se imiddlertid følgende dokumentasjon: http://no.php.net/manual/en/wrappers.php, http://no.php.net/manual/en/book.curl.php');
+ //die('
LO:'.retar($data));
+ }
+ //die('
XML for:'.$xml_url.' WAS: '.$data);
+ // Når vi har kommet hit er det noe som tyder på at vi har lykkes med å laste værdata, ller i det minste lage en teilmelding som beskriver eventuelle problemer
+ return $data;
+ }
+
+ // Last XML til en array struktur
+ private function parseXMLIntoStruct($data){
+ global $yr_datadir;
+ $parser = xml_parser_create('ISO-8859-1');
+ if((0==$parser)||(FALSE==$parser))return $this->getYrDataErrorMessage('Det oppstod en feil mens værdata ble forsøkt hentet fra yr.no. Teknisk info: Kunne ikke lage XML parseren.');
+ $vals = array();
+ //die('
'.retar($data).'
');
+ if(FALSE==xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1))return $this->getYrDataErrorMessage('Det oppstod en feil mens værdata ble forsøkt hentet fra yr.no. Teknisk info: Kunne ikke stille inn XML-parseren.');
+ if(0==xml_parse_into_struct($parser, $data, $vals, $index))return $this->getYrDataErrorMessage('Det oppstod en feil mens værdata ble forsøkt hentet fra yr.no. Teknisk info: Parsing av XML feilet.');
+ if(FALSE==xml_parser_free($parser))return $this->getYrDataErrorMessage('Det oppstod en feil mens værdata ble forsøkt hentet fra yr.no. Kunne ikke frigjøre XML-parseren.');
+ //die('
'.retar($vals).'
');
+ return $vals;
+ }
+
+
+ // Rense tekst data (av sikkerhetshensyn)
+ private function sanitizeString($in){
+ //return $in;
+ if(is_array($in))return $in;
+ if(null==$in)return null;
+ return htmlentities(strip_tags($in));
+ }
+
+ // Rense tekst data (av sikkerhetshensyn)
+ public function reviveSafeTags($in){
+ //$in=$in.'STRONGUNDERLINEBOLDITALICS';
+ return str_ireplace(array('<strong>','</strong>','<u>','</u>','<b>','</b>','<i>','</i>'),array('','','','','','','',''),$in);
+ }
+
+
+
+ private function rearrangeChildren($vals, &$i) {
+ $children = array(); // Contains node data
+ // Sikkerhet: sørg for at all data som parses strippes for farlige ting
+ if (isset($vals[$i]['value']))$children['VALUE'] = $this->sanitizeString($vals[$i]['value']);
+ while (++$i < count($vals)){
+ // Sikkerhet: sørg for at all data som parses strippes for farlige ting
+ if(isset($vals[$i]['value']))$val=$this->sanitizeString($vals[$i]['value']);
+ else unset($val);
+ if(isset($vals[$i]['type']))$typ=$this->sanitizeString($vals[$i]['type']);
+ else unset($typ);
+ if(isset($vals[$i]['attributes']))$atr=$this->sanitizeString($vals[$i]['attributes']);
+ else unset($atr);
+ if(isset($vals[$i]['tag']))$tag=$this->sanitizeString($vals[$i]['tag']);
+ else unset($tag);
+ // Fyll inn strukturen vær slik vi vil ha den
+ switch ($vals[$i]['type']){
+ case 'cdata': $children['VALUE']=(isset($children['VALUE']))?$val:$children['VALUE'].$val; break;
+ case 'complete':
+ if (isset($atr)) {
+ $children[$tag][]['ATTRIBUTES'] = $atr;
+ $index = count($children[$tag])-1;
+ if (isset($val))$children[$tag][$index]['VALUE'] = $val;
+ else $children[$tag][$index]['VALUE'] = '';
+ } else {
+ if (isset($val))$children[$tag][]['VALUE'] = $val;
+ else $children[$tag][]['VALUE'] = '';
+ }
+ break;
+ case 'open':
+ if (isset($atr)) {
+ $children[$tag][]['ATTRIBUTES'] = $atr;
+ $index = count($children[$tag])-1;
+ $children[$tag][$index] = array_merge($children[$tag][$index],$this->rearrangeChildren($vals, $i));
+ } else $children[$tag][] = $this->rearrangeChildren($vals, $i);
+ break;
+ case 'close': return $children;
+ }
+ }
+ }
+ // Ommøbler data til å passe vårt formål, og returner
+ private function rearrangeDataStruct($vals){
+ //die('
".retar($tree));
+ //Hent ut det vi bryr oss om
+ if(isset($tree['WEATHERDATA'][0]['FORECAST'][0]))return $tree['WEATHERDATA'][0]['FORECAST'][0];
+ else return YrComms::getYrDataErrorMessage('Det oppstod en feil ved behandling av data fra yr.no. Vennligst gjør administrator oppmerksom på dette! Teknisk: data har feil format.');
+ }
+
+ // Hovedmetode. Laster XML fra en yr.no URI og parser denne
+ public function getXMLTree($xml_url, $try_curl, $timeout){
+ // Last inn XML fil og parse til et array hierarcki, ommøbler data til å passe vårt formål, og returner
+ return $this->rearrangeDataStruct($this->parseXMLIntoStruct($this->loadXMLData($xml_url,$try_curl,$timeout)));
+ }
+
+ // Statisk hjelper for å parse ut tid i yr format
+ public function parseTime($yr_time, $do24_00=false){
+ $yr_time=str_replace(":00:00", "", $yr_time);
+ if($do24_00)$yr_time=str_replace("00", "24", $yr_time);
+ return $yr_time;
+ }
+
+ // Statisk hjelper for å besørge riktig encoding ved å oversette spesielle ISO-8859-1 karakterer til HTML/XHTML entiteter
+ public function convertEncodingEntities($yrraw){
+ $conv=str_replace("æ", "æ", $yrraw);
+ $conv=str_replace("ø", "ø", $conv);
+ $conv=str_replace("å", "å", $conv);
+ $conv=str_replace("Æ", "Æ", $conv);
+ $conv=str_replace("Ø", "Ø", $conv);
+ $conv=str_replace("Å", "Å", $conv);
+ return $conv;
+ }
+
+ // Statisk hjelper for å besørge riktig encoding vedå oversette spesielle UTF karakterer til ISO-8859-1
+ public function convertEncodingUTF($yrraw){
+ $conv=str_replace("æ", "æ", $yrraw);
+ $conv=str_replace("ø", "ø", $conv);
+ $conv=str_replace("Ã¥", "å", $conv);
+ $conv=str_replace("Ã", "Æ", $conv);
+ $conv=str_replace("Ã", "Ø", $conv);
+ $conv=str_replace("Ã ", "Å", $conv);
+ return $conv;
+ }
+
+
+ public function getXMLEntities($string){
+ return preg_replace('/[^\x09\x0A\x0D\x20-\x7F]/e', '$this->_privateXMLEntities("$0")', $string);
+ }
+
+ private function _privateXMLEntities($num){
+ $chars = array(
+ 128 => '€', 130 => '‚',
+ 131 => 'ƒ', 132 => '„',
+ 133 => '…', 134 => '†',
+ 135 => '‡',136 => 'ˆ',
+ 137 => '‰',138 => 'Š',
+ 139 => '‹',140 => 'Œ',
+ 142 => 'Ž', 145 => '‘',
+ 146 => '’',147 => '“',
+ 148 => '”',149 => '•',
+ 150 => '–',151 => '—',
+ 152 => '˜',153 => '™',
+ 154 => 'š',155 => '›',
+ 156 => 'œ',158 => 'ž',
+ 159 => 'Ÿ');
+ $num = ord($num);
+ return (($num > 127 && $num < 160) ? $chars[$num] : "".$num.";" );
+ }
+}
+
+// Klasse for å vise data fra yr. Kompatibel med YRComms sin datastruktur
+class YRDisplay{
+
+ // Akkumulator variabl for å holde på generert HTML
+ var $ht='';
+ // Yr Url
+ var $yr_url='';
+ // Yr stedsnavn
+ var $yr_name='';
+ // Yr data
+ var $yr_data=Array();
+
+ //Filename for cached HTML. MD5 hash will be prepended to allow caching of several pages
+ var $datafile='yr.html';
+ //The complete path to the cache file
+ var $datapath='';
+
+ // Norsk grovinndeling av de 360 grader vindretning
+ var $yr_vindrettninger=array(
+ 'nord','nord-nordøst','nordøst','øst-nordøst',
+ 'øst','øst-sørøst','sørøst','sør-sørøst',
+ 'sør','sør-sørvest', 'sørvest','vest-sørvest',
+ 'vest', 'vest-nordvest','nordvest', 'nord-nordvest', 'nord');
+
+ // Hvor hentes bilder til symboler fra?
+ var $yr_imgpath='http://fil.nrk.no/yr/grafikk/sym/b38';
+
+
+ //Generer header for varselet
+ public function getHeader($use_full_html){
+ // Her kan du endre header til hva du vil. NB! Husk å skru det på, ved å endre instillingene i toppen av dokumentet
+ if($use_full_html){
+ $this->ht.=<<
+
+
+
+ Værvarsel fra yr.no
+
+
+
+
+EOT
+ ;
+ }
+ $this->ht.=<<
+
+EOT
+ ;
+ }
+
+ //Generer footer for varselet
+ public function getFooter($use_full_html){
+ $this->ht.=<<
+
+EOT
+ ;
+ // Her kan du endre footer til hva du vil. NB! Husk å skru det på, ved å endre instillingene i toppen av dokumentet
+ if($use_full_html){
+ $this->ht.=<<
+
+
+EOT
+ ;
+ }
+ }
+
+
+ //Generer Copyright for data fra yr.no
+ public function getBanner($target='_top'){
+ $url=YRComms::convertEncodingEntities($this->yr_url);
+ $this->ht.=<<
+
+EOT
+ ;
+ }
+
+
+ //Generer Copyright for data fra yr.no
+ public function getCopyright($target='_top'){
+ $url=YRComms::convertEncodingEntities($this->yr_url);
+ /*
+ Du må ta med teksten nedenfor og ha med lenke til yr.no.
+ Om du fjerner denne teksten og lenkene, bryter du vilkårene for bruk av data fra yr.no.
+ Det er straffbart å bruke data fra yr.no i strid med vilkårene.
+ Du finner vilkårene på http://www.yr.no/verdata/1.3316805
+ */
+ $this->ht.=<<Værvarsel for $this->yr_name
+
+
+EOT
+ ;
+ }
+
+
+ //Generer tekst for været
+ public function getWeatherText(){
+ if((isset($this->yr_data['TEXT'])) && (isset($this->yr_data['TEXT'][0]['LOCATION']))&& (isset($this->yr_data['TEXT'][0]['LOCATION'][0]['ATTRIBUTES'])) ){
+ $yr_place=$this->yr_data['TEXT'][0]['LOCATION'][0]['ATTRIBUTES']['NAME'];
+ if(!isset($this->yr_data['TEXT'][0]['LOCATION'][0]['TIME']))return;
+ foreach($this->yr_data['TEXT'][0]['LOCATION'][0]['TIME'] as $yr_var2){
+ // Små bokstaver
+ $l=(YRComms::convertEncodingUTF($yr_var2['TITLE'][0]['VALUE']));
+ // Rettet encoding
+ $e=YRComms::reviveSafeTags(YRComms::convertEncodingUTF($yr_var2['BODY'][0]['VALUE']));
+ // Spytt ut!
+ $this->ht.=<<$yr_place $l:$e
+
+EOT
+ ;
+ }
+ }
+ }
+
+ //Generer lenker til andre varsel
+ public function getLinks($target='_top'){
+ // Rens url
+ $url=YRComms::convertEncodingEntities($this->yr_url);
+ // Spytt ut
+ $this->ht.=<<$this->yr_name på yr.no:
+ Varsel med kart
+ Time for time
+ Helg
+ Langtidsvarsel
+
+
+EOT
+ ;
+ }
+
+ //Generer header for værdatatabellen
+ public function getWeatherTableHeader(){
+ $name=$this->yr_name;
+ $this->ht.=<<
+
+
+
+
+EOT
+ ;
+ list($thisyear, $thismonth, $thisdate)=explode('-', $fromdate);
+ $displaydate=$thisdate.".".$thismonth.".".$thisyear;
+ $firstcellcont=$displaydate;
+ $thisdate=$fromdate;
+ ++$dayctr;
+ }else $divider=$firstcellcont='';
+
+ // Vis ny dato
+ if($dayctr<7){
+ $this->ht.=$divider;
+ // Behandle symbol
+ $imgno=$yr_var3['SYMBOL'][0]['ATTRIBUTES']['NUMBER'];
+ if($imgno<10)$imgno='0'.$imgno;
+ switch($imgno){
+ case '01': case '02': case '03': case '05': case '06': case '07': case '08':
+ $imgno.="d"; $do_daynight=1; break;
+ default: $do_daynight=0;
+ }
+ // Behandle regn
+ $rain=$yr_var3['PRECIPITATION'][0]['ATTRIBUTES']['VALUE'];
+ if($rain==0.0)$rain="0";
+ else{
+ $rain=intval($rain);
+ if($rain<1)$rain='<1';
+ else $rain=round($rain);
+ }
+ $rain.=" mm";
+ // Behandle vind
+ $winddir=round($yr_var3['WINDDIRECTION'][0]['ATTRIBUTES']['DEG']/22.5);
+ $winddirtext=$this->yr_vindrettninger[$winddir];
+ // Behandle temperatur
+ $temper=round($yr_var3['TEMPERATURE'][0]['ATTRIBUTES']['VALUE']);
+ if($temper>=0)$tempclass='pluss';
+ else $tempclass='minus';
+
+ // Rund av vindhastighet
+ $r=round($yr_var3['WINDSPEED'][0]['ATTRIBUTES']['MPS']);
+ // Så legger vi ut hele den ferdige linjen
+ $s=$yr_var3['SYMBOL'][0]['ATTRIBUTES']['NAME'];
+ $w=$yr_var3['WINDSPEED'][0]['ATTRIBUTES']['NAME'];
+
+ $this->ht.=<<
+
$firstcellcont
+
$fromtime–$totime
+
+
$rain
+
$temper°
+
$w fra $winddirtext
+
$r m/s
+
+
+EOT
+ ;
+ }
+ }
+ }
+
+ //Generer footer for værdatatabellen
+ public function getWeatherTableFooter($target='_top'){
+ $this->ht.=<<
+
+
+
+
+
Værsymbolet og nedbørsvarselet gjelder for hele perioden, temperatur- og vindvarselet er for det første tidspunktet. <1 mm betyr at det vil komme mellom 0,1 og 0,9 mm nedbør.
+ Slik forstår du varslene fra yr.no.
+EOT
+ ;
+ }
+
+
+ // Handle cache directory (re)creation and cachefile name selection
+ private function handleDataDir($clean_datadir=false,$summary=''){
+ global $yr_datadir;
+ // The md5 sum is to avoid caching to the same file on parameter changes
+ $this->datapath=$yr_datadir .'/'. ($summary!='' ? (md5($summary).'['.$summary.']_') : '').$this->datafile;
+ // Delete cache dir
+ if ($clean_datadir) {
+ unlink($this->datapath);
+ rmdir($yr_datadir);
+ }
+ // Create new cache folder with correct permissions
+ if(!is_dir($yr_datadir))mkdir($yr_datadir,0300);
+ }
+
+
+ //Main with caching
+ public function generateHTMLCached($url,$name,$xml, $url, $try_curl, $useHtmlHeader=true, $useHtmlFooter=true, $useBanner=true, $useText=true, $useLinks=true, $useTable=true, $maxage=0, $timeout=10, $urlTarget='_top'){
+ //Default to the name in the url
+ if(null==$name||''==trim($name))$name=array_pop(explode('/',$url));
+ $this->handleDataDir(false,htmlentities("$name.$useHtmlHeader.$useHtmlFooter.$useBanner.$useText.$useLinks.$useTable.$maxage.$timeout.$urlTarget"));
+ $yr_cached = $this->datapath;
+ // Clean name
+ $name=YRComms::convertEncodingUTF($name);
+ $name=YRComms::convertEncodingEntities($name);
+ // Clean URL
+ $url=YRComms::convertEncodingUTF($url);
+ // Er mellomlagring enablet, og trenger vi egentlig laste ny data, eller holder mellomlagret data?
+ if(($maxage>0)&&((file_exists($yr_cached))&&((time()-filemtime($yr_cached))<$maxage))){
+ $data['value']=file_get_contents($yr_cached);
+ // Sjekk for feil
+ if(false==$data['value']){
+ $data['value']='
Det oppstod en feil mens værdata ble lest fra lokalt mellomlager. Vennligst gjør administrator oppmerksom på dette! Teknisk: Sjekk at rettighetene er i orden som beskrevet i bruksanvisningen for dette scriptet