The story so-far… In the beginning the universe was created… Then after a while came weather with the inhabitants of a little blue-green planet having a great interest in this weather – presumably because there was so much of it… So people started to try to predict the weather. Seaweed, pine cones and sky colours were used by old wives until the advent of computers. Some still say that seaweed and so on are more accurate though…
But now, we have affordable little computers with affordable little weather instruments, so everyone can now be a weather forecaster! All you need to do is plumb it all together and write the software… That’s what I’m going to start doing now. I have the hardware – currently in-bits on my floor as my workbench is taken up with another project involving beer…
Start with a plan
Here’s the plan. I think I’ll write a single C program that periodically looks at the sensors and writes them into a log-file. Nothing fancy, just a simple human-readable CSV file. Probably one line per minute as that’s going to be good enough to start with. The program will need to keep running for as long as possible so it can keep track of the count of rain sensor tilts and the wind speed. Rainfall is typically measured in millimetres per square meter per unit of time. 1mm in a square meter is 1 litre… Wind speed is typically measured in kilometres per hour, so these two measurements will require some sort of program running over a period of time to perform the measurement.
So-far I’ve written some new code for wiringPi to let it read the sensors directly, and I’ve tested it using the gpio program. I also wrote a bit of code to help me get the wind vane/direction readings. I’m thinking I’ll use this code in my main program and create a little function which wraps the low-level sensor readings into something more readable for the main program. I have a view that the main program will be nothing more than a loop – running once a minute – which calls each sensors sampling code then writes those values into a file (top-down thinking), but when it comes to actual coding, I like to write the low-level codes first and test them as I go.
I also like to write the easy bits first – sometimes they’re really the hard bits in disguise, but there are 2 functions that will require interrupt handlers – I’ll class those are hard and leave them until last. At least for now.
Since I already have some code for the wind vane, I’ll start with that.
Starting a new project
What I typically do would be to create a new directory and edit files in there. So in the /home/pi directory,
$ cd $ mkdir weather $ cd weather $ mv ~/wiringPi/wiringPi/vane.c . $ mv vane.c weather.c
and off I go. I’ve renamed the vane.c file to weather.c which will be the main file. Typically I’ll start with one file, then split the functions into separate files so they can be compiled separately.
Note: Just in-case you’ve missed this, I’m doing all the work directly on the weather station Raspberry Pi. I’m logged in via SSH from my (Linux) desktop PC. I am not using an IDE (I use vim), and I am not cross-compiling on another system. This is what the Raspberry Pi was designed for – to allow you to develop programs directly on the Pi without the need for anything else. I could be doing this on the Pi if it had a screen and keyboard – but it doesn’t and I have a nice keyboard on my desktop, so remotely via ssh works just fine. FWIW: the Pi is much faster with more memory than the first Unix computer I used X windows on – a Sun 3 with 4MB of RAM. No local storage, it was all on a network file server (NFS) via 10Mb Ethernet … The first Unix computer I used only has 128KB of RAM and a 3MB hard drive… (and ran at 4Mhz) How times have changed.
In the end, I threw away most of the vane.c code – I was going to keep its low-pass filter but I don’t think I need it – also to use it, I’d need to keep sampling the wind direction sensor more or less continuously. Exercise for another day. Things I tried when writing the code – use a fuzzy match on the sensor reading – e.g. +/- 5 to compare with the readings I got with the vane.c program earlier, however that didn’t work as some of the samples were too close. In the end, I went for a list of the values I got with the vane.c program and simply compared the sampled value to each in-turn to find out which was the closest. This seems to work OK and I’ve tested it on my desk and I can reliably get 8 different compass readings. A programming rule I applied here was: “Don’t be afraid to throw away code and start again.”
If you’re doing this yourself, then you’ll need to run the original vane.c program to get the values out of your wind vane as I’m sure no 2 are going to be identical…
Things that have popped into my head while doing this in a sort of random order – need a common header file for the pin numbers, maybe need a common naming scheme, does each sensor need any initialisation code?
Here is the source of this first little module in its entirety:
/* * weather.c: * Plan C for the Raspberry Pi weather station. * * This is an example/demonstration of building a project (in this case * the Raspberry Pi weather station) in C. * * Copyright (c) 2016 Gordon Henderson. ********************************************************************************* */ #include <stdio.h> #include <stdlib,h> #include <wiringPi.h> #include <mcp3422.h> #define DEPTH 8 #define DIR_N 0 #define DIR_NE 1 #define DIR_E 2 #define DIR_SE 3 #define DIR_S 4 #define DIR_SW 5 #define DIR_W 6 #define DIR_NW 7 #define ADC_PIN_BASE 100 #define WIND_PIN 0 // Some global data char *directions [8] = { "North", "North east", "East", "South east", "South", "South west", "West", "North west" } ; #define NUM_READINGS 14 static int readings [NUM_READINGS] = { 814, 204, 251, 29, 33, 23, 71, 46, 124, 100, 455, 1765, 1279, 590, } ; static int direction [NUM_READINGS] = { 0, 1, 1, 1, 2, 3, 3, 3, 4, 5, 5, 6, 7, 7, } ; /* * getWindDirection: * Return the current wind direction - or at least try. ********************************************************************************* */ static int getWindDirection (void) { int i ; int sample ; int diff, bestDiff, candidate ; candidate = 0 ; bestDiff = 999999 ; // a highly unlikely value sample = analogRead (ADC_PIN_BASE + WIND_PIN) ; for (i = 0 ; i < NUM_READINGS ; ++i) { diff = abs (readings [i] - sample) ; if (diff < bestDiff) { bestDiff = diff ; candidate = i ; } } return direction [candidate] ; } /* * main: ********************************************************************************* */ int main (void) { wiringPiSetup () ; mcp3422Setup (ADC_PIN_BASE, 0x69, 0,0) ; for (;;) printf ("%s\n", directions [getWindDirection ()]) ; }
It’s essentially the wind vane read function with a tiny little wrapper that will let me test it.
It was compiled with:
$ gcc -Wall -Wextra -o weather weather.c -lwiringPi
I strongly encourage everyone to use -Wall and -Wextra in their code. It can pick up all sorts of simple mistakes and give you very verbose warnings. I feel there is little excuse these days to have programs that don’t compile cleanly without them.
The program compiled and ran (and was re-edited, changed, re-compiled, re-run) until I was happy with it.
Next, I’ll look at the air quality sensor….