#!/usr/bin/perl


# PID File
$pidfile='/var/run/sump.pid';

use Device::SerialPort;
use DBI;
use LWP::Simple;
use Time::HiRes qw(usleep);



# Obtain directory from executed path $1=path, $2=file[
$_=$0;
m/(.*\/)(.*)/;

require $1.'sump.rev2.inc.pl';





# Set up the serial port
# 19200, 81N on the USB ftdi driver
my $port = Device::SerialPort->new($SERIALPORT);
$port->databits(8);
$port->baudrate($SERIALBAUD);
$port->parity("none");
$port->stopbits(1);


# Write Process ID to file
open (PIDFILE, '>',$pidfile);
print PIDFILE "$$\n";
close (PIDFILE);

$count=0;
$OldPump=-1;
$dbh = DBI->connect('DBI:mysql:'.$database.":$host",$user,$pw) or die("Can't connect to $host.$database!\n");

#$sql="INSERT INTO `pump` (`dt`,`status`) VALUES (CURRENT_TIMESTAMP , NULL);";
#$c = $dbh->do($sql);

	# On startup, add a NULL entry to Sump table	
	$sql = "INSERT INTO `$database`.`$sumptable` (`level`) VALUES (NULL);";
	$c = $dbh->do($sql);
	if(!$quiet) {print " Added $c NULL row to Sump\n";}
	# Sleep for a second
	sleep(2);


my $STALL_DEFAULT=1; # how many seconds to wait for new input
my $timeout=$STALL_DEFAULT;
$port->read_char_time(0);     # don't wait for each character
$port->read_const_time(1); # 1 second per unfulfilled "read" call


$port->lookclear;
	$oldlevel=500.0*$DMAX;		# Make sure level is updated on first loop by setting it absurdly high
print "Entering loop\n";
while(1) {
	$data='';
	until('' ne $data) {
		$data = $port->lookfor;       # poll until data ready
		usleep(1000);
	}
#	print "\n";
	@values=split(/,/,$data);
	if($values[1] eq "lvls") { process_levels(); }
	elsif($values[1] eq "alg") { process_analog(); }
	elsif($values[1] eq "1wire") { process_1wire(); }
	else{ print "Unknown: ".$values[1]."\n"; }
}
 	$dbh->disconnect();
#	if(!$quiet) {print "Could not connect to database: $DBI::errstr";}
$port->close();



################################ Subroutines #################################

sub process_levels() {
#print "Data: {$line}\n";
	$lvl_cistern=sprintf("%.2f",((($values[2]/1024)-0.04)/0.018)*4.01325981);
        $lvl_sump=sprintf("%.2f",((($values[3]/1024)-0.04)/0.09)*4.01325981);
	if($lvl_cistern<0) {$lvl_cistern=-0.01;}
	if($lvl_sump<0) {$lvl_sump=-0.01;}

	$Pump=$values[4];
	if($Pump!=$OldPump) {	# Update Pump Status
		if($Pump) {
			$sql="INSERT INTO `$database`.`$pumptable` (`status`) VALUES ('$Pump');";
			$c+= $dbh->do($sql);
			$lastid=$dbh->last_insert_id(undef,undef,$pumptable,"id");
		}elsif(defined($lastid)){
			$duration=$values[7]/1000.0;
			$sql="UPDATE `$database`.`$pumptable` SET `cycle` =  '$values[6]', `duration` =  '$duration',`status`='0' WHERE  `pump`.`id` =$lastid;";
#				print "$sql\n";
			$c+= $dbh->do($sql);
			undef($lastid);
			print "Pump ran for $duration seconds on cycle $values[6]\n";
	
			}
			$OldPump=$Pump;
			# Force sump level update on pump cycle
			$oldlvl_sump=-10;
		}

		# Calculate Cistern & Sump deltas
		$delta_sump=abs($lvl_sump-$oldlvl_sump);
		$delta_cistern=abs($lvl_cistern-$oldlvl_cistern);

		print "C: $count\tSump: ${lvl_sump}\tCistern: ${lvl_cistern}\tDelta_Sump: ";
		print sprintf("%.3f",$delta_sump);
		print "/".$delta{"sump"};
		print "\tDelta_Cistern: ";
		print sprintf("%.3f",$delta_cistern);
		print "/".$delta{"cistern"};
		
		print "\tPump: ";
		if($Pump) {
			print "On ";
		} else {
			print "Off";
		}
		$count++;
		if($time["sump"]!=time()) {
			if($delta{"sump"}<$delta_sump or (time()-$time["sump"])>$maxage{"sump"}) {
				$sql = "INSERT INTO `$database`.`$tablename` (`level`) VALUES ('$lvl_sump');";
				$c+= $dbh->do($sql);
			$oldlvl_sump=$lvl_sump;
			$count=0;
			$time["sump"]=time();
			}
		}





		if($time["cistern"]!=time()) {
			if($delta{"cistern"}<$delta_cistern or (time()-$time["cistern"])>$maxage{"cistern"}) {
				$sql = "INSERT INTO `$database`.`cistern` (`level`) VALUES ('$lvl_cistern');";
				$c+= $dbh->do($sql);
			$oldlvl_cistern=$lvl_cistern;
			$time["cistern"]=time();
			}
		}







	if(!$quiet & $c>0) {print "\tAdded $c row"; if($c>1) {print "s";}}
	
	$c=0;
	print "\n";	
}

