#!/usr/bin/perl -w
# One code to rule them all!
#
# @#$mnm20100803 
# after an existing code from Brian Fahrlander https://help.ubuntu.com/community/1wireAppCountermoon.org#Sensorproc
#
use strict;
use warnings;
use POSIX;
use RRDs;

##############################################################################
# Program setup
##############################################################################

# we need global variables

#my $path_to_owfs = "/mnt/1-wire/uncached";
my $path_to_owfs = "/mnt/1-wire";
my $id_temp_boiler = "$path_to_owfs/28.227415020000";            # temp in drinking water heater
my $id_temp_bzu_luft = "$path_to_owfs/28.8C4615020000";          # temp of bathroom air
my $id_temp_fbh_rl = "$path_to_owfs/28.E35415020000";            # temp of floor heating water return
my $id_temp_fbh_vl = "$path_to_owfs/28.405C15020000";            # temp of floor heating water input (after the mixer)
my $id_temp_ofen_vl = "$path_to_owfs/28.8D3C15020000";           # temp of oven water input (after the mixer)
my $id_temp_ofen_oben = "$path_to_owfs/28.664515020000";         # temp of water at top of the oven (near output)
my $id_temp_ofen_rl = "$path_to_owfs/28.1C5015020000";           # temp of oven exhaust gas (indirect measurement) 
my $id_temp_puffer_unten = "$path_to_owfs/28.F13915020000";      # temp of heating water buffer lowest sensor
my $id_temp_puffer_untermitte = "$path_to_owfs/28.0F5715020000"; # temp of heating water buffer below the middle
my $id_temp_puffer_uebermitte = "$path_to_owfs/28.496D15020000"; # temp of heating water buffer above the middle
my $id_temp_puffer_oben = "$path_to_owfs/28.893015020000";       # temp of heating water buffer highest sensor
my $id_temp_hk_vl = "$path_to_owfs/28.A04A15020000";             # temp of radiant heaters water input (after the mixer)
my $id_temp_wzu_boden = "$path_to_owfs/28.2E4115020000";         # temp of living room floor
my $id_temp_wzu_luft = "$path_to_owfs/28.764A15020000";          # temp of living room air
my $id_temp_aussen = "$path_to_owfs/28.487A15020000";            # temp of outside temperature in 2m height


my $temp;      # variable for storing temperature values
my $str_temp;

# for rrd
# define location of rrdtool databases
my $rrd = '/home/srv/rrd/heatingtemps12.rrd';


# Comfort Norms and other values initialization


##############################################################################
# Subroutines Here
##############################################################################

# now do start up

sub startup {
   my $rrd = shift;
   my $time;
   my $error;

   if (! -e "$rrd")   {
      print "creating rrd database for sensors ...\n";
      $time = time();
      RRDs::create "$rrd",
# DS:variable_name:DST:heartbeat:min:max
# DS  - Data Source
# DST - Data Source Type
	"DS:temp_boiler:GAUGE:60:10:110",
	"DS:temp_bzu_luft:GAUGE:60:0:50",
	"DS:temp_fbh_vl:GAUGE:60:10:110",
	"DS:temp_fbh_rl:GAUGE:60:10:110",
	"DS:temp_ofen_vl:GAUGE:60:10:125",
	"DS:temp_ofen_rl:GAUGE:60:10:125",
	"DS:temp_ofen_oben:GAUGE:60:10:125",
	"DS:temp_puffer_unten:GAUGE:60:10:110",
	"DS:temp_puffer_um:GAUGE:60:10:110",
	"DS:temp_puffer_uem:GAUGE:60:10:110",
	"DS:temp_puffer_oben:GAUGE:60:10:110",
	"DS:temp_hk_vl:GAUGE:60:10:110",
	"DS:temp_wzu_boden:GAUGE:60:0:50",
	"DS:temp_wzu_luft:GAUGE:60:0:50",
	"DS:temp_aussen:GAUGE:60:-30:50",
	"--start=$time",
	"--step=30",
	##"--step=6",
# RRA:CF:xff:M*step:rows
# RRA - Round Robin Archive
# CF  - Consolidation Function can be AVERAGE, MINIMUM, MAXIMUM, and LAST
	"RRA:AVERAGE:0.5:1:85400";	# 1 samples / 30sec ...is 2 pro min, is 120 per min with 60 min in 1h with 24h per day for 30 days
					# N samples * (M * step sec)	/ 30 days / 24h / 60min / 60sec
					# 30 days * 24h * 60min * 60sec / (M * step sec) = N
					# 30 * 24 * 60 * 60 / (1 * 30) = 86400

	if ($error = RRDs::error) { die "$0: failed to create rrd $rrd: $error $!\n"; }
	}
}

# now do shut down
sub shutdown {
print "going bye bye...\n\n";
sleep(0.1);

exit;
}

