In my previous post, I tested the ZMOD4510 sensor on my Arduino MKR WIFI 1010, and thankfully that process went really well
Now that I had the sensor part figured out, the next step was to get the MKR WIFI board connecting to WiFi and sending the data to my NodeRed installation on my little Raspberry Pi Server.
I was very hopeful for this part to be easier than the previous steps, because I've done the various steps before, on other boards.
But I've been hopeful before and it hasn't always turned out as simple as I had hoped.
Stay tuned to find out the exciting surprises that pop up in the continuing story of this garage air quality monitoring project!
Spoiler alert, it was thankfully not as surprising as one might have feared!
MQTT - Connecting the Arduino to my Raspberry Pi Server
To receive the data on the server side, I already had most of the Node-Red steps figured out for other projects, so I was able to piggy-back onto that work by copying it and making a few minor changes to the flow to gather the sensor data and show it in the debug nodes and in some basic gauges I set up.
This was enough for my initial testing, I decided to add the graphs later. One step at a time keeps it manageable!
As for sending the data, the MKR WIFI 1010 is specifically designed to work with WiFi, as the name implies, and with it being Arduino, it was easy to find an example of using exactly this board to send data via MQTT.
In fact, the Arduino website itself has an MQTT example specifically made for the MKR WIFI 1010: https://docs.arduino.cc/tutorials/mkr-wifi-1010/mqtt-device-to-device
Their tutorial sends MQTT between two Arduino boards, but because MQTT uses a general publish-subscribe model, it was very easy to change the receiver. So instead of another Arduino as the subscriber, it's almost trivial to have the Node-Red server on my Raspberry Pi be the subscriber instead (or in addition to, if so desired). I already had Mosquitto installed on my Raspberry Pi, so I'm using that as my MQTT broker. Node-Red has a node already built for this, so all I had to do was add that node and give it the proper settings for my MQTT broker and topic.
For the MQTT publisher sketch you can also just use the built-in example in the Arduino IDE, which is nearly identical. From the File menu, choose Examples - ArduinoMqttClient - WiFi Simple Sender.
Because we don't need to use an Arduino to receive data, we can just use the example for the publisher (aka sender), and ignore the subsriber (aka receiver) example.
To start with, I simply used a slightly modified version of the example to send some test data to my Node-Red server, in the JSON format I eventually intend to use for sending actual data.
It was then easy to verify, using the Arduino Serial Console as well as the Debug Console in Node-Red, that the Arduino board was connecting properly and sending information to my server.
In my case, the server verified that it was receiving information by giving me error messages LOL oops.
But it was not too difficult to figure out what I had done wrong: I used a Node-Red debug node to help me figure out a typo I had made - I had copied and pasted a line that included an extra set of closing quotation marks, which was throwing off the JSON format.
Note: My Raspberry Pi Mosquitto server is NOT exposed to the Internet - this meant I had to make sure that the Arduino board had to connect to the same local WiFi network as my Raspberry Pi. It also means that I could not use the guest network, as I usually would recommend, as it would have been isolated from the server that way. Using a free cloud MQTT server would give more flexibility, but I like having my setup be completely independent.
Here is my Node-Red flow at this point, and the resulting debug data as it shows up in Node-Red:
I've attached my sample MQTT app (InTheAirTonight_test_MQTT.ino) to this blog post. It's not much different than the examples I mentioned above, other than that it connects to my Raspberry Pi, uses my topic and client ID, and sends test data in JSON format that mimics the way real data will eventually be sent.
Note that you'll have to add your own arduino_secrets.h file to set the ssid and password for your own WiFI. Or remove the #include for it, and just replace the SECRET_xxx defines with your info. If you're trying to follow along, you might just want to start a new app from the aforementioned ArduinoMqttClient example and then do some cutting and pasting.
Merging the Sensor code with the MQTT code
Having verified that my MQTT communications code worked, and that both sending and receiving was now happening in the correct format, I could now move on to the next step of merging the ZMOD4510 code together with the MQTT code - this would then allow me to get the air quality data from the sensor into the Node-Red server.
My main worry was that maybe the ZMOD4510 sensor might somehow not play nice with the MKR WIFI's WiFi module once I activated it all together. There's always the chance of controls overlapping, memory usage being too much for the board to handle, or processing power not being enough to do it all at once.
However, the Arduino team built this little MKR WIFI 1010 board with some powerful components that are definitely up to the task!
The main processor is a SAMD21 Cortex-M0+ 32-bit processor that can run at 48 MHz, and the WiFi module, a u-blox NINA-W102, appears to have its own processing power that doesn't need much help from the main processor: "stand-alone multiradio MCU module that integrates a powerful microcontroller (MCU) and a radio for wireless communication."
The MKR WIFI 1010 board also has a LOT more memory than the earlier AVR model Arduino boards, with 256kB flash and 32kB of SRAM, where the Uno only has 32kB of flash and 2kB of SRAM.
Merging the code wasn't too difficult, as my communication code was already separated out into standalone functions and could therefore be copied into the Renesas sample quite easily.
Unfortunately, the Renesas source code is subject to their licence agreement, which includes this line that specifically forbids me to share my sample app with you: "the license granted is limited for Your internal use, only (in source form), and shall not be transferred nor access provided to any third party (in source form)".
But, as I mentioned above, integrating my communications code wasn't too difficult - if you are trying to build a similar application, you could use my communications sample as a guide (MIT licence, mostly meaning "free to use at your own risk"), and add it into the Renesas sample code like I just did. You'll have to get the Renesas libraries and samples directly from Renesas, of course.
Make sure you allow the sensor code to run outside of the "if (currentMillis" loop, so that sensor samples are taken in the intervals required for the AQI calculations, while the server only gets updated once a minute, or however often is desired.
I also recommend only sending data to the server after the warmup has completed. Using a simple bool flag makes that part easy. Otherwise you'll just end up with a bunch of zeroes for however long the warmup time is.
On the bright side, not being able to share the code allowed me to make the code super complicated and messy because nobody else gets to see it ;)
I think I'll rename all the variables to use the names of spongebob characters.
(Those who know me well enough won't know if I'm kidding or not LOL)
Don't forget to reset bikiniBottom at the end of the loop or else squarePants will not be called again.
At this point I had to be patient again, letting the sensor run long enough for the algorithm to have gathered enough data to give a FastAQI value, after which it started updating the server.
The sensor setup is actually pretty good righty now, but unfortunately it's still using hard-coded temperature and humidity values for the algorithm. As I was not able to get the HS4001 temperature and humidity sensor going, I am going to assume (and hope) that the temperature and humidity variations will be minor and hopefully won't affect my outcomes too much. I don't need super-accurate numbers anyways, as it's the general trends and ranges I'm looking for. My plan is to just take a temperature and humidity reading in the test area and use those values for the entire duration.
After running it for a few hours gathering data in my office, my dashboard was finally showing real data (except for the hard-coded humidity and temperature, of course).
In my next blog post I'll clean up the data a bit, store it, and set up some graphs to help visualize the air quality trends better.
And I should fix the errors in the AQI gauges - degrees Celsius.. oops!
InTheAirTonight_test_MQTT.ino.zip