sub process_analog(){
$vcc=$values[2]/1000;
$temp=$values[3];
print "Analog:\tVoltage: ".$vcc."V\tInternal Temperature: ".$temp."\xc2\xb0C\n";
}

sub process_1wire() {
$id=$values[2];
$serial=$values[3];
$temp=$values[4];
print "1W: $id\t";
if(!defined($IDwire->{$serial})) {
	$sql="SELECT id FROM `1wire` WHERE `serial` = \'$serial\'";
	$sth = $dbh->prepare($sql);
	$sth->execute();
	my ($rowid) = $sth->fetchrow();
	if(defined($rowid)) {
		$IDwire->{$serial}=$rowid;
		print "Found $serial in database, ID=$rowid\t";
	} else {
		$sql = "INSERT INTO `sump`.`1wire` (`serial`) VALUES (\'$serial\');";
		if($dbh->do($sql)) {
			$IDwire->{$serial}=$dbh->last_insert_id(undef,undef,"1wire","id");
			
		} else {
		print "Error inserting 1wire Serial into 1wire database!\n";
		}
	}
}else {
		print "Found $serial in cache, ID=$IDwire->{$serial}\t";
}
	if(defined($IDwire->{$serial})) {
	$myid=$IDwire->{$serial};
	if(!defined($IDTIMEwire->{$serial}->["time"])) {
		$sql = "SELECT TIME_TO_SEC(TIMEDIFF(NOW(),dt)),UNIX_TIMESTAMP(dt),celcius FROM `Temperature` WHERE `id`='$myid' ORDER BY `dt` DESC LIMIT 0,1";
		$sth = $dbh->prepare($sql);
		$sth->execute();
#		print "\nSQL HIT!\n";
		my ($age,$time,$celcius) = $sth->fetchrow();
		$IDTIMEwire->{$serial}->["time"]=$time;
	}
#	print "\ntime:\t".time()."\nage:\t";
#	print $IDTIMEwire->{$serial}->["time"];
#	print "\n";
	$age=(time()-$IDTIMEwire->{$serial}->["time"]);
	$last=$IDwire->{$serial}->["celcius"];
	print "Age: $age\tLast temp: $last\xc2\xb0C\tCurrent temp: $temp\xc2\xb0C";

	if(abs($temp-$IDwire->{$serial}->["celcius"])>$delta{"1wire"} or $age>$maxage{"1wire"} or !defined($age)) {
		$sql = "INSERT INTO `sump`.`Temperature` (`id`, `celcius`) VALUES (\'$IDwire->{$serial}\', \'$temp\')";

		if(!$dbh->do($sql)) { print "Error inserting Temperature into Database!\n"; }
		else {
			$c++;
			$IDTIMEwire->{$serial}->["time"]=time();
			$IDwire->{$serial}->["celcius"]=$temp;
		}
		
	}
	
}
	if(!$quiet & $c>0) {print "\t\tAdded $c row"; if($c>1) {print "s";}}

	$c=0;

print "\n";
}
