<?php
$top = 110;
$bottom = 45;
$old_hour_min = "";
date_default_timezone_set( "America/Los_Angeles" );
class Temperature_Graph
{
public $image;
public $black;
public $white;
public $red;
public $blue;
public $green;
public $brightgreen;
public $violet;
public $gray;
public $image_width = 900;
public $image_height = 400;
public $low_pixel = 400 - 50;
public $high_pixel = 70;
public $hi_temp_degrees_F = 110;
public $lo_temp_degrees_F = 45;
public $range_in_degrees_F;
public $pixels_per_degree;
public $zero;
public $font;
public function __construct()
{
global $top, $bottom, $bottom_temp, $begin, $end, $latest, $latest_mean, $target;
$this->font = "..\\php\\extras\\fonts\\ttf\\Vera.ttf";
$this->hi_temp_degrees_F = intval( $top ) + 1;
$this->lo_temp_degrees_F = intval( $bottom ) - 0.5;
$this->range_in_degrees_F = $this->hi_temp_degrees_F - $this->lo_temp_degrees_F;
$this->pixels_per_degree = ($this->low_pixel - $this->high_pixel) / $this->range_in_degrees_F;
$this->zero = $this->hi_temp_degrees_F * $this->pixels_per_degree + $this->high_pixel;
$this->image = imagecreatetruecolor( $this->image_width, $this->image_height );
$this->black = imagecolorallocate( $this->image, 0, 0, 0 );
$this->gray = imagecolorallocate( $this->image, 200, 200, 200 );
$this->darkgray = imagecolorallocate( $this->image, 80, 80, 80 );
$this->white = imagecolorallocate( $this->image, 255, 255, 255 );
$this->red = imagecolorallocate( $this->image, 255, 50, 50 );
$this->blue = imagecolorallocate( $this->image, 50, 50, 255 );
$this->green = imagecolorallocate( $this->image, 0, 150, 0 );
$this->brightgreen = imagecolorallocate( $this->image, 0, 255, 0 );
$this->violet = imagecolorallocate( $this->image, 255, 50, 255 );
imagefill( $this->image, 0, 0, $this->white );
$target_y = $this->zero - $target * $this->pixels_per_degree;
imageline( $this->image, 10, $target_y, $this->image_width - 30, $target_y, $this->violet );
$high_tick = $this->zero - $this->hi_temp_degrees_F * $this->pixels_per_degree;
$tick_degrees = $this->hi_temp_degrees_F;
for( $tick_y = $high_tick; $tick_y < $this->low_pixel; $tick_y += .1 * $this->pixels_per_degree )
{
imageline( $this->image, 10, $tick_y, 20, $tick_y, $this->black );
if( ($tick_degrees * 100) % 50 == 0 )
{
imageline( $this->image, 10, $tick_y, 40, $tick_y, $this->black );
imagettftext( $this->image, 10, 0, 15, $tick_y+12, $this->black, $this->font,
number_format($tick_degrees,1) . " \xC2\xB0F" );
}
$tick_degrees -= .1;
}
imagerectangle( $this->image, 10, 10, $this->image_width-1, $this->image_height-1, $this->black );
imagettftext( $this->image, 10, 0, 180, $this->image_height-32, $this->blue, $this->font,
"Min " . number_format($bottom_temp,4) . " \xC2\xB0F" );
imagettftext( $this->image, 10, 0, 425, $this->image_height-32, $this->darkgray, $this->font,
"Mean " . number_format($latest_mean,4) . " \xC2\xB0F" );
imagettftext( $this->image, 10, 0, 685, $this->image_height-32, $this->red, $this->font,
"Max " . number_format($top,4) . " \xC2\xB0F" );
imagettftext( $this->image, 14, 0, 420, 30, $this->black, $this->font, "Temperature" );
imagettftext( $this->image, 10, 0, 70, 50, $this->black, $this->font, "Begin " . $begin );
imagettftext( $this->image, 10, 0, 425, 50, $this->green, $this->font,
"Latest " . number_format($latest,4) . " \xC2\xB0F" );
imagettftext( $this->image, 10, 0, 425, 70, $this->violet, $this->font,
"Target " . number_format($target,4) . " \xC2\xB0F" );
imagettftext( $this->image, 10, 0, 685, 50, $this->black, $this->font, "End " . $end );
}
public function plot_sample( $column, $time, $temperature, $mean, $std_dev, $heater, $integral, $target )
{
global $old_hour_min;
$temperature_y = $this->zero - $temperature * $this->pixels_per_degree;
$mean_y = $this->zero - $mean * $this->pixels_per_degree;
$x = $column * 3 + 80;
//
// Draw the dot for the mean
//
imagefilledellipse( $this->image, $x, $mean_y, 6, 6, $this->gray );
//
// Draw the dot for the temperature
//
imagefilledellipse( $this->image, $x, $temperature_y, 5, 5, $this->green );
if( $column % 20 == 0 )
{
$hour_min = substr( $time, 11, 5 );
$hour_min_sec = substr( $time, 11, 8 );
imageline( $this->image, $x+2, $this->image_height, $x+2, $this->image_height-15, $this->black );
if( $hour_min != $old_hour_min )
imagettftext( $this->image, 8, 0, $x+4, $this->image_height-2, $this->black, $this->font, " " . $hour_min );
$old_hour_min = $hour_min;
}
}
public function __destruct()
{
header( 'Content-Type: image/png' );
imagepng( $this->image );
imagedestroy( $this->image );
}
}
class Read_Database_Temperatures
{
public $mysqli;
public $selected;
public $select;
public function __construct()
{
$db_name = "water_bath";
//
// This program can be called with optional arguments:
// --database=foo the name of the database to use
//
$options = getopt( "", [ "database::" ] );
if( $options )
{
foreach( array_keys( $options ) as $key )
{
if( $key == "database" )
{
$db_name = $options[$key];
}
}
}
$this->mysqli = new mysqli( 'localhost', 'root', '', $db_name )
or die( 'Could not connect: ' . mysqli_error() );
$this->mysqli->select_db( $db_name )
or die( "Could not select database $db_name" );
$this->mysqli->query( "SET time_zone='-8:00';" )
or die( 'Select failed: ' . $this->mysqli->error );
//
// Last 24 hours
//
// $this->select =
// "SELECT id, temperature, mean, std_dev, heater, reg_date FROM temps"
// . " WHERE reg_date >= (CURTIME() - INTERVAL 1 DAY)";
//
// Yesterday
//
// $this->select =
// "SELECT id, temperature, mean, std_dev, heater, reg_date FROM temps"
// . " WHERE DATE(reg_date) = (CURDATE() - 1)";
//
// Last 5 minutes
//
$this->select =
"SELECT id, temperature, mean, std_dev, heater, integral, target, reg_date FROM temps"
. " WHERE reg_date > date_sub( now(), interval 5 minute )";
$this->selected = $this->mysqli->query( $this->select )
or die( 'Select failed: ' . $this->mysqli->error );
}
public function output()
{
if( $this->selected->num_rows > 0 )
{
global $top, $bottom, $bottom_temp, $begin, $end, $latest, $latest_mean, $target;
$columns = array();
$top = -99999;
$bottom = 100000;
$bottom_temp = 100000;
$num = 0;
$row = 0;
for( $x = 0; ; $x++ )
{
$row = $this->selected->fetch_assoc();
if( ! $row )
break;
$temperature = $row["temperature"];
$latest = $temperature;
$mean = $row["mean"];
$latest_mean = $mean;
$std_dev = $row["std_dev"];
$heater = $row["heater"];
$integral = $row["integral"];
$target = $row["target"];
if( $temperature < $bottom_temp )
$bottom_temp = $temperature;
if( $temperature < $bottom )
$bottom = $temperature;
if( $mean < $bottom )
$bottom = $mean;
if( $temperature > $top )
$top = $temperature;
if( $mean > $top )
$top = $mean;
if( $x == 0 )
$begin = $row["reg_date"];
$end = $row["reg_date"];
$columns[$num] = array( $num, $end, $temperature, $mean, $std_dev, $heater, $integral, $target );
$num++;
if( ! $row )
break;
}
$graph = new Temperature_Graph();
for( $x = 0; $x < $num; $x++ )
{
$c = $columns[ $x ];
$graph->plot_sample( $c[0], $c[1], $c[2], $c[3], $c[4], $c[5], $c[6], $c[7] );
}
}
}
}
$db = new Read_Database_Temperatures();
$db->output();
?>