The following work is a proof of concept of an innovative wireless sensor node based on Helium Atom modules for Internet of Things applications. The module has several features that makes it the best solution for an embedded sensor where reliable and connectivity are the primary requirements. The device is designed using commercially available components and featuring a variety of possible configurations for different scenarios, ranging from industrial sensor and actuator devices to agricultural and environment monitoring and portable applications.
IntroductionToday there is a wave after wave of IoT products and technologies getting into the shores of consumers and developers. From the point of view of the consumer, a lot of the available solutions have a high cost because manufacturer R&D and developing cost, somehow making them prohibited for simple solutions. For some applications in the industrial sector the price might not be an impediment as important, this sector looks for reliable and secure devices, but also with flexible solutions for today changing world.
For developers there is a bum of open source technologies such Arduino. Those are fine to make a mockup and develop your initial idea, but in order to test advance features and new technologies, a breadboard and flying cables might not give you the correct results, leading developers to wrong conclusion about the implementations. This might be the case where you want to test against battery operation factors such power consumption.
This project shows a product design that is ready for the market (with some software tweeks) but at the same a platform that enable developers to deploy a solution, allowing the introduction of software features only available with the underlying hardware.
About the Sensor IoT Node DevelopmentThe sensor heart is around the Helium Atom module and its central MCU. Atom modules are best used in conjunction with a micro controller unit that handles the required peripheral and low power operation. In order to achieve a fast developing and make it a more universal solution, the ATSAMD21G18 microcontroller is used, the same device used in the Arduino Zero board.
The following section discuss the hardware PCB and all its interfaces. Let's start by saying that the board has 78 mm by 78 mm in size. The aim was to make it as smaller as possible while making it compatible with a commercially available enclosure that can be mass produced. Though this project shows a 3D printing enclosure, it's actually an available part number from Polycase. I have found very useful to make the 3D print to validate the design as we will discuss later.
Because of the PCB size and all the interfaces and features included, the PCB has to be a 4 layer board and most components are somehow difficult to solder by hand. Because of budget constraints for this project the PCB was assembly at home using a home made reflow oven based on this open source profile controller. For this a stencil has to be made and manual component placement performed, which is feasible though still time consuming and error prone.
The sensor node is a real and ready product for the market. Here are a couple of images of how it looks like.
Uncovering reveal how external sensors and communication buses can be easily hookup using spring type terminal blocks.
The sensor node includes several interfaces ranging from communications, digital and analog I/O, Power On/Off actuators and built-in sensors. Some of them are not possible to have concurrently, this allows for a single PCB to carry different possible configurations and then different products are available using same PCB design. This might or might not be ideal for a final product, though special care has been made to have most of the SMD components on a single layer which lower SMD assembly cost, the I/O connectors and battery holders have to go in another layer which can be soldered by hand craft process.
The following interfaces and sensors which are available in no order of relevance:
- Temperature/humidity sensor
- Barometric sensor
- Internal battery measurement.
- One-Wire Line using strong pull device
- RS-485 interface
- Analog 0 - 15V input or digital (non-isolated) input with protection
- Serial Flash memory (64Mb)
- Isolated digital input
- 4-20mA industrial protected sensor interface
- AC output relay 2A rating
- 2 Outputs DC load switch, 2.7-18V @2A capable
- Arduino-compatible headers
- Helium Atom ready socket
The sensor node power supply design is one of the key elements of the product as it gives special capabilities such as be portable and be battery backed up for critical operations.
The key features of the power supply are:
- DC wall input 0 - 15V
- Two AA primary batteries with PCB holders
- USB power input
- DC wall input preference over AA battery input (The battery supply circuit is shutdown when external DC Input is detected.)
- Synchronous boost regulator with load switch to power down peripherals
- Can provides 3.3V @ 50mA from 0.7V input
- 5V LDO regulator
The following images shows where the aforementioned elements sections are located in PCB.
The communication connector is shared among One-Wire, RS-485 and 4-20mA sensor Input. The manner to select which is active is by using the jumpers at the Top layer. All the jumpers are 2 mm SMD jumpers to save board space. The example firmware has been developed to allow only one of those interfaces to be selected in a given build.
A few details are provided below regarding each interface.
Built-In Sensors
The sensors are I2C which allows easy integration.
A temperature / Humidity sensors HDC1080 from Texas Instruments is on board.
A pressure sensor MPL3115A2 from NXP is on board. It allows direct pressure, altimetry and temperature.
4-20 mA Sensor Interface
A precision current sense amplifier is used to sense external current. Other applications can be achieved but no extra care has been taken to allow high current sensing due to the distance from connector pins and precision resistor. Nonetheless low current sensing can be achieved by customizing the shunt resistor used.
For 4-20 mA a 1 Ohm 1% precision resistor is used. The analog output is feed directly to one of the Analog Input pins of the SAMD MCU. The arduino code example shows how to gather the samples using 12 bit resolution.
Here is an image of the setup used for testing and making the firmware. It uses a commercially available PT100 with a 4-20 mA transducer.
One-Wire Using External IC
The One-Wire bus can be routed directly from an MCU pin to the terminal block using jumpers. This is ok for short cable and perhaps when a single sensor attached. Because of this limitation among many others an external IC from Maxim Dallas DS2482-100 is included. It allows strong pull, better signal wave generation (slew rate) and easy interfacing using I2C bus. An example code is provided for interface with a temperature probe that uses DS18B20 IC.
RS-485 Communication Bus
One the most common communication buses found in industrial applications cannot be missing here. A linear LT2852 IC is used and hardware peripheral from SAM D21 MCU allows to have reliable communication. The testing demo code uses this port with a USB to RS-485 converter to allow serial console debugging.
PowerOutput Relay and Load Switches
An AC miniature relay can handle 2A AC loads, it can be configured as Normally Open or Normally Close. It shares the 4 position terminal block with two DC load switches capables of handling 2A DC loads up to 18V. The board can be configured to have :
- One (1) AC relay with both N.O. and N.C. contacts.
- One (1) AC relay with only N. O. contact and one (1) load switch
- Two (2) load switches.
In order to allow the load switches, a spare terminal block of two positions provides additional spare GND.
Digital and Analog I/O Lines
Two digital inputs can be obtained, one is isolated by means of Silicon Labs SI8712CC, this devices offer high speed and reliable operation for harsh environment. The other input is directly tied to an MCU I/O line and protected using Schottky diodes.
The analog Input shares the digital I/O lines, so only one can be configured for a given product life cycle. By voltage divider circuit a 0-15V range can be achieved.
Power Supply Details
At its heart, the power supply uses a Texas Instruments TPS61098x Boost converter with special features for even single AA cell battery. Because of the power requirements of Atom Wireless modules, it was choose to use two AA cells.
The Atom nodes are low-power modules, though they still require roughly 300mA when transmitting. The TPS61098X can certainly supply this current if the input voltage allows it, two discharged AA cells might provide 1.6V which will suffice to at least allow for RX and MCU operation. Two polymer SP capacitors from Panasonic allows for better stability and safety among other benefits.
An special feature of the TPS61098x device is that it has a load switch output (or a LDO output, though the former is used here) that can be use to shutdown certain devices on the board during shortages of power supply such as battery operation in order to save power.
A special mosfet device from ON Semiconductor NTGD1100L is used to shutdown the load whether a DC input from Wall adapter or USB connector is active. This way the battery is saved, otherwise battery will continue to be drained. It was necessary to introduce a Schottky diode in order to prevent reverse current flow from DC input to the primary batteries, this was not way to avoid as desired to prevent losses in the diode. Since currents are not so high and when operating from battery those might be seems as short pulses, it might not be too bad.
The 4 layer PCB is ENIG finished to better solderability.
Initial Setup
The SAMD21 MCU can be programmed using Atmel Studio, this is the preferable way for an embedded industrial application. The only drawback is that takes longer time to setup everything, specially for the fact that Helium Libraries are ready for arduino sketches.
For this reason the demonstration firmware was done using Arduino IDE. Before doing anything, it's necessary to Flash the Arduino bootlooader into the ATSAMD21G18A MCU. For this purpose, you can download the binary file from this adafruit nice tutorial and use the Atmel Studio with a JTAG device. Thereafter you are ready to load sketches.
Arduino Firmware
Let's discuss somehow the arduino code, for exact details you can access it at my github here.
The following section of code shows the includes necessary to compile the code.
#include "Arduino.h"
#include "Board.h"
#include "Helium.h"
#include "HeliumUtil.h"
// Need it for the serial port 2
#include "wiring_private.h" // pinPeripheral() function
// need it for the I2C sensor
#include <Wire.h>
#include "HDC1080JS.h"
#include <Adafruit_MPL3115A2.h>
#include "ArduinoJson.h"
#include <RTCZero.h>
#include "Time.h"
#include "TimeLib.h"
#include "Timezone.h"
#include "Adafruit_VEML6070.h"
I have found some conflict to compile the RTCZero library when using the Timezone library here. The problem solves when you comment both codes and compile, the enable it and should compile with just a warning about AVR code been use. It happens that the Timezone code uses the AVR eeprom feature, the you have to remove that code for the SAMD arch.
I have included the Serial2 definition in my variants.h and arduino core library. Specifically you should include the following code in variant.cpp
Uart Serial2( &sercom2, 3, 2, SERCOM_RX_PAD_1, UART_TX_PAD_2);
void SERCOM2_Handler()
{
Serial2.IrqHandler();
}
and the extern declaration in variant.h
extern Uart Serial2;
This was mainly because we change the debug port to Serial2 which is using the RS-485 interface. Since the Helium Sensor has the Arduino compatible headers you can actually use anything allowed for the SAMD. A good guide is here.
A part from that the code should compile smooth after you install the libraries.
I have used a lot of defines and ifdef clauses over the code to allow the compilation of certain features. This might be improved but it's a good starting point to avoid confusion. Other practice might be to have different repositories.
For example the following code
#ifdef PT100
#if defined(RS485)
#error "cannot use RS485 and PT100 - share I/O terminal block conflict"
#elif defined(ONEWIRE)
#error "cannot use ONEWIRE and PT100 - share I/O terminal block conflict"
#elif defined(ATOM)
#undef DEBUG_SERIAL
#endif
#endif
Will give you a compile error when enabling the PT100 sensor (4-20 mA) and trying to use the RS-485.
The PT100 4-20 mA transducer code is
#ifdef PT100
float get_pt100_temperature() {
int sensorValue;
float temperature = ERROR_PT100; // error condition
float current;
float voltage;
String err;
// read the analog voltage of current sense amplifier
analogReadResolution(12);
sensorValue = analogRead(A1);
voltage = sensorValue * (3.29 / 4095.0); // 1 OHM Shunt gives a Full Scale of ma
current = sensorValue * (32.9 / 4095.0); // 1 OHM Shunt gives a Full Scale of ma
if (current < 4.0) {
err = String("ERR: Open Sensor");
} else if (current > 20.0) {
err = String("ERR: Overcurrent Condition");
} else {
current = current - 4.0;
temperature = -50.0 + 12.50 * current; // 200C/16mA is the slope
String tmp_string = String(temperature);
err = String("PT100 Temp: " + tmp_string + " C");
}
#ifdef DEBUG_SERIAL
debugSerial->println(err);
#endif
return temperature;
}
#endif
I am using the latest (actually beta) library of well know arduino json here, be aware of it since the syntax has change and you might get some error using an old version of the library.
At the beginning of the Firmware execution, when it's time to connect the sensor node to Helium network, we include a code that gathers configuration parameters, in this case we can get the sample interval and timezone programmed to sensor. For this we have customized the update config function as shown below.
void update_config(bool stale)
{
if (stale)
{
debugSerial->print("Fetching Config - ");
debugSerial->println(CONFIG_INTERVAL_KEY);
int status = config.get(CONFIG_INTERVAL_KEY, &send_interval, 60000); // 60 seconds default
report_status(status);
debugSerial->print("Value: ");
debugSerial->println(send_interval);
debugSerial->print("Fetching Config - ");
debugSerial->println(CONFIG_TIMEZONE_KEY);
memset(tzone, 0, sizeof(tzone));
status = config.get(CONFIG_TIMEZONE_KEY, tzone, sizeof(tzone), (char*)"Eastern");
report_status(status);
debugSerial->print("Value: ");
debugSerial->println(tzone);
if (status == helium_status_OK)
{
// CONFIG VALUE INTERVAL
debugSerial->println("Updating Config - ");
debugSerial->print(CONFIG_INTERVAL_KEY);
debugSerial->print(" : ");
debugSerial->println(send_interval);
status = config.set(CONFIG_INTERVAL_KEY, send_interval);
report_status(status);
}
}
}
#endif
We update the integer variable interval and the Timezone string. The interval is somehow obvious that will be used in the arduino loop so it will delay one sample from the other.
The time zone is then adjusted after returning from the update function as below.
// Get the initial interval
update_config(true);
for (tzIndex = 0; tzIndex < sizeof(confTZnames); tzIndex++) {
if (confTZnames[tzIndex].equals(String(tzone))) {
break;
}
}
if (tzIndex > sizeof(confTZnames)) {
tzIndex = 0;
}
// Now tz has the Timezone accordingly to the configuraed value for the Atom Node
tz = timezones[tzIndex];
// Configure RTC as per the Network Epoch Value
helium.info(&info);
time_epoch = (time_t)info.time;
eastern = (*tz).toLocal(time_epoch);
TimeElements tm;
breakTime(eastern, tm);
rtc.begin(); // initialize RTC
// Set the time
debugSerial->print("epoch: ");
debugSerial->println(time_epoch);
rtc.setHours(tm.Hour);
rtc.setMinutes(tm.Minute);
rtc.setSeconds(tm.Second);
// Set the date
rtc.setDay(tm.Day);
rtc.setMonth(tm.Month);
rtc.setYear(tm.Year - 30);
Interesting is also the section of code that parses our variables to json and send to Google cloud.
#ifdef ATOM
size_t used;
int8_t result;
// This requires beta version of JsonLibrary
DynamicJsonDocument doc;
JsonObject root = doc.to<JsonObject>();
root[F("interval")] = send_interval;
char buffer[HELIUM_MAX_DATA_SIZE];
used = serializeJson(doc, buffer);
// Send data to channel
channel.send(buffer, strlen(buffer), &result);
// Print status and result
update_config(config.is_stale());
if (gstatus == helium_status_OK) {
// Get the TimeStamp Value
snprintf(TimeStampBuf, TimeStampSize, "%d-%02d-%02d %02d:%02d:%02d", rtc.getYear() + 2000, rtc.getMonth(), rtc.getDay(), rtc.getHours(), rtc.getMinutes(), rtc.getSeconds());
// Send some data to the configured Google channel
DynamicJsonDocument gdoc;
JsonObject groot = gdoc.to<JsonObject>();
groot[F("RH")] = lround(humid); // Humidity
groot[F("Ti")] = round2(temp); // Internal Temperature
groot[F("ALT")] = lround(altm); // Altitude in meters
groot[F("PHg")] = round2(pascals / 3377); // Pressure in Hg
groot[F("Te")] = round2(temp); // Internal Temperature
groot[F("DT")] = TimeStampBuf; // Datetime Value
groot[F("LS")] = uv_level; // Light Sensor Value
char gbuffer[HELIUM_MAX_DATA_SIZE];
memset(gbuffer, 0, sizeof(gbuffer));
used = serializeJson(gdoc, gbuffer);
#ifdef DEBUG_SERIAL
debugSerial->println("Sending - ");
debugSerial->println(gbuffer);
#endif
int status = GoogleChannel.send(gbuffer, strlen(gbuffer), &result);
// Print status and result
report_status_result(status, result);
}
#endif
Notice how we have used a pointer to select the debug Serial port such as
#ifdef DEBUG_SERIAL
#ifdef RS485
Uart *debugSerial = &Serial2;
#elif not defined(ATOM)
Uart *debugSerial = &Serial1;
#endif
#endif
This was an easy way to debug, sometimes I was working only on certain peripheral and could took off the Helium module and debug using TTL port.
Last but not least I did a test to include an external UV sensor which was mounted inside the sensor enclosure with an aperture for light obviously. It was handy to have the arduino headers for this.
Enough for talking, let see some video of how it looks our sensor.
Mechanical PartsAs mentioned before the sensor node use a commercially available enclosure from Polycase. It was 3d printed and it allow us to validate a few things.
- PCB mechanical fixture. This was somehow more difficult to handle the first time since the antenna cables from Taoglas company has to be pass at the bottom.
- The Atom module should be better placed directly on the PCB for a production units since the 2 mm headers increase the component height.
The Helium dashboard is very intuitive and friendly to use, it also very quick to get results.
At the time of this writing the sensor was logging every 5 minutes. The UV sensor was disconnected (in case you are wondering about the value) due to some problem to securely close the lid.
The configuration variables are neat mechanism to update things in your sensor node. Here is how the debug console look like when the sensor starts.
The cool thong is that if you change the configuration in the Helium dashboard it automatically detect it and adjust the operational parameters on the fly.
The Google Channels is also working as can be seen in the event log.
If you see this is because everything seems good at google cloud. Let's go there and check it out.
Google Cloud ChannelThe google configuration is not complicated but for newcomers like me you have to spend some time getting use to it. There are plenty of tutorials so I will just point you the key elements.
You need to create the Registry ID and input topic After that you need to setup Big Query and create the table, the table looks like this.
With the registry ID, the Pub/Sub Topic, the Table and temporary location you proceed as shown below to create the Job.
If everything goes well, after the Sensor Node start sending data you can check using a database query command.
There are plenty things to implement using google cloud and tools, for example you can setup a datastudio template that might look like this
From this point the possibilities are endless and very project and application dependent, also other channels can be used which is something that might change as per customer requirements, the important thing is that moving your data from the Sensor Node to the Cloud is now painless with Helium dashboard.
Final ThoughtsThe sensor node designed is a ready for the market device that has a variety of hardware options to accommodate a broad range of projects from industrial to environmental and government agency climate monitoring and even for home users. Here's a video of how it looks like at my home roof.
Happy sensing and IoTing with sensor node powered by Helium Atom module!
Comments