In an early version of the software I used to provide a sample configuration JSON file in the associated GitHub repository. Users had to download this file to a computer, update it with their Azure IOT Hub or Azure IoT Central connection string or AdafruitIO APIKey , frequency and device address, then upload to the field gateway.
In a later version of the software I added code which created an empty configuration file with defaults for all settings, many of which were a distraction as the majority of users would never change them.
More settings meant there was more scope for users to change settings which broke the device samples and the gateway.
I have removed the code to generate the full configuration file (starting with Azure IOT Hub field gateway) and included a sample configuration file with the minimum required settings in the GitHub repositories and installers.
I am assuming that if a user wants to change advanced settings they can look at the code and/or documentation and figure out the setting names and valid values.
The new sample configuration file for a Azure IoT Hub telemetry only gateway is
While building this AdaFruit.IO LoRa field gateway, and sample clients I revisited my RFM9XLoRa-Net library a couple of times adding functionality and renaming constants to make it more consistent. I made many of the default values public so they could be used in the field gateway config file.
The bare minimum configuration is
In this version of the protocol the message type & device identifier are nibbles packed into the first bye of the message. This saved a byte but limits the number of message types and device identifier length
// Copyright (c) 2018, devMobile Software
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
private const byte nRF24Channel = 10;
private const NRFDataRate nRF24DataRate = NRFDataRate.DR250kbps;
private readonly byte nRF24ClientAddress = Encoding.UTF8.GetBytes("T&H01");
private readonly byte nRF24BaseStationAddress = Encoding.UTF8.GetBytes("Base1");
private static byte deviceIdentifier;
private readonly OutputPort led = new OutputPort(Pins.ONBOARD_LED, false);
private readonly NRF24L01Plus radio;
private readonly SiliconLabsSI7005 sensor = new SiliconLabsSI7005();
radio = new NRF24L01Plus();
public void Run()
// Configure the nRF24 hardware
radio.OnDataReceived += OnReceive;
radio.OnTransmitFailed += OnSendFailure;
radio.OnTransmitSuccess += OnSendSuccess;
radio.Initialize(SPI.SPI_module.SPI1, Pins.GPIO_PIN_D7, Pins.GPIO_PIN_D3, Pins.GPIO_PIN_D2);
radio.Configure(nRF24ClientAddress, nRF24Channel, nRF24DataRate);
// Setup the device unique identifer, in this case the hardware MacAddress
deviceIdentifier = NetworkInterface.GetAllNetworkInterfaces().PhysicalAddress;
Debug.Print(" Device Identifier : " + BytesToHexString(deviceIdentifier));
Timer humidityAndtemperatureUpdates = new Timer(HumidityAndTemperatureTimerProc, null, 15000, 15000);
private void HumidityAndTemperatureTimerProc(object state)
double humidity = sensor.Humidity();
double temperature = sensor.Temperature();
Debug.Print("H:" + humidity.ToString("F1") + " T:" + temperature.ToString("F1"));
string values = "T " + temperature.ToString("F1") + ",H " + humidity.ToString("F0");
// Stuff the single byte header ( payload type nibble & deviceIdentifierLength nibble ) + deviceIdentifier into first byte of payload
byte payload = new byte[ 1 + deviceIdentifier.Length + values.Length];
payload = (byte)((1 <> 4];
// Mask off the upper 4 bits to get the rest of it.
hexString += hexChars[bytes[b] & 0x0F];
The diagnostics logging code was refactored several times and after reading this reference on docs.Microsoft.com I settled on the published approach.
I considered using the built in Universal Windows Platform (UWP) application data class but this would have made configuration in the field hard for most of the targeted users school students & IT departments.
I have the application running at my house and it has proved pretty robust, last week I though it had crashed because the telemetry data stopped for about 20 minutes. I had a look at the Device portal and it was because Windows 10 IoT core had downloaded some updates, applied them and then rebooted automatically (as configured).
I put a socket on the Raspberry PI nRF24L01 Shield rather than soldering the module to the board so that I could compare the performance of the Low and High power modules. The antenna end of the high power module tends to droop so I put a small piece of plastic foam underneath to prop them up.
I had code to generate an empty JSON configuration but I removed that as it added complexity compared to putting a sample in the github repository.
I considered using a binary format (the nRF24L01 max message length is 32 bytes) but the code required to make it sufficiently flexible rapidly got out of hand and as most of my devices didn’t have a lot of sensors (battery/solar powered *duinos) and it wasn’t a major hassle to send another message so I removed it.
I need to tidy up the project and remove the unused Visual Assets and have a look at the automated update support.