<?xml version="1.0" encoding="Windows-1252"?>
<node id="728159" title="Weather reports on the HP4350's front panel" created="2008-12-04 21:12:44" updated="2008-12-04 21:12:44">
<type id="1042">
CUFP</type>
<author id="20250">
pemungkah</author>
<data>
<field name="doctext">
This is an adaptation of yaakov's &lt;a href="http://kovaya.com/miscellany/2007/10/get-weather-on-your-hp-4200.html"&gt;original&lt;/a&gt; program to allow you to simply specify a location textually and have it look up the ICAO code to use to get the weather report.
&lt;p&gt;
The weather report displays as 4 20-character lines on the printer's front panel.  Time to make that display do something useful instead of just sitting there saying "READY".
&lt;p&gt;
Lexmark printers seem to understand the PJL language used to set the display; try yours!

&lt;code&gt;
#!/usr/bin/perl -w

  # $Id: 4200wx.pl 2 2008-07-10 00:05:58Z yaakov $

  # Current Weather Condition on an HP 4200 Printer 
  # 
  # This program gets METAR weather conditions from the NOAA webiste and uses
  # Geo::METAR to parse the result.  It then hard formats the result so it
  # looks reasonably good on the 4200's display.
  #
  # The program need to know the four-letter ICAO airport code for your area,
  # as well as the IP address of the target printer.  I run this program as a
  # cron job at 10 minute intervals.  You can change the "WEATHER CONDITIONS"
  # heading to reflect your cities name.  You will have to pad it properly
  # to center it.
  #
  # THIS PROGRAM IS PROVIDED WITH NO WARRANTY OF ANY KIND EXPRESSED OR IMPLIED
  # THE AUTHOR CANNOT BE RESPONSIBLE FOR THE EFFECTS OF THIS PROGRAM
  # IF YOU ARE UNCERTAIN ABOUT THE ADVISABILITY OF USING IT, DO NOT!
  #
  # Yaakov (http://kovaya.com/)
  #
  # Updated 12/04/2008 by Joe McMahon
  #  - options parsing with Getopt::Long
  #  - lookup of ICAO code from location name
  #  - Fetches METAR data via JSON (Geo::METAR no longer works)

use strict;

use LWP::Simple;
use IO::Socket;
use Getopt::Long;
use WWW::Mechanize;
use JSON;

my($opt_n, $opt_v, $ip, $station_code, $location);
GetOptions(
	"n"     =&gt; \$opt_n,
	"v"     =&gt; \$opt_v,
	"ip=s" =&gt; \$ip,
	"icao=s" =&gt;\$station_code,
	"location=s" =&gt; \$location,
);

$ip = '172.21.42.200' unless $ip;
my $mech = new WWW::Mechanize;
$|++ if $opt_v;

# Figure out ICAO code if not specified.
if ($station_code and $location) {
	warn "Both station code and location specified, choosing code\n";
}
elsif (!$station_code and !$location) {
	die "Must specify either -icao or -location to continue\n";
}
elsif ($location) {
	# Convert location into a station code.
	my ($city, $state, $error) = split /,\s*/, $location;
	$city =~ s/\s+/+/g;
	$state=~ s/\s+/+/g;
	print "Obtaining ICAO code ... " if $opt_v;
	$mech-&gt;get("http://www.jfast.org/Tools/Port2PortAirDist/GeoLookup.asp?Name=$city&amp;Country=$state&amp;Geo=&amp;Icao=&amp;Submit1=Look+up");
	die "Can't look up ICAO code for '$location': @{[$mech-&gt;status]}\n" unless $mech-&gt;success;
	my ($table) = ($mech-&gt;content =~ /(&lt;TR&gt;&lt;TD&gt;.*)$/m);
	my @lines = ($table =~ m{&lt;TR&gt;(.*?)&lt;/TR&gt;}g);
	my @content;
	foreach my $line (@lines) {
		@content = ($line =~ m{&lt;TD&gt;(.*?)&lt;/TD&gt;}g);
		last if $content[3] ne "    ";
	}
	die "No ICAO station code found for '$location'\n" if $content[3] eq '    ';
	$station_code = $content[3];
}

# At this point we have an ICAO code.
print "Fetching weather info ... " if $opt_v;
$mech-&gt;get("http://ws.geonames.org/weatherIcaoJSON?ICAO=$station_code");
die "Can't get weather from geonames.org: @{[$mech-&gt;status]}" unless $mech-&gt;success;
my $weather = from_json($mech-&gt;content);

my $temp_c = $weather-&gt;{weatherObservation}-&gt;{temperature};
my $temp_f = 9/5*$temp_c + 32;
my $conditions = $weather-&gt;{weatherObservation}-&gt;{weatherCondition};
$conditions = "clear" if $conditions eq 'n/a';
my $wind_speed = $weather-&gt;{weatherObservation}-&gt;{windSpeed};

# Looks like 4 lines on the printer, but it's really just one. Embedding 
# carriage returns in an attempt to format the data will not work!
my $wx = qq(@{[hp_pad("Weather")]}@{[hp_pad("${temp_f}F/${temp_c}C")]}@{[hp_pad(ucfirst($conditions))]}@{[hp_pad("Wind $wind_speed mph")]});

setdisplay($wx, $ip);

sub hp_pad {
	my ($string) = @_;
	return substr($string,0,20) if length($string) &gt;= 20;
	my $end_pad_length = int((20 - length($string) ) / 2);
	$string = ' ' x $end_pad_length . $string . ' ' x $end_pad_length;
	$string = "$string " if length $string == 19;
	return $string;
}

sub setdisplay {

  my ($rdymsg, $peeraddr) = @_;
  my $socket;

  if (! $opt_n) {
      $socket = IO::Socket::INET-&gt;new(
          PeerAddr	=&gt; $peeraddr,
          PeerPort	=&gt; "9100",
          Proto     =&gt; "tcp",
          Type	=&gt; SOCK_STREAM
      ) or die "Could not create socket: $!";
  }

my $data = &lt;&lt;EOJ
\e%-12345X\@PJL JOB
\@PJL RDYMSG DISPLAY="$rdymsg"
\@PJL EOJ
\e%-12345X
EOJ
;

  if (! $opt_n) {
	  print "Setting up printer ... ";
      print $socket $data;
  }
  else {
      print $data;
  }
  print "\n";
}
&lt;/code&gt;</field>
</data>
</node>
