The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package Device::Kiln;

use Device::DSE::Q1573;
use Device::Kiln::Orton;
use SVG::TT::Graph::TimeSeries;
use HTTP::Date qw(time2iso str2time);


use strict;

BEGIN {
	require Device::DSE::Q1573;
	use Exporter ();
	use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
	$VERSION     = '0.03';
	@ISA         = qw(Exporter);
	@EXPORT      = qw();
	@EXPORT_OK   = qw();
	%EXPORT_TAGS = ();

}

sub new {
	
	my $class = shift;
	my %config = %{$_[0]};
	


	my $self = bless( {}, ref($class) || $class );
	
	
	if( defined $config{'serialport'} ) {
		$self->{meter}      = Device::DSE::Q1573->new($config{serialport});
		$self->{serialport} = $config{serialport};
	}
		

	$self->{width}      = $config{'width'};
	$self->{height}     = $config{'height'};
	$self->{interval}   = $config{'interval'};
	$self->{rampuprate} = 150;
	$self->{tid}        = undef;
	$self->{datafile}   = '/tmp/q1573.tmp';
	$self->{cones}		= {
			'1 - 018' =>  	{ 
							60  => 712,
							100 => 722,
							150 => 732
							},
							
			'2 - 017' =>  	{
							60  => 736,
							100 => 748,
							150 => 761
							},
							
			'3 - 016' =>	{
							60  => 769,
							100 => 782,
							150 => 794
							},
							
						};
				
	$self->{maxtemp}	= [""];
	return $self;
}

sub run {


	my $self = shift;

	print $self->{file} . "\n";
	my $time  = 0;
	my $count = 0;

	my $fh;

	open( $fh, ">>", $self->{datafile} );
	$fh->autoflush(1);

	sleep 1;

	while (1) {
		
		my $time = time();
		my $raw = $self->{meter}->rawread();
		#print $raw. "\n";
		$self->{setting} = substr( $raw, 0,  2 );
		$self->{value}   = substr( $raw, 2,  7 ) + 0;
		$self->{units}   = substr( $raw, 11, 1 );

		$self->{value} =~ s/ //g;

		#print $self->{value} . " ";
		print time2iso() . "\n";

		print $fh time2iso() . "|" . $self->{value}  . "\n";
		
		
		while( time() < ($self->{interval} + $time) ){sleep 1;};
		print time() . " : $time\n";
		

	}

}

sub graph {

	my $self = shift;
	my $config = shift;
		
	my @data;
	my @ideal;
	my $fh;
	my ($startperiod, $startvalue);
	
	
	$config->{conemax} = Device::Kiln::Orton->hashref()->{$config->{cone}}->{$config->{conerate}};
	#$config->{conemax} = $self->{cones}->{$config->{cone}}->{$config->{conerate}};
	

	#@data = ( [ time2iso(), $self->{value} ] );
	
	open( $fh, "<", $self->{datafile} );
	my $count = 0;
	while(<$fh>) {


		chomp;
		push @data, [split /\|/, $_];
		
		
		if($count == 0 ) {
			$startperiod = $data[0][0];
			$startvalue = $data[0][1];
			$count++;
		}
		
				
	}

	debug("-------------------------");
	
	debug("Warmupramp :" . $config->{warmupramp});
	debug("Warmuptemp :" . $config->{warmuptemp});
	debug("Warmuptime :" . $config->{warmuptime});
	debug("Fireuprate :" . $config->{fireuprate});
	debug("Conerate   :" . $config->{conerate});
	debug("Cone       :" . $config->{cone});
	debug("Cone Max   :" . $config->{conemax});
	
	
	
	my $endperiod = @{@data[@data-1]}[0];
	my $duration = str2time($endperiod) - str2time($startperiod);
	
	my $value=$startvalue;

	debug("Duration " . $duration);
	
	push @ideal, [$startperiod,$value];
	debug( "Data : " . $ideal[@ideal-1][0] . ", " . $ideal[@ideal-1][1]);
	

	
	push @ideal, warmupramp($startvalue,$startperiod,$endperiod,$config);

	
	# Warm Up Time
	my $warmupsecs = $config->{warmuptime} * 60;
	
	if($duration > $config->{used} || $config->{fullgraph} == 0) {
		
		push @ideal, warmuptime($startvalue,$startperiod,$endperiod,$config);
		
		# Fire up to Pre Cone Fire	
		if( $duration > $config->{warmupramptime} + $warmupsecs && $config->{fullgraph} == 0) {
			push @ideal, fireuptime($startvalue,$startperiod,$endperiod,$config);
		
			if($duration > $config->{fireuptime}) {
				push @ideal, conefire($startvalue,$startperiod,$endperiod,$config);
			}
		}
	
	}
	
	
	
	my $graph = SVG::TT::Graph::TimeSeries->new(
		{

			# Optional - defaults shown
			'height' => 600,
			'width'  => 1024,

			'x_label_format' => '%H:%M:%S',
			'area_fill'      => 1,

			'max_time_span' => 0,
			'timescale_divisions' => '15 minutes',

		    'rollover_values'   => 1,
		    'show_data_points'  => 1,
		    'show_data_values'  => 1,

			# Stylesheet defaults
			'style_sheet'   => '/graph.css',    # internal stylesheet
			'random_colors' => 0,
			'compress'      => 0,
			'key'		=> 1,
			
		}
	);

	$graph->add_data(
		{
			'data'  => \@data,
			'title' => 'Temperature',
		}
	);
	
	$graph->add_data(
		{
			'data'  => \@ideal,
			'title' => 'Ideal',
		}
	);
	
	
	debug("-------------------------");

	
	return $graph->burn();
	

}