# Write data to a file/device
sub wrdata {
  my ($address , $data) = @_;
  open (HANDLE, ">" . $address);
  print HANDLE $data;
  close (HANDLE);
}

# Write log to a file
sub wr_log {
  my ($file , $data) = @_;
  open HANDLE, ">>$file" or die "I could not open $file: $!";
  print HANDLE $data . "\n";
  close (HANDLE);
}

# Write to RRD
sub wrrrd {
   my $rrd = shift;
   my $temp = shift;
   my $error;
   my $sec, my $min, my $hour, my $mday, my $mon, my $year, my $wday, my $yday, my $isdst;
    


   # insert values into rrd
   RRDs::update "$rrd",
      #"-t", "boil",
      "N:$temp";
      	
   if ($error = RRDs::error) {
      print "$0: failed to insert data into rrd: $error\n"; }
   else {
     # ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
     # print "$hour".":"."$min".":"."$sec"." successfully updated $rrd with $temp"."degC\n"; 
        }
}

# read temperature from sensor
sub rdtemp {
   my ($address) = @_;
   my $temp;
   my $time;
  
   if (open HANDLE, "<$address/temperature10") {
      $temp = <HANDLE>;
      close (HANDLE);
      if (! defined($temp)) {
         $time = localtime(time);
         warn $time." - No value for $address/temperature10 was returned by owfs\n";
         warn "Setting it do -99\n";
         $temp = -99;
         #die;
      } 
    } else {
       warn "I could NOT open $address/temperature10: $!\n";
       #die;
       $temp = -99;
    }
      
  # string trimming leading and trailing blanks
  # 2009-MAR-17: GGARIEPY: [creation] (geoff.gariepy@gmail.com)
  $temp =~ s/^\s+|\s+$//g; # All the action happens in one regex!

  # Regex Notes:
  # ^ - anchors to the beginning of the string
  # $ - anchors to the end of the string
  # g - causes regex to match as many times as possible
  # | - logical OR
  
  # now we round to 1 place after the dot
  # those simple sensors don't have more resolution anyway
  
#test resolution again
#$temp = sprintf "%.1f", $temp;

  return $temp;
}

sub waitaminute {
   my $fullsec = shift;
   my $wait;
   
   $wait = ($fullsec -time() % $fullsec);       # now we wait to the next full second
   sleep ($wait);	# so, for fullsec = 60 it would be every full minute
   
}




##############################################################################
# Program startup
##############################################################################
# everything stay where it is - for now

##############################################################################
# Trap interrupts here for shutdown
##############################################################################
$SIG{'INT' } = 'shutdown';
$SIG{'QUIT'} = 'shutdown';
$SIG{'HUP' } = 'shutdown';
$SIG{'TRAP'} = 'shutdown';
$SIG{'ABRT'} = 'shutdown';
$SIG{'STOP'} = 'shutdown';

##############################################################################
# Main Loop
##############################################################################
# Here's where we do whatever needs to be done in this non-interrupt
# driven sequence of events
#
#init
startup($rrd);

while (1) {
    # wait for the next full 30 seconds
    waitaminute(30);

    $temp = rdtemp($id_temp_boiler);
    $str_temp = $temp;

    $temp = rdtemp($id_temp_bzu_luft);
    $str_temp = "$str_temp:$temp";

    $temp = rdtemp($id_temp_fbh_vl);
    $str_temp = "$str_temp:$temp";

    $temp = rdtemp($id_temp_fbh_rl);
    $str_temp = "$str_temp:$temp";

    $temp = rdtemp($id_temp_ofen_vl);
    if ($temp > 20) {               # sensor is mounted outside the pipe
        $temp = 1.17 * $temp - 3.0; # so we compensate for error
        }
    $str_temp = "$str_temp:$temp";

    $temp = rdtemp($id_temp_ofen_rl);
    $str_temp = "$str_temp:$temp";

    $temp = rdtemp($id_temp_ofen_oben);
    $str_temp = "$str_temp:$temp";

    $temp = rdtemp($id_temp_puffer_unten);
    $str_temp = "$str_temp:$temp";

    $temp = rdtemp($id_temp_puffer_untermitte);
    $str_temp = "$str_temp:$temp";

    $temp = rdtemp($id_temp_puffer_uebermitte);
    $str_temp = "$str_temp:$temp";

    $temp = rdtemp($id_temp_puffer_oben);
    $str_temp = "$str_temp:$temp";

    $temp = rdtemp($id_temp_hk_vl);
    $str_temp = "$str_temp:$temp";

    $temp = rdtemp($id_temp_wzu_boden);
    $str_temp = "$str_temp:$temp";

    $temp = rdtemp($id_temp_wzu_luft);
    $str_temp = "$str_temp:$temp";

    $temp = rdtemp($id_temp_aussen);
    $str_temp = "$str_temp:$temp";

    wrrrd($rrd, $str_temp);

}

