#!/usr/bin/perl -w
#
# Example code how to receive meteobridge "WL Cloud" data on your web server.
# Documentation of Davis Data logger formats (LOOP, HILOWS, DMPAFT) can be found here:
# https://www.davisinstruments.com/support/weather/download/VantageSerialProtocolDocs_v261.pdf
#

#use strict;
use HTTP::Request::Common qw(POST);
use HTTP::Headers;
use LWP::UserAgent;
use CGI::Carp qw(fatalsToBrowser);
use File::Path qw(mkpath);
use Sys::Syslog;
use POSIX;
use warnings;

my $tmpdir = "/var/run/wlcloud";	# <-- enter path of your temp folder here
my $wanip = $ENV{'REMOTE_ADDR'};

openlog ("WLCLOUD " . $wanip, "", "local0");
mkdir ($tmpdir) unless (-d $tmpdir);

print "Content-type: text/plain\n\n";

if ($ENV{'REQUEST_METHOD'} eq "PUT") 
{
  binmode STDIN;
  read (STDIN, $dest, $ENV{'CONTENT_LENGTH'})
                || die "could not get PUT data\n";
  
  my $len = $ENV{'CONTENT_LENGTH'};
  my $mode = vec ($dest, 1, 8);
  my $id = vec ($dest, 4, 8) * 65536 + vec ($dest, 5, 8) * 256+ vec ($dest, 6, 8);
  my $hexid = sprintf ("%06X", $id);
  my $ok = 0;

  if ($mode == 1)
  {
    # INIT data (64 bytes): 
    # - 64  bytes are a proprietary header
    $ok = 1;
    $tmpfn = $tmpdir . "/" . $hexid . "-init.dat";
  }
  if ($mode == 2)
  {
    # LOOP data (120 bytes): 
    # - first 20 bytes are a proprietary header
    # - followed by 92 bytes LOOP data starting at byte #4 of the LOOP definition
    # -trailing 8 bytes are proprietary again 
    $ok = 1;
    $tmpfn = $tmpdir . "/" . $hexid . "-loop.dat";
  }
  if ($mode == 4)
  {
    # HILOW data, first section (147 bytes): 
    # - first 11 bytes are a proprietary header
    # - followed by 126 bytes HILOWS data starting at byte #0 of the HILOWS definition
    # - trailing 10 bytes are proprietary again 
    $ok = 1;
    $tmpfn = $tmpdir . "/" . $hexid . "-hilows.dat";
  }
  if ($mode == 5)
  {
    # HILOW data, second section (321 bytes): 
    # - first 11 bytes are a proprietary header
    # - followed by 310 bytes HILOWS data starting at byte #126 of the HILOWS definition
    $ok = 1;
    $tmpfn = $tmpdir . "/" . $hexid . "-hilows2.dat";
  }
  if ($mode == 7)
  {
    # DMPAFT data (12 + n * 52 bytes, n=1..7): 
    # - first 11 bytes are a proprietary header
    # - followed by 1 byte indicating the number of records
    # - followed by 1-7 DMPAFT records, each 52 bytes long 
    $ok = 1;
    my $ix = (vec ($dest, 11, 8) - 1) * 52 + 12;
    my $ts = vec ($dest, $ix, 8) * 65536 + vec ($dest, $ix+1, 8) * 65536 * 256 + vec ($dest, $ix+2, 8) + vec ($dest, $ix+3, 8) * 256;
    my $year = floor (($ts >> 16) / 512) + 2000;
    my $mon = floor ((($ts >> 16) % 512) / 32);
    my $day = (($ts >> 16) % 512) % 32;
    my $hour = floor (($ts & 0xffff) / 100);
    my $min = ($ts & 0xffff) % 100; 
    my $tstr = sprintf ("%04d%02d%02d%02d%02d", $year, $mon, $day, $hour, $min);
    $tmpfn = $tmpdir . "/" . $hexid . "-dmpaft-" . $tstr . ".dat";
    open (MYFILE, ">" . $tmpdir .  "/" . $hexid . ".ts") || die "cannot open timestamp file for writing $!\n";
    print MYFILE $ts;
    close MYFILE;
  }

  if ($mode != 6) 
  {
    if ($ok == 1)
    {
      if (open (MYFILE, ">" . $tmpfn))
      {
        binmode MYFILE;
        print MYFILE $dest;
        close MYFILE;
        syslog ('info', "packet type #" . $mode . " from id " . $hexid . " with length " . $len . " written to file " . $tmpfn);
        print "0\n#WL*\n"
      }
      else
      {
        syslog ('warning', "Error: cannot write file " . $tmpfn );
        print "Error: cannot write file ". $tmpfn . "\n";
      }
    }
    else
    {
      syslog ('warning', "Bad Request, unknow packet type: " . $mode . "(length " . $len . ")");
      print "Bad Request: unknown packet type: " . $mode . "(length " . $len . ")\n"
    }
 
  }
  else
  {
    my $row = 0;
    if (open (my $fh, "<" . $tmpdir . "/" . $hexid . ".ts"))
    {
      $row = <$fh>;
      close ($fh);
    }
    syslog ('info', "timestamp " . $row . " handed over to " . $hexid);
    print "0\n$row\n#WL*\n";
  }
}
else 
{
  syslog ('warning', "not a PUT request"); 
  print "Bad Request: please submit data via HTTP PUT\n";
}

closelog ();
exit (0);