sub warmupramp {

	my ($startvalue,$startperiod,$endperiod,$config) = @_;
	
	my @ideal;
	my $duration = str2time($endperiod) - str2time($startperiod);
	
	#
	# Warmup Ramp
	#
	debug( "-----> warmupramp ");
	$config->{warmupramptime} = ($config->{warmuptemp}-$startvalue)/($config->{warmupramp})*60*60;
	
	
	if($duration <= $config->{warmupramptime} && $config->{fullgraph} == 0) {
		my $value = ($duration/3600) * $config->{warmupramp} + $startvalue;
		push @ideal, [$endperiod,$value];
		debug( "Data : " . $ideal[@ideal-1][0] . ", " . $ideal[@ideal-1][1]);
		$config->{used} = $duration;
		
	} else {
		push @ideal, [time2iso($config->{warmupramptime}+str2time($startperiod)),$config->{warmuptemp}];
		$config->{used} = $config->{warmupramptime};
		debug( "Data : " . $ideal[@ideal-1][0] . ", " . $ideal[@ideal-1][1]);
		
	}
	return @ideal;
}

sub warmuptime {
	
	my ($startvalue,$startperiod,$endperiod,$config) = @_;
	my $warmupsecs = $config->{warmuptime} * 60;
	my $duration = str2time($endperiod) - str2time($startperiod);
	my @ideal;
		
	if( $duration < $config->{used} + $warmupsecs && $config->{fullgraph} == 0) {
		
		push @ideal, [$endperiod,$config->{warmuptemp}];
		$config->{used} = $duration;
		
	} else {

		push @ideal, [time2iso($config->{warmupramptime}+str2time($startperiod)+ $warmupsecs),$config->{warmuptemp}];
		$config->{used} = $config->{used} + $warmupsecs; 
		
	}	

	debug( "Data : " . $ideal[@ideal-1][0] . ", " . $ideal[@ideal-1][1]);
	return @ideal;
	
}	



sub fireuptime {
	
	my ($startvalue,$startperiod,$endperiod,$config) = @_;
	my $duration = str2time($endperiod) - str2time($startperiod);
	
	my @ideal;
	
	my $endtemp = $config->{conemax} - 100;
	my $risetemp = $endtemp - $config->{warmuptemp};
	
		
	my $endfireuptime = $config->{used} + ($risetemp / $config->{fireuprate}) * 3600;
	
	
	if($duration < $endfireuptime ) {
		my $leftover = $duration - $config->{used};
		my $value = $leftover * ($config->{fireuprate} / 3600) + $config->{warmuptemp};
		push @ideal, [$endperiod, $value];
		$config->{used} = $duration;
		
	} else {
		
		
		push @ideal, [time2iso($endfireuptime + str2time($startperiod)),$endtemp];
		$config->{used} = $endfireuptime;
		$config->{fireuptemp} = $endtemp;
	}
	
	
	debug( "Data : " . $ideal[@ideal-1][0] . ", " . $ideal[@ideal-1][1]);
	return @ideal;	
	
}


sub conefire {
	
	my ($startvalue,$startperiod,$endperiod,$config) = @_;
	my $duration = str2time($endperiod) - str2time($startperiod);
	my @ideal;
	my $fullconetime = 100 / $config->{conerate} * 3600;
	
	if( $duration < $config->{used} + $fullconetime ) {
	 
		push @ideal, [$endperiod, $config->{fireuptemp} + 100 * (($duration-$config->{used})/$fullconetime) ];
		$config->{used} = $duration;
		
	} else {
		
		
		push @ideal, [time2iso($config->{used} + 3600 + str2time($startperiod)), $config->{conemax}];
		$config->{used} += $fullconetime; 
		debug("in");
	}
	
	debug( "Data : " . $ideal[@ideal-1][0] . ", " . $ideal[@ideal-1][1]);
	return @ideal;
	
}

sub debug {
	
	my $msg = shift;
	
	open( my $dfh, ">>", "/tmp/kilnserver.dbg");
	print $dfh (scalar localtime) . " : " . $msg . "\n";
	close($dfh);
	
}

=head1 NAME

Device::Kiln - Graph kiln firing use Data logged from Device::DSE::Q1573 

=head1 SYNOPSIS

  use Device::Kiln;
  my $meter = Device::Kiln->new("/dev/ttyS0");
  


=head1 DESCRIPTION

Sets up a connection to a DSE Q1573 or Metex ME-22 
Digital Multimeter, and allows then plots data to a png file
at regular intervals. 
=head1 USAGE

=head2 new(serialport)

 Usage     : my $meter=Device::Kiln->new("/dev/ttyS0")
 Purpose   : Opens the meter on the specified serial port
 Returns   : object of type Device::Kiln
 Argument  : serial port
 
=head2 rawread();

 Usage     : my $meter->rawread()
 Purpose   : Returns the raw 14 byte string from the meter.
 
=head1 EXAMPLE

use Device::DSE::Q1573;

my $meter = Device::Kiln->new( "/dev/ttyS0" );

while(1) {
	my $data = $meter->read();
	print $data . "\n";
	sleep(1);
}


=head1 AUTHOR

    David Peters
    CPAN ID: DAVIDP
    davidp@electronf.com
    http://www.electronf.com

=head1 COPYRIGHT

This program is free software; you can redistribute
it and/or modify it under the same terms as Perl itself.

The full text of the license can be found in the
LICENSE file included with this module.


=head1 SEE ALSO

perl(1).

=cut

#################### main pod documentation end ###################

1;