Hot off the press - NOAA15 pass @ 16:00 UTC today, our first test image off the WX Sat system :)Keep an eye on Emily's weather blog for lots of further updates.
Hot off the press - NOAA15 pass @ 16:00 UTC today, our first test image off the WX Sat system :)
#!/usr/bin/php
<?
/* gMFSK getwx::
A simple script to grab your local weather from the web to insert into F-key
macros in the same way as $mycall $yourcall etc.
This is a slightly more finished version of the test scripts recently published
on my blog. This version checks if it has a local copy with a recent datestamp
of the RSS data from yahoo - then builds a complete weather report from the cached
data to save hitting yahoo every time the script is called.
Yes it could be done more easilly using cron, but feedback from some users
has suggested that a self contained "easy" script is wanted
Yes I could have used CURL - but a basic php_cli install doesnt always have
CURL compiled in.
to get the right url for your local yahoo weather vist weather.yahoo.com
type in your location and hit return. When you get your local weather click
on the orange RSS button and make a note of the URL. its the p=XXXXXXXXX bit that
is important. Changing the u=f to u=c gets you metric results
You need php_cli installed for this script to work eg: sudo apt-get install php5_cli
save this script to your gMFSK directory, remember to chmod it +x to be executeable
in one of the gMFSK function key windows add the command:
$(/home/g7nbp/gMFSK/getwx)
Remember to alter your path to point at wherever the file is saved.
Please feel free to experiment :)
Written by g7nbp 28-12-2009
*/
// OK first a few variables
$pageurl = "http://weather.yahooapis.com/forecastrss?p=UKXX1012&u=c"; // url of yahoo weather RSS feed
$file = "wx.xml"; // the file to save the xml to
$update_time = 1800; // period between getting updates down in seconds
if (file_exists($file)){
// the wx.xml file has been found :)
$fileage = time() - filemtime($file); // workout how old the local copy is
if ($fileage >= $update_time){
// local copy older than update_time - call the get_xml routine to read from website
get_xml();
}
}else{
// no the wx.xml file has not been found (first run??) so call the get_xml routine
get_xml();
}
// OK assuming nothing broke we can now work with the local copy :)
$rss = simplexml_load_file($file); // open local copy
// Build the variables from the assorted yweather:something namespaces
$condx = $rss->xpath('//yweather:condition/@text');
$condx = ltrim(rtrim($condx[0])) ." ";
$pressure = $rss->xpath('//yweather:atmosphere/@pressure');
$pressure_units = $rss->xpath('//yweather:units/@pressure');
$pressure = ltrim(rtrim($pressure[0])) . $pressure_units[0];
$temp = $rss->xpath('//yweather:condition/@temp');
$temp_units = $rss->xpath('//yweather:units/@temperature');
$temp = ltrim(rtrim($temp[0])) ."°". $temp_units[0];
$windd = $rss->xpath('//yweather:wind/@direction');
$winds = $rss->xpath('//yweather:wind/@speed');
$wind_units = $rss->xpath('//yweather:units/@speed');
$wind = ltrim(rtrim($windd[0])) . "° ". ltrim(rtrim($winds[0])) . $wind_units[0];
// finally build our output string
echo "local WX: Temp=". $temp . " Pressure=" . $pressure . " Wind=" . $wind . " Condx=" . $condx . "\n" ;
// --- thats all folks! ---
// functions live here
function get_xml(){
// a really simple file_get file_put routine to grab a copy of the weather XML
// and save it local to save hitting yahoo every time time we run the srcipt
global $file, $pageurl;
$xml =file_get_contents($pageurl);
file_put_contents($file, $xml);
}
?>
<yweather:wind chill="1" direction="260" speed="14.48" />
temp::
#!/usr/bin/php
<?
$rss = simplexml_load_file('http://weather.yahooapis.com/forecastrss?p=UKXX1012&u=c');
$temps = $rss->xpath('//yweather:condition/@temp');
$units = $rss->xpath('//yweather:units/@temperature');
$temp = ltrim(rtrim($temps[0])) ."°". $units[0];
echo "T: " .$temp;
?>
Pressure::
#!/usr/bin/php
<?
$rss = simplexml_load_file('http://weather.yahooapis.com/forecastrss?p=UKXX1012&u=c');
$pressures = $rss->xpath('//yweather:atmosphere/@pressure');
$units = $rss->xpath('//yweather:units/@pressure');
$pressure = ltrim(rtrim($pressures[0])) . $units[0];
echo "P: ". $pressure;
?>
Wind::
#!/usr/bin/php
<?
$rss = simplexml_load_file('http://weather.yahooapis.com/forecastrss?p=UKXX1012&u=c');
$windd = $rss->xpath('//yweather:wind/@direction');
$winds = $rss->xpath('//yweather:wind/@speed');
$units = $rss->xpath('//yweather:units/@speed');
$wind = ltrim(rtrim($windd[0])) . "° ". ltrim(rtrim($winds[0])) . $units[0];
echo "W: " .$wind;
?>
condx::
#!/usr/bin/php
<?
$rss = simplexml_load_file('http://weather.yahooapis.com/forecastrss?p=UKXX1012&u=c');
$condx = $rss->xpath('//yweather:condition/@text');
$condx = ltrim(rtrim($condx[0])) ." ";
echo $condx;
?>
The DDS itself has a frequency range of 0-60Mhz, in 1Hz steps. With such a wide range what would be really handy is the ability to scroll thru a wide range of frequencies rapidly, slow down, then fine tune over a few hertz. A combination of Keypads, up down buttons and rotary encoders are the usual method of changing frequency, combined with an LCD frequency readout. All work fine, but are really rather clunky methods of navigating up and down a wide range of frequencies, but with good fine tuning accuracy.
There is however a device that make this sort of thing really quite intuitive - the Jog/Shuttle Dial
The jog/shuttle dial has an outer ring which allows you to rapidly select +/- movement (usually of position within multi-media) with center stop. The greater the deflection, the higher the rate of change. The inner wheel with finger hole spinner allows fine tuning up down depending on direction of rotation like a conventional rotary encoder.This type of control features occasionally on high-end radio transceivers for VFO control, but is usually well beyond the means of the typical home constructor. Partly because of cost, and partly because of the complexity of interfacing. HOWEVER!! these days that doesn’t have to be the case :)
The following few blog entries describe my tests interfacing a jog/shuttle control to an arduino for use with the DDS board. Hopefully others will find the tests useful and will incorporate this useful control type into other radio and electronic projects.
So, first things first - where do you get a jog/shuttle control?
Well. You can of course buy one, ALPS make them. Several suppliers stock them. The usual problems of minimum order quantity and cost are however factors to consider here - they are expensive items. There is however a fairly reliable source of jog/shuttle dials available second hand - as long as you dont mind a bit of disassembly to get at them. I refer of course to their use in video recorders. Quite a range of "pro-sumer" grade VCRs sold over the last 10 years will have featured a jog-shuttle dial. Ebay, junk stores and swapmeets etc are a good source.Another place you may find a jog shuttle dial is on the remote control that went with the VCR - which is where I got the one Im experimenting with. (There are a couple of sellers on Ebay who sell just remotes - and the one I bought cost me about £12).
The case on this one had the usual single screw and snap fit casing lugs, so it was on the bench and plugged into the logic analyser within a few minutes of it arriving in the post.
Bench testing the control
I connected up the remote to a 3v supply via the battery terminals and tacked on some breakout leads to the switch connections to connect up my logic analyser.
The pinout was thoughtfully printed on the reverse of the PCB. I expected to find a simple two-pin-plus- ground AB quadrature system for the jog dial (as denoted by J1/J2, with 0v via C2) and 4 other pins plus 0v common C1 giving a grey coded binary output from the shuttle ring, and this seemed to be confirmed by the pins.
Firstly I decided to check that the jog dial was as expected - plain old 2bit greycoded quadrature.
Yup, fairly conclusive. I did however note that sometimes the jog dial would produce two transitions per click on the dial, and sometimes only one.
Slowly rotating the shuttle dial gave the expected single bit change at about 10 degree steps. Building a truth table took just a few moments. 
I carefully removed the control and placed it on a scrap of veroboard and added some 90degree header pins to make plugging it into a breadboard a bit more easy.Here we see the control in place in the breadboad connected to arduino and laptop.
-----------------------------------------
/*
Jog test - 1
(a minimal quadrature type decoder for jog dials)
*/
int clock = 6; // Define encoder pin A
int data = 7; // Define encoder pin B
int count = 0; // pre-init the count to zero
int c = LOW; // pre-init the state of pin A low
int cLast = LOW; // and make its last val the same - ie no change
int d = LOW; // and make the data val low as well
void setup() {
pinMode (clock,INPUT); // setup the pins as inputs
pinMode (data,INPUT);
Serial.begin (9600); // and give some serial debugging
}
void loop() {
c = digitalRead(clock); // read pin A as clock
d = digitalRead(data); // read pin B as data
if (c != cLast) { // clock pin has changed value... now we can do stuff
d = c^d; // work out direction using an XOR
if ( d ) {
count--; // non-zero is Anti-clockwise
}else{
count++; // zero is therefore anti-clockwise
}
Serial.print ("Jog:: count:");
Serial.println(count);
cLast = c; // store current clock state for next pass
}
}
-----------------------------------------
-----------------------------------------
/*
* Shuttle test prog -1
*/
// define grey code positions stored in 0-15 array in global scope
int gray2pos[] = { -60,+50,-70,+60,-50,+40,-80,+70,-30,+20,-20,+10,-40,+30,-10,0 };
void setup()
{
Serial.begin(9600); // set up Serial library at 9600 bps
pinMode(8, INPUT); // sets the digital pins as input
pinMode(9, INPUT);
pinMode(10, INPUT);
pinMode(11, INPUT);
}
void loop()
{
Serial.print("Shuttle :: Bin:");
Serial.print(PINB,BIN); // scan PORTB (pins 8-13) and print as a binary
Serial.print(" Dec:");
Serial.print(PINB,DEC); // print the same data as a decimal
Serial.print(" Pos:");
Serial.print(gray2pos[PINB]);
Serial.println(176, BYTE); // extended ascii val to get the degrees symbol
delay(1000);
}
-----------------------------------------
and we end up with
-----------------------------------------
/*
* Full Jog/Shuttle test prog
*/
// global scope vars
int clock = 6; // Define jog pin A
int data = 7; // Define jog pin B
int c = LOW; // pre-init the state of pin A low
int cLast = LOW; // and make its last val the same - ie no change
int d = LOW; // and make the data val low as well
int count = 0; // pre-init the count to zero
// define counter shuttle steps array
int gray2pos[] = { -64,32,-128,+64,-32,16,-256,+128,-8,4,-4,2,-16,8,-2,0 };
void setup()
{
Serial.begin(9600); // set up Serial library at 9600 bps
pinMode (clock,INPUT); // setup the jog pins as inputs
pinMode (data,INPUT);
pinMode (8, INPUT); // sets the shuttle pins as input
pinMode (9, INPUT);
pinMode (10, INPUT);
pinMode (11, INPUT);
}
void loop()
{
checkjog(); // move each of the checks out to a function
checkshuttle();
Serial.print("Jog/Shuttle:");
Serial.println(count);
}
int checkjog(){
c = digitalRead(clock); // read pin A as clock
d = digitalRead(data); // read pin B as data
if (c != cLast) { // clock pin has changed value... now we can do stuff
d = c^d; // work out direction using an XOR
if ( d ) {
count--; // non-zero is Anti-clockwise
}else{
count++; // zero is therefore anti-clockwise
}
cLast = c; // store current clock state for next pass
}
}
int checkshuttle(){
count += gray2pos[PINB];
}
-----------------------------------------