As normally all my stories begin, I had a bunch of stuff lying around and (...)
At home we wanted to have for some time now more information about the weather, no big deal, normally we just browsed our mobile and wunderground to get feedback about our area, in fact we found this particular PWS (personal weather station) being really close to home.
But then again depending on the day the information seemed a bit off, and wunderground's free developer plan limits the number of requests to 500 per day, and we wanted to be able to exploit the data for other purposes, like to make an app to suggest you to put more clothes on in case of a chilly morning waiting for the bus, make our own weather forecasts, share this information with others to increase the weather information resolution in our neighbourhood, and other excuses like this to get my wife's blessing to work on a weekend.
Truth is I had sensors and a weather meter lying around, and I wanted to test what I could do in a weekend with enough time to work on this.
The main objective is to register my DIY Weather Station as a PWS (personal weather station) in wunderground, and share my weather information with anyone. The first step and the remainder of this page will detail the PWS implementation and testing, then on a later (and future) project I will elaborate on publishing to wunderground, and improvements done to the Weather Station after weeks of testing.
The components and requirementsThe following are the components I had at hand, honestly the only thing I would change is the rain gauge, but we will get to that later.
Zolertia RE-Mote platform
Disclaimer: I work at Zolertia (only to get freebies)
As obviously I have some RE-Motes laying around the house, and I wanted to implement the Weather Station to be wireless and with as low maintenance as possible. Being the RE-Mote an ultra-low power platform and with dual radio, these two requirements were met.
The RE-Mote has a built-in battery charger, so powering the Weather Station over LiPo batteries and recharging using the RE-Mote's USB connector with a common micro-USB cable was an easy option.
At the moment as my Weather Station is to be located on my balcony, next to the living room where my Raspberry Pi is installed, I'm using the 2.4GHz IEEE 802.15.4 radio interface, but in case I would ran out of radio juice then it would be straightforward to just shift to the 868/915MHz radio for a coverage boost. I'm using the 2JW031 multiband antenna, so no need for me to replace antennas if changing the radio interface (both are driven to the RP-SMA connector)
The RE-Mote is ported to Contiki OS, so building the application and porting any missing driver is fairly simple (unless you complicate yourself with fancy stuff as normally I tend to do...)
A sparkfun's Weather Meter
The Weather Meter is composed of three sensors: anemometer, rain gauge and a wind vane. The implementation of the sensors is quite straightforward: the anemometer and the rain gauge (a tipping bucket) "ticks" upon an even, so wiring up to a GPIO and capturing the interrupt is enough. The wind vane changes its resistor value depending on its angle. Following the datasheet instructions was easy enough to create the drivers (more about it later).
The Weather Meter has 3 x RJ-11 cables (same as telephones), the short one from the anemometer is to be connected to the wind vane (see below), so you end up with just 2 cables to connect: the rain gauge and the anemometer/wind vane (see below)
Instead of powering the sensors with 5V I used 3.3V, this has no significant impact on the performance or values, but only to recalculate the wind vane degrees/voltage relationship as follow:
/* From the datasheet we adjusted the values for a 3V divider, using a 10K
* resistor, the check values are the following:
* --------------------+------------------+-------------------------------
* Direction (Degrees) Resistance (Ohms) Voltage (mV)
* 0 33k 2532.55 *
* 22.5 6.57k 1308.44 *
* 45 8.2k 1486.81 *
* 67.5 891 269.97 *
* 90 1k 300.00 *
* 112.5 688 212.42 *
* 135 2.2k 595.08 *
* 157.5 1.41k 407.80 *
* 180 3.9k 925.89 *
* 202.5 3.14k 788.58 *
* 225 16k 2030.76 *
* 247.5 14.12k 1930.84 *
* 270 120k 3046.15 *
* 292.5 42.12k 2666.84 *
* 315 64.9k 2859.41 *
* 337.5 21.88k 2264.86 *
* --------------------+------------------+-------------------------------
*/
Also it is required to de-bounce the anemometer and rain gauge to prevent false readings.
One note of caution: the rain gauge when assembled and attached to the weather meter pole may produce false readings, as strong winds, vibration or similar causes the tipping bucket to... well... tip, this can be quite annoying as the only option I could think of was to either fix separately from the weather meter, on a flat surface, or use another sensor (like a moisture sensor) to validate the readings. Below is my attempt to secure the rain gauge using a zip strip, this proved to generate lesser fake readings.
Atmospheric pressure, Temperature and Humidity sensors
Luckily from a previous project I had a PCB made with the SHT25 and BMP085 I2C-based digital sensors on-board, featuring also 2 RJx11 ports to connect the Weather Meter. If you are not as lucky as me, you can purchase the sensors from Sparkfun, Seeedstudio or Zolertia (the BMP085/BMP180 and SHT21/SHT25 should do just fine as the code is the same).
If using Seedstudio sensors, be aware the connectors and cables are 2 mm pitch, while Zolertia's sensors and connectors are 2.54mm. If you notice on the photo, there is also an ambient light sensor (TSL2563), not used in this setup as I'm planning to put all the electronics in an IP65 enclosure.
LiPo rechargeable battery
I had this battery lying around, good enough for a first test. Its 4Ah capacity allows over 15 days of continuous operation running at 8mA (my worst case scenario), but this figure is way to conservative as the RE-Mote platform can go as down as 150nA, but I wasn't interested in optimizing for power consumption... yet!
The IP65 enclosure
When choosing an enclosure there's not to much of a choice, rugged and ugly are the normal choices, specially when diving upon the company storage room to try to find an IP65 enclosure big enough to host all components (specially the LiPo battery). One option to simplify the enclosure selection would probably be to change the LiPo battery model with a smaller one, but I didn't wanted to spend money on this.
Once I found an enclosure I made a fixture to keep the battery secured, and to place the RE-Mote on top, mostly to avoid jiggling components jumping inside the enclosure, specially in presence of strong winds. Using a female connector was enough to make an easily removable "lock" to remove the RE-Mote if needed.
I drilled a hole at the bottom to pass through the Weather Meter cables (I know this is not IP65-ish but I only cared about being water resistant on the other box faces), and also for the internal temperature and humidity to be roughly the same as the outside of the enclosure. As the hole was made at the bottom, in case of rain the electronics will not be affected, but I have yet to test if the humidity would not rise high to damage the boards, probably using a moisture absorbing bag should be enough.
The RE-Mote and Weather Meter pin-out are available in the previous section. To connect the sensors and the LiPo battery to the RE-Mote just follow the below instructions:
/* Component Pin
Anemometer PC1
Wind Vane PA5 (ADC1)
Rain Gauge PC0
Wind Vane PA5 (ADC1)
SDA (I2C) PC2
SCL (I2C) PC3
LiPo battery +VBAT
Ground DGND
3.3V D+3.3
*/
I used 2 x zip strip to secure the enclosure to the Weather Meter pole, drilling 4 small holes on the back of the enclosure. I have yet to put some epoxy on this to prevent water from entering the enclosure, or replace the strips with something easy to lock and unlock if required to dismount off the pole.
I wanted to use IPv6 for this weather station application, so I could run a local network (using an aaaa::/64
prefix) for testing, or a public IPv6 prefix to be able to connect to it remotely from anywhere enabled, or to other IPv6 devices.
At the moment is running on a local network with a Raspberry Pi acting as a Gateway, running an IPv6 UDP server to communicate with the Weather Station on IPv6.
The Weather Station application (Node)
I wanted to be able to reuse the Weather Station application as much as possible. For this particular project I'm using UDP over IPv6, but I wanted also to be able to easily switch to MQTT, CoAP, LWM2M or other.
For this implementation I'm using Contiki OS.
I implemented the Weather Station as an application running in a different process, taking care of the sensor initialization and readings separately from other network related processes. Below is the abstraction done:
The Makefile
uses the udp-client.c
as the networking application, running the weather-station.c
application underneath.
all: udp-client
TARGET = zoul
CONTIKI = ../../../..
CFLAGS += -DPROJECT_CONF_H=\"project-conf.h\"
CONTIKI_TARGET_SOURCEFILES += sht25.c bmpx8x.c weather-meter.c
PROJECT_SOURCEFILES += weather-sensors.c weather-station.c httpd-simple.c
CONTIKI_WITH_IPV6 = 1
include $(CONTIKI)/Makefile.include
The weather meter (anemometer, rain gauge and wind vane) library is located in weather-meter.c
, the SHT25 (temperature and humidity) and BMP085 (atmospheric pressure) sensor libraries are in sht25.c
and bmpx8x.c.
Contiki has a sensor interface that allows to initialize and poll the sensors as follow:
/* Activate the sensors */
SENSORS_ACTIVATE(weather_meter);
SENSORS_ACTIVATE(bmpx8x);
SENSORS_ACTIVATE(sht25);
Then we have the next data values available, saved directly into a weather_station_t
extern structure.
/* Poll the weather meter */
weather_sensor_values.rain_mm = weather_meter.value(WEATHER_METER_RAIN_GAUGE);
weather_sensor_values.wind_speed = weather_meter.value(WEATHER_METER_ANEMOMETER);
weather_sensor_values.wind_dir = weather_meter.value(WEATHER_METER_WIND_VANE);
weather_sensor_values.wind_dir_avg_int = weather_meter.value(WEATHER_METER_WIND_VANE_AVG_X);
weather_sensor_values.wind_speed_avg = weather_meter.value(WEATHER_METER_ANEMOMETER_AVG);
weather_sensor_values.wind_speed_avg_int = weather_meter.value(WEATHER_METER_ANEMOMETER_AVG_X);
weather_sensor_values.wind_speed_max = weather_meter.value(WEATHER_METER_ANEMOMETER_MAX);
The WEATHER_METER_ANEMOMETER_AVG_X
and WEATHER_METER_WIND_VANE_AVG_X
are return the value of the anemometer and wind vane averaged every 2 minutes as default. The default integration period can be changed by adding WEATHER_METER_CONF_AVG_PERIOD
to the project-conf.h
file with the desired value in seconds. The WEATHER_METER_ANEMOMETER_AVG
averages the wind speed value continuously, not over a given period. The other values are straightforward to understand (I hope!)
In the project-conf.h
file we define the GPIOs to use for the Anemometer and Rain Gauge, also the ADC channel to use for the Wind Vane. Notice we also include the NVIC_INT_GPIO_PORT_C
as the interrupt vector, in case we want to use any of the interrupt features of the weather-meter.c
driver.
#define WEATHER_METER_CONF_ANEMOMETER_PIN 1
#define WEATHER_METER_CONF_ANEMOMETER_PORT GPIO_C_NUM
#define WEATHER_METER_CONF_ANEMOMETER_VECTOR NVIC_INT_GPIO_PORT_C
#define WEATHER_METER_CONF_RAIN_GAUGE_PIN 0
#define WEATHER_METER_CONF_RAIN_GAUGE_PORT GPIO_C_NUM
#define WEATHER_METER_CONF_RAIN_GAUGE_VECTOR NVIC_INT_GPIO_PORT_C
#define WEATHER_METER_CONF_RAIN_WIND_VANE_ADC ZOUL_SENSORS_ADC1
The weather-station.c
application can be briefly resumed as:
/* Initialize sensors */
/* Notify applications about sensors being initialized */
/* Start the webserver */
/* Load default values (publish interval) */
/* Start the periodic timer */
while(1) {
/* Wait until a new configuration event from the webserver */
/* or to the timer to expire and publish sensor data */
}
/* End the process (never gets here) */
}
The Weather Station configuration webserver allows to change run-time operational values of the Weather Station, using browsers like Firefox
or Chrome
. The WS is implemented in the httpd-simple.c, below is a screenshot of the WS running on the Raspberry Pi using links. The URL of the WS is the IPv6 address of the Weather Station and the ws.html
page as shown below:
The configuration values are stored in the flash memory to make it persistent in case of a reboot.
The udp-client.c application just configures the UDP IPv6 connection and awaits for a data event from the Weather Station, then sends the data stored in the weather_station_t
structure.
while(1) {
PROCESS_YIELD();
if(ev == tcpip_event) {
tcpip_handler();
}
if(ev == weather_station_started_event) {
printf("Weather station started\n");
} else if (ev == weather_station_data_event) {
printf("Weather station data available\n");
send_packet();
}
}
To program the Weather Station just connect the RE-Mote over USB and:
cd contiki/example/zolertia/zoul/weather-station
make udp-client.upload
The Border Router (EDGE node) on the Raspberry Pi
The Border Router creates a virtual interface (similarly to the wlan0
WiFI interface), so packets coming from the 6LoWPAN network are forwarded as IPv6 packets and viceversa.
First program a different RE-Mote as Border Router:
cd examples/ipv6/rpl-border-router
make TARGET=zoul BOARD=remote border-router.upload
In the Raspberry Pi then enable the IPv6 module.
And connect the RE-Mote programmed as Border Router to any of the Raspberry USB port and do as follow:
git clone https://github.com/alignan/contiki.git
cd contiki && git checkout weather-station
cd tools
make tunslip6
sudo tunslip6 -s /dev/ttyUSB0 -t tun aaaa::1/64
This will create a network interface named tun
.
Now we can access the Border Router webserver and see if the Weather Station has joined the network as follows:
The software
As mentioned before, an UDP Server runs in the Raspberry Pi, binded to the local IPv4/IPv6 addresses. The server created the UDP connection then sits and wait for UDP packets to arrive, then does some data formatting to convert from 1-2 digit precision integers to floating point variables. We also multiply the rain gauge sensor values by 0.294
as we send the number of ticks, instead of millimetres.
In the screenshot above if enabling the print_recv_data function
, the content of the message is printed on screen.
To validate the Weather Station data and to ease my testing, the UDP server publish the results to Ubidots. Besides publishing my own data, I also send data to Ubidots from a nearby PWS (less than 300 metres away) using wunderground's API, and graph the values in the same plot to see how much close/far the readings are from each other, and have a sense of validation regarging I'm obtaining valid sensor data.
From the photo it seems the sensor data is OK, except the atmospheric pressure readings which seems a bit off, but then again I have to check if the altitude is affecting the readings (I live on a 6th floor while the ICERDANY6 PWS says its elevation is 318... but no units!).
To keep everything smooth and running I installed supervisor
, to keep the tunslip6 and UDP-Server processes running.
You can follow the results at the link below. Be aware that this is an active project so there may be times the weather station may be offline, or under testing indoors.
Ubidots weather station dashboard
Update (a week later)The weather station has been running for over a week now!
Before moving to the next phase of the project (to be done on a separate post) and register to wunderground, I need to verify the data is OK and ready to be published.
One correction I did was for the wind direction average calculation, as monitoring the data over Ubidots I found some really odd values:
This was due to some incorrect casting upon calculating the values, it is fixed now in the latest Github commit.
There is also something pending to be fixed, related to the enclosure being overheated when facing the sun. This has two solutions: changing the enclosure for a white one, or paint it white, to avoid the black enclosure from absorbing too much heat. The other one is to drill more holes to help ventilating the box.
As it is the battery lasts over a week, and takes over 1-2 hours to recharge over the USB cable (thanks to the RE-Mote built-in battery charger). The weather station stops working when the battery voltage drops to 2.75V approx. The average current draw is 28.4mA so there's a lot of room for improvement in the next phase of the project: the goal is to achieve an overall of 500-800uA.
This is the first step towards a bigger project, I have the following items pending on my to do list:
- Publishing weather information to wunderground
- Restarting average values at midnight (using the RE-Mote RTCC or the UDP Server via an UDP message)
- Sending Link Quality data from the Weather Station to graph on Ubidots
- Sending battery level information to trigger alarms when low battery
- Track reboot causes (if any), I ran the weather station for 15 hours without interruption
- Reduce the power consumption from 28mA to less than 1mA
But this will be material for a new follow-up project.
Comments