Category Archives: Web

Perl to JavaScript Data via JSON

I have a Perl script monitoring serial ports for sensor data, that data is then to be accessed in a web page via AJAX so needs to be readable by JavaScript. I’m using JSON as the data format to transport the data.

Writing JSON in Perl

Install the JSON module with CPAN if not already installed. Then simply construct a hash table, or a hash of hashes to create a name hierarchy. Once the hash is created, use the to_json function to format the hash as a JSON string and write that string to a text file.

my $json->{"temp"} = {"f" => ($ad1 * 100.0 / 0x3ff) * 9 / 5 + 32, "c" => ($ad1 * 100.0 / 0x3ff)};
$json->{"water"} = $dio4;

$json_text = to_json $json;

open FILE, ">xbee.json";
print FILE $json_text;
close FILE;

Reading JSON in JavaScript

Now that JSON file can be accessed from a web browser to display the results. Using jQuery there is a .getJSON function that will read the file and unpack the JSON format into a JavaScript variable. Once in the variable, as data is here, the hashes written in Perl are accessed as child objects of the variable. Eg. the hash water is simple accessed as data.water in Javascript.


$.getJSON('xbee.php', function(data) {
 $('#basement_temp').html(data.temp.f.toFixed(1));
 if (data.water != '0') {
$('#basement_water').removeClass('sensor_alert').addClass('sensor_ok');
 } else {
$('#basement_water').removeClass('sensor_ok').addClass('sensor_alert');
 }
 });

Variable range scrollback for archive images

For a given image of class=’camview’  this jQuery javascript will scroll back a variable amount depending on the mouse location over the image.

The mouse over right edge of the image represents the most recent image from the archive. The bottom-left corner represents 24 hours ago. But to have finer granularity at reviewing more recent images, scrolling the mouse over the top of the image will scroll back one time-increment every 10 pixels. Moving the mouse from right to left over the bottom of the image will scroll back over a full 24 hours (1440 one-minute images) skipping frames as needed to fit the mouse resolution. Mouse heights between the top and bottom edges will have a linearly scaled proportion of archive history.

$('.camview').mousemove(function(event) {
 var x = event.pageX - $(this).offset().left;
 var y = event.pageY - $(this).offset().top;
 var mindx = 0.1;
 var maxdx = 1440.0 / $(this).width();
 var dy = 1.0 - y / $(this).height();
 var dx = dy * mindx + (1.0-dy) * maxdx;
 var arc = ($(this).width() - x) * dx;
 $(this).find('img').attr('src', 'camjpg.php?cam=' + $(this).attr('id') + '&arc=' + arc.toFixed(0));
});

Archiving thumnails of FTP camera images

This php script will iterate over an array $cams that has an element file that is the filename.

It uses the PHP Imagick package to resize the image and overlay a timestamp. The file timestamp is used so the time of the last ftp image is used, which may differ from the current time if the ftp has stalled. The image is then copied to an Hour/Minute specific folder for a 24 hour rolling archive.

$H = date('H');
$i = date('i');
$arcpath = $ftppath . $H . '/';
mkdir($arcpath);
$arcpath = $ftppath . $H . '/' . $i . '/';

foreach ($cams as $cam)
{
  $pathfile = $ftppath . $cam['file'];
  if (file_exists($pathfile)) {
    $thumbname = $cam['file'] . '_320x240';

    $thumb = new Imagick($pathfile);
    $thumb->scaleImage(320,240);

    $draw = new ImagickDraw();
    $draw->setFontSize(12);
    $draw->setFillColor(new ImagickPixel("#ffffff"));

    $draw->setTextAlignment(LEFT);
    $draw->annotation(5, 12,  date ("F d Y H:i:s", filemtime($pathfile)));
    $thumb->drawImage($draw);

    $thumb->setImageCompression(imagick::COMPRESSION_JPEG);
    $thumb->setImageCompressionQuality(80);
    $thumb->stripImage();
    $thumb->writeImage($ftppath . $thumbname);
    $thumb->clear();
    $thumb->destroy();
    copy($ftppath . $thumbname, $arcpath . $thumbname);
  }
}

Http proxy for accessing local area network images

To access multiple cameras on a local area network from a single web page, you need to proxy the requests from your web server. Since many netcams require BasicAuth to access images,

A PHP script to handle the proxy request can be found here: http://www.troywolf.com/articles/php/class_http/
To process a set of cameras, store the camera access data in an array such as this

$cams = array(
 "c30a" => array(
 "name" => "c30a",
 "type" => "http",
 "http" => "http://192.168.3.71/SnapshotJPEG?Resolution=640x480&Quality=Standard&Count=1",
 "http_user" => "<user>",
 "http_pass" => "<password>",
 "title" => "Backyard",
 "live" => "//192.168.3.71/CgiStart?page=Single&Language=0"
 ),
 "c20a" => array (
 "name" => "c20a",
 "type" => "http",
 "http" => "http://192.168.3.73/SnapshotJPEG?Resolution=640x480&Quality=Standard&Count=1",
 "http_user" => "<user>",
 "http_pass" => "<password>",
 "title" => "Garage",
 "live" => "//192.168.3.73/CgiStart?page=Single&Language=0"
 ),
}
?>

Include the above config.php in the php script that will handle the proxy request. It will look up the local area network destination from the ‘http’ element of the array, and pass the request along the camera, then copy the image returned from the camera to the caller.

url = $cam['http'];
 $h->postvars = $_POST;
 if (!$h->fetch($h->url, 0, "", $http_user, $http_pass)) {
   header("HTTP/1.0 501 Script Error");
   echo "proxy.php had an error attempting to query the url";
   exit();
 }

 $http_user = "";
 $http_pass = "";
 if (isset($cam['http_user'])) $http_user = $cam['http_user'];
 if (isset($cam['http_pass'])) $http_pass = $cam['http_pass'];

 $h->url = $cam['http'];
 $h->postvars = $_POST;
 if (!$h->fetch($h->url, 0, "", $http_user, $http_pass)) {
 header("HTTP/1.0 501 Script Error");
 echo "proxy.php had an error attempting to query the url";
 exit();
 }

 // Forward the headers to the client.
 $ary_headers = explode("\n", $h->header);
 foreach($ary_headers as $hdr) { header($hdr); }

 // Send the response body to the client.
 echo $h->body;
?>

To use this proxy from a web page, the javascript with jQuery would request an image from the same page as the main web site.

 $('#c30a img').attr('src', 'proxy.php?cam=c30a');