Weather Station : Transmission

My last posts discussed a little why the world desperately needed yet another weathers station, where I would place it and why and how the sensor package looked like. Now lets talk a little about data transmission.

Why

Given the position of the Sensor Package on roof of my house, a wireless solution was required.  Question is, which wireless system to use?  All the cool kids nowadays use WiFi modules like the ESP8266 to connect directly to the house WiFI network.  Its the obvious and the cleanest way of doing it as it also allows programming the Arduino over the wifi connection.  I did not go down that route for three reasons.

  • Wifi is pretty bad up there and I would have to put a repeater near it (inside the house) to make sure I have a reliable connection.
  • I really wanted a true mesh system that allows me to add sensors anywhere on the property, basically a backbone for home automation, alarms, chicken coop, hydroponics etc.  The more sensors (within reason), the denser the mesh, the more reliable the communication.
  • I thought building a radio communication from “ground” up mostly as a challenge to myself.  Yes, this was the real reason.

In the end, I chose to use the Xbee standard from Digi since it is a very well documented flavor of the even better documented Zigbee (IEEE 802.15.4).  Xbee allows true mesh radio systems with relatively low programming, a lot of the network maintenance code is already build in.

As a recap on mesh networks, this page explains them very well. The advantage is that it allows good network expansions since the devices form a communication chain. As long as there is a coordinator, a remote device can send data across multiple “hops”.  The downside is that the data transmission rate is pretty low – a lot of bandwidth is burned just to establish the mesh itself.  Eventually, my house-network will have maybe 25 sensors and devices permanently powered that periodically send a short burst of data (weather stations) or battery operated end devices that only come online when they have something to send (door / window sensors, driveway sensors etc).

Mesh Networks

Lastly, mesh networks have a few interesting features, in that a single device attempts to communicate with many other devices and assesses which signal strength (RSSI) is the strongest.  For static sensors, this is not a big deal.  But in the back of my mind I had the idea of using this system to track small, mobile objects (=cats) and use the RSSI as a means to identify where they are.  To be honest, I wanted to build it because several intelligent and knowledgeable engineers told me that it is a bad idea and I thought it would be cool to prove them wrong. But that is a project for later.

xbee-rssi

The picture above shows three sensors (coordinator, weather station and a Laptop (blue, left) communicating with each other.  The signal strength for each path is shown on the arrows.

Back to the weather station.  I have one XBee configured as Router (inside the Sensor Package) and another as Coordinator connected to an Arduino which also doubles as a clock, display unit and general “hub”.   But while Arduinos excellent in interacting with the world, their single-thread processing and limited storage make crummy computer replacements.   Eventually (so the internet tells me) I should move the coordinator to a Rasperry PI but for the same effort, I probably just use an old laptop.  As the my coordinator, I ended up using a Arduino Mega since an Uno already ran out of storage.

 

How

To run an Xbee inside a mesh as described above, I need to structure the data into a package that the coordinator understands and I spent way too much time trying to figure this out by following well-meaning YouTubers.  In the end I bought the excellent book “Building Wireless Sensor Networks” by  Matthijs Kooijman which made understanding and implementing the network extremely easy.

Alright so we have the weather station Sensor Package on the roof sending data every 30 seconds to the coordinator.  The entire sketch is on Gitub.


void sendPacket() {

detachInterrupt(AnemInterruptPin); //stop interrupts while sending package //this is probably overkill but I dont like taking chances with interrupts during transmissison
detachInterrupt(RainInterruptPin); //stop interrupts while sending package

WindSpeed = (AnemCount / sendInterval * 1000) * WindFactor;
MaxGust = (MaxGustCount / gustInterval * 1000) * WindFactor;
MinGust = (MinGustCount / gustInterval * 1000) * WindFactor;

if (MinGustCount == 0 || MinGustCount == 1000) { //messy code. Cant reset the MinGust to 0 since it will always be lower than any reading. Setting it to some large value
MinGust = 0;
}

MaxGustCount = 0;
MinGustCount = 1000; //messy way of doing it

RainRate = (RainCount * RainFactor); // accummulated raind during the interval. The true mm/[time] is done elsewhere
AnemCount = 0;
RainCount = 0;

In this function, I detach the two interrupts since I am paranoid that an interrupt will disrupt the transmission sequence. It may not be necessary but I felt it was safer. Then the wind speed is calculated from the data sheet of the anemometer, gusts are calculated as the delta between the maximum and minimum wind speed of 5 second intervals within the 30 second send interval.


// Prepare the Zigbee Transmit Request API packet
ZBTxRequest txRequest;
txRequest.setAddress64(0x0000000000000000); //I assume this is broadcast.


// Allocate 40 payload bytes. 10 parameters = 8x4 bytes + 1 byte.
// Appending this needs appending on the Coordinator as well - shouldnt one be able to use the length?

AllocBuffer<41> packet;

// Packet type, temperature, humidity
packet.append<uint8_t>(1); //this is the additional byte.
packet.append<float>(dhtT); //each parameter has 4 bytes
packet.append<float>(dhtH);
packet.append<float>(bmpT);
packet.append<float>(p0);
packet.append<float>(WindSpeed);
packet.append<float>(RainRate);
packet.append<float>(windDirection);
packet.append<float>(MaxGust);
packet.append<float>(MinGust);
packet.append<float>(millis()); //place holder for battery status or the like. not relevant

txRequest.setPayload(packet.head, packet.len());

// And send it
xbee.send(txRequest);
attachInterrupt(0, AnemAcq, RISING);
attachInterrupt(1, RainAcq, CHANGE);

The data package for the Xbee transmission is assembled very closely to the examples in Kooijman’s book. I was concerned that the package was getting too long but this has not been an issue yet. The package consists of 1 byte + 4 bytes for each parameter that I send, so a total of 41 bytes is sent every 30 seconds. (The code comment is wrong, it should read 10 parameters = 10×4 bytes) It works very well and the library takes care of the heavy lifting (HEX codes etc). One improvement would be to calculate the package length automatically but since the structure doesn’t change, its not a big deal. Obviously, every new measurement type increases the package on the sending and the receiving end by 4 bytes.

 

Improvements for future

I mentioned before that Xbees are perfect for “beacon-based” transmissions, i.e. let the coordinator run the timer and requests the data from the router rather than have each route send based on their own time.  This keeps the channel much more controlled especially when multiple Routers or end devices are in the system and space needs to be made for non-scheduled transmissions (such as status changes, door openings etc).  I’ll do that next year when the next round of sensors is installed.

One additional feature I did not install yet is “store and forward”.  In principle, radio communication is always slightly messy, environmental effects affect signal strengths, power outages can occur and in general “stuff just happens”.  Especially longer transmissions with a single checksum may get garbled.  The Xbee system has some safeguards but if power is lost to the coordinator for a few minutes, data will be lost.  Implementing a system to store incoming data until its confirmed as sent is standard in many wireless systems and likely something that I will look into in the future as well.

 

 

My next project is to improve the receiver end (coordinator), at the moment its a naked Arduino with a LCD display and second Arduino hanging on it with a WiFi shield.  It works but its very messy