Connect Conduit to TTN LoRaWan via Poly Packet Fwd

One of the most versatile LoRa / LoRaWAN gateways on todays market is Multitech Conduit with LoRa module. This nice blue boxes comes in 2 flavours; mLinux with everything driven from the command line and standard config files and the AEP version with a web based UI. The AEP version is intended for private LoRaWan deployments and where quick and easy configuration is required. I am not going to discuss benefits of Multitech gateway, there is another post coming where I will compare gateways from several vendors one of them being Multitech.

AEP

AEP lorawan

I will focus now on how to configure your AEP box to talk to TTN with PolyPacket Forwarder.

To begin, you need to install the Poly Packet Forwarder on your box. I suggest to download the package to another system and then use scp to move it to your Conduit:

From another system, download the latest version of ipk binary from the following link: https://github.com/kersing/packet_forwarder/tree/master/multitech-bin

Use scp to copy it to your conduit:
scp poly-packet-forwarder_2.1-r3_arm926ejste.ipk admin@<IP_OF_YOUR_CONDUIT>:/tmp/

Ssh to your Conduit or use the console access via USB port (at the front, behind the plastic cover).

Now, you can install the ipk package by executing:

opkg install poly-packet-forwarder_2.1-r3_arm926ejste.ipk

In order to keep the Lora Network/Application server functionality of the Conduit, we will not change it’s mode via the UI. We will, just modify the startup file and add few additional config files.

In order to start Poly Packet Forwarder instead of the original packet forwarder, replace /etc/init.d/lora-network-server script with the following:

#!/bin/bash
set -e

NAME=”lora-network-server”

run_dir=/var/run/lora
conf_dir=/var/config/lora
conf_file=$conf_dir/lora-network-server.conf
conf_db=$conf_dir/lora-network-server.db

angel=/sbin/angel

net_server=/opt/lora/lora-network-server
net_server_log=/var/log/lora-network-server.log
net_server_pidfile=$run_dir/$NAME.pid

pkt_fwd=/opt/lora/poly_pkt_fwd
pkt_fwd_log=/var/log/lora-pkt-fwd-1.log
pkt_fwd_pidfile=$run_dir/lora-pkt-fwd-1.pid

lora_us_id=”MTAC-LORA-915″
lora_eu_id=”MTAC-LORA-868″

read_card_info() {
# product-id of first lora card
lora_id=$(mts-io-sysfs show lora/product-id 2> /dev/null)
lora_eui=$(mts-io-sysfs show lora/eui 2> /dev/null)
# remove all colons
lora_eui_raw=${lora_eui//:/}
}

do_start() {
JSON=$(curl -m 5 -s “127.0.0.1/api?fields=loraNetwork/lora,system/capabilities/lora,system/macAddress”)
LORA_ENABLED=$( echo $JSON | jsparser -p /result/loraNetwork_lora/enabled )
LORA_CAPABLE=$( echo $JSON | jsparser -p /result/system_capabilities_lora )
LORA_PKT_FWD=$( echo $JSON | jsparser -p /result/loraNetwork_lora/packetForwarderMode –isNull || true )
if [ “$LORA_PKT_FWD” = “true” ]; then
LORA_PKT_FWD=false
else
LORA_PKT_FWD=$( echo $JSON | jsparser -p /result/loraNetwork_lora/packetForwarderMode )
fi
MAC_ADDR=$( echo $JSON | jsparser -p /result/system_macAddress )

if [ “$LORA_ENABLED” != “true” ] || [ “$LORA_CAPABLE” != “true” ]; then
exit 0
fi

if [ “$LORA_PKT_FWD” = “true” ]; then
echo -n “Starting packet forwarder mode: “i
read_card_info
GW_ID=”${lora_eui//:/}”
mkdir -p $run_dir/1

USE_GPS=$( curl -m 5 -s “127.0.0.1/api/loraNetwork/lora/packetForwarderConfig” | jsparser -p /result | grep fake_gps | wc -c )
if [ “$USE_GPS” != “0” ]; then
pkt_fwd=/opt/lora/gps_pkt_fwd
fi

curl -m 5 -s “127.0.0.1/api/loraNetwork/lora/packetForwarderConfig” | jsparser -p /result | sed “s/\(.*gateway_ID\”\s*\:\s*\”\)[^\”]*\(.*\)/\1${GW_ID}\2/g” > /var/run/lora/1/global_conf.json
# start packet forwarder
start-stop-daemon –start –background –make-pidfile \
–pidfile $pkt_fwd_pidfile –exec $angel — \
$pkt_fwd -c $run_dir/1 -l $pkt_fwd_log
renice -n -20 -p $(pgrep $(basename $pkt_fwd))
echo OK
exit 0
fi

/usr/bin/python /sbin/loraconfig.py
read_card_info

if ! [ -f $conf_file ]; then
echo “$0: $conf_file missing”
exit 1
fi

echo -n “Starting $NAME: ”
mkdir -p $run_dir/1
# start network server
start-stop-daemon –start –background –make-pidfile \
–pidfile $net_server_pidfile –exec $angel — \
$net_server -c $conf_file –lora-eui $lora_eui –lora-path $run_dir –db $conf_db \
–noconsole -l $net_server_log
sleep 2
# start packet forwarder
start-stop-daemon –start –background –make-pidfile \
–pidfile $pkt_fwd_pidfile –exec $angel — \
$pkt_fwd -c $conf_dir -l $pkt_fwd_log

renice -n -20 -p $(pgrep lora-network-se)
renice -n -20 -p $(pgrep $(basename $pkt_fwd))

echo “OK”
}

do_stop() {
echo -n “Stopping $NAME: ”
start-stop-daemon –stop –quiet –oknodo –pidfile $net_server_pidfile –retry 15
start-stop-daemon –stop –quiet –oknodo –pidfile $pkt_fwd_pidfile –retry 5
rm -f $net_server_pidfile $pkt_fwd_pidfile
echo “OK”
}

case “$1” in
“start”)
do_start
;;
“stop”)
do_stop
;;
“restart”)
## Stop the service and regardless of whether it was
## running or not, start it again.
do_stop
do_start
;;
*)
## If no parameters are given, print which are avaiable.
echo “Usage: $0 {start|stop|restart}”
exit 1
;;
esac

As I mentioned before, DO NOT MODIFY ANYTHING via your UI!!!

Now, you just need to add your local config files into /var/config/lora/ folder on the conduit:

global_conf.json

{
"SX1301_conf": {
"lorawan_public": true,
"clksrc": 0, /* radio_1 provides clock to concentrator */
"radio_0": {
"enable": true,
"type": "SX1257",
"freq": 912200000,
"rssi_offset": -166.0,
"tx_enable": true
},
"radio_1": {
"enable": true,
"type": "SX1257",
"freq": 913000000,
"rssi_offset": -166.0,
"tx_enable": false
},
"chan_multiSF_0": {
"enable": true,
"radio": 0,
"if": -300000
},
"chan_multiSF_1": {
"enable": true,
"radio": 0,
"if": -100000
},
"chan_multiSF_2": {
"enable": true,
"radio": 0,
"if": 100000
},
"chan_multiSF_3": {
"enable": true,
"radio": 0,
"if": 300000
},
"chan_multiSF_4": {
"enable": true,
"radio": 1,
"if": -300000
},
"chan_multiSF_5": {
"enable": true,
"radio": 1,
"if": -100000
},
"chan_multiSF_6": {
"enable": true,
"radio": 1,
"if": 100000
},
"chan_multiSF_7": {
"enable": true,
"radio": 1,
"if": 300000
},
"chan_Lora_std": {
"enable": true,
"radio": 0,
"if": 400000,
"bandwidth": 500000,
"spread_factor": 8
},
"chan_FSK": {
"enable": false,
"radio": 0,
"if": 100000,
"bandwidth": 250000,
"datarate": 100000,
"freq_deviation" : 25000
},
"tx_lut_0": {
/* TX gain table, index 0 */
"pa_gain": 0,
"mix_gain": 8,
"rf_power": -6,
"dig_gain": 0
},
"tx_lut_1": {
/* TX gain table, index 1 */
"pa_gain": 0,
"mix_gain": 10,
"rf_power": -3,
"dig_gain": 0
},
"tx_lut_2": {
/* TX gain table, index 2 */
"pa_gain": 0,
"mix_gain": 12,
"rf_power": 0,
"dig_gain": 0
},
"tx_lut_3": {
/* TX gain table, index 3 */
"pa_gain": 1,
"mix_gain": 8,
"rf_power": 3,
"dig_gain": 0
},
"tx_lut_4": {
/* TX gain table, index 4 */
"pa_gain": 1,
"mix_gain": 10,
"rf_power": 6,
"dig_gain": 0
},
"tx_lut_5": {
/* TX gain table, index 5 */
"pa_gain": 1,
"mix_gain": 12,
"rf_power": 10,
"dig_gain": 0
},
"tx_lut_6": {
/* TX gain table, index 6 */
"pa_gain": 1,
"mix_gain": 13,
"rf_power": 11,
"dig_gain": 0
},
"tx_lut_7": {
/* TX gain table, index 7 */
"pa_gain": 2,
"mix_gain": 9,
"rf_power": 12,
"dig_gain": 0
},
"tx_lut_8": {
/* TX gain table, index 8 */
"pa_gain": 1,
"mix_gain": 15,
"rf_power": 13,
"dig_gain": 0
},
"tx_lut_9": {
/* TX gain table, index 9 */
"pa_gain": 2,
"mix_gain": 10,
"rf_power": 14,
"dig_gain": 0
},
"tx_lut_10": {
/* TX gain table, index 10 */
"pa_gain": 2,
"mix_gain": 11,
"rf_power": 16,
"dig_gain": 0
},
"tx_lut_11": {
/* TX gain table, index 11 */
"pa_gain": 3,
"mix_gain": 10,
"rf_power": 20,
"dig_gain": 0
},
"tx_lut_12": {
/* TX gain table, index 12 */
"pa_gain": 3,
"mix_gain": 11,
"rf_power": 23,
"dig_gain": 0
},
"tx_lut_13": {
/* TX gain table, index 13 */
"pa_gain": 3,
"mix_gain": 12,
"rf_power": 24,
"dig_gain": 0
},
"tx_lut_14": {
/* TX gain table, index 14 */
"pa_gain": 3,
"mix_gain": 13,
"rf_power": 25,
"dig_gain": 0
},
"tx_lut_15": {
/* TX gain table, index 15 */
"pa_gain": 3,
"mix_gain": 15,
"rf_power": 26,
"dig_gain": 0
}
},
"gateway_conf": {
/* change with default server address/ports, or overwrite in local_conf.json */
"gateway_ID": "008000000000XXXX",
/* Devices */
"gps": true,
"beacon": false,
"monitor": false,
"upstream": true,
"downstream": true,
"ghoststream": false,
"radiostream": true,
"statusstream": true,
/* node server */
"server_address": "127.0.0.1",
"serv_port_up": 1780,
"serv_port_down": 1782,
/* node servers for poly packet server (max 4) */
"servers":
[ { "server_address": "127.0.0.1",
"serv_port_up": 1780,
"serv_port_down": 1782,
"serv_enabled": true },
{ /* "server_address": "us01-iot.semtech.com", */
"server_address": "12.13.93.141",
"serv_port_up": 1780,
"serv_port_down": 1780,
"serv_enabled": false },
{ /* "server_address": "router.us.thethings.network", */
"server_address": "router.us.thethings.network",
"serv_port_up" : 1700,
"serv_port_down" : 1700,
"serv_enabled": true },
{ /* "server_address": "ott1.iothub.ca", */
"server_address": "ott1.iothub.ca",
"serv_port_up": 1700,
"serv_port_down": 1700,
"serv_enabled": true }],
/* adjust the following parameters for your network */
"keepalive_interval": 12,
"stat_interval": 20,
"push_timeout_ms": 120,
"synch_word" : 52,
/* forward only valid packets */
"forward_crc_valid": true,
"forward_crc_error": false,
"forward_crc_disabled": true,
/* GPS configuration */
"gps_tty_path": "/dev/ttyAMA0",
"fake_gps": true,
"ref_latitude": YOUR_LAT,
"ref_longitude": YOUR_LON,
"ref_altitude": YOUR_ALT,
/* Ghost configuration */
"ghost_address": "127.0.0.1",
"ghost_port": 1918,
/* Monitor configuration */
"monitor_address": "127.0.0.1",
"monitor_port": 2008,
"ssh_path": "/usr/bin/ssh",
"ssh_port": 22,
"http_port": 80,
"ngrok_path": "/usr/bin/ngrok",
"system_calls": ["df -m","free -h","uptime","who -a","uname -a"],
/* Platform definition, put a asterix here for the system value, max 24 chars. */
"platform": "*",
/* Email of gateway operator, max 40 chars*/
"contact_email": "YOUR_EMAIL",
/* Public description of this device, max 64 chars */
"description": "YOUR_GW_DESCRIPTION"
}
}

Keep in mind, that this example is for SubBand 7 of North American flavour of Lora.
The local_conf.json will overwrite respective portion go global_conf.json with your site specific information

local_conf.json
{
/* Put there parameters that are different for each gateway (eg. pointing one gateway to a test server while the others stay in production) */
/* Settings defined in global_conf will be overwritten by those in local_conf */
"gateway_conf": {
/* you must pick a unique 64b number for each gateway (represented by an hex string) */
"gateway_ID": "008000000000XXXX",
/* Email of gateway operator, max 40 chars*/
"contact_email": "YOUR_CONTACT_EMAIL",
/* Public description of this device, max 64 chars */
"description": "DESCRIPTION_OF_YOUR_GATEWAY",
/* Enter VALID GPS coordinates below before enabling fake GPS */
"fake_gps": true,
"ref_latitude": YOUR_GPS_LAT,
"ref_longitude": YOUR_GPS_LON,
"ref_altitude": YOUR_GPS_ALT
}
}

There is one more thing, since the UI controls switching between Packet forwarder mode and Network server mode, you will have no logging for the packet forwarder. In order to enable it, you need to issue the following command from your console:
curl 127.0.0.1/api/loraNetwork -X PUT -d '{"log":{"syslog":false}}' -H "Content-Type: application/json"

At this point you can restart you lora service /etc/init.d/lora-network-server restart and your log should confirm that everything is in order:
tail -f /var/log/lora-pkt-fwd-1.log
# Invalid gps time reference (age: 1464959181 sec)
# Manual GPS coordinates: latitude ....., longitude ...., altitude 111 m
##### END #####
INFO: [down] for server router.us.thethings.network PULL_ACK received in 106 ms
INFO: [up] PUSH_ACK for server router.us.thethings.network received in 108 ms
INFO: [up] PUSH_ACK for server ott1.iothub.ca received in 35 ms
INFO: [down] for server 127.0.0.1 PULL_ACK received in 1 ms
INFO: [down] for server ott1.iothub.ca PULL_ACK received in 34 ms
INFO: [down] for server router.us.thethings.network PULL_ACK received in 105 ms
INFO: [down] for server 127.0.0.1 PULL_ACK received in 1 ms
INFO: [down] for server ott1.iothub.ca PULL_ACK received in 34 ms

As you can see, we are also connecting to the localhost, so Conduit’s network server. I used that for some tests and find it very helpful.

At this point you can start your node-red (on the Conduit) and configure it to connect to TTN to retrieve and process your packets:

ttn

ttn

node-red & lorawan

node-red & lorawan

From the node-red, processed packets are send to InfluxDB and then Grafana provides nice user interface:

SenseInAir over lorawan

SenseInAir over lorawan

Please let me know if you are interested in any write-ups on Node-Red and TTN (or other LoRaWan networks), but for now enjoy your AEP Conduit communicating flawlessly with The Things Network and LoRaWan.

 

 

 

 

Air Quality Index – Part 2; LoRaWan Sensor

As indicated in our previous post, affordable Air Quality Index (AQI) measurements could help to establish a better view and understanding on what is really happening around you as far as Air Quality. Having a consolidated view and data provided in a consistent way by many sensors, will provide a single source of accurate indication of trends as well as historical data. Different technologies could be used to transmit data to the Cloud, low power and long range being preferred. With increasing penetration of Air Quality Sensor #2LoRaWan, design of such sensor became feasible. After several long discussions, we have decided to create one. The main objective was a affordability. Virtual everyone should be able to afford it. At the same time, we do not want to “cut any corners” and we decided to measure all relevant parameters necessary to calculate Air Quality Index, just like the local Governments would do.

gases: NO2, SO2, CO and O3

particles condensation at PM2.5 and PM10.

The clean power was our secondary objective. After researching available energy sources, we have decided that solar power combined with good rechargeable battery was the most reliable source of energy for our project.

The prototypes are already collecting data across 3 continents, well still only 3 cities :). The product will be available soon through SensorsConnect web site.  The product, collects all necessary variables required to establish Air Quality Index;  In addition, temperature, humidity and GPS location are also measured. Collected measurements are sent over LoRaWan, operating in either private or public mode on European or North American bands of LoRaWan. In North American flavour, users can connect via full 64+8 mode gateway or hybrid mode gateway limited to one of the 8 sub-bands configurable via our provisioning interface. Each node will ship factory pre-calibrated and will provide a mechanism to self-calibrate in a clear Air. Configuration of measurement cycle duration, GPS mode of operation and LoRaWan specific parameters is available over LoRaWan and/or BLE (future perhaps). The GPS sensor provides location information and accurate clock for the unit. By default, GPS operates in a Mobile mode, collecting location information as often as a measurement cycle is called. In order to improve DSCF2201-Editbattery life, or simple if your device is mounted permanently at one location, GPS activity can be limited. SenseInAir® (SIA) can be re-configured to operate in a stationary or fixed position mode where only a single GPS lookup is performed in order to establish location and set unit’s internal Real Time Clock. However, having the Mobile GPS mode presents an interesting opportunity for Cities fully covered by LoRaWan. Driving around in an electric car (with the unit on your dash), could generate a virtual map of a region, indication AQI factors for all critical parts of the City. Areas and factories causing higher pollution could be easily identified and monitored.

The node will be ready for expansion. Optional (future) Zigbee interface and matching future firmware releases will accommodate additional sensors and turn it into a smart Zigbee/LoRaWan bridge. We are still contemplating if that makes sense, as it will obviously increase the unit cost. The SenseInAir® is based on STMicroelectronics STM32 series MCU designed for the Ultra-Low power mode of operation. During idle time, MCU and sensors together, consume below 1uA.  With our carefully crafted hardware design and power saving algorithms, the SensorsConnect device can operate for a long time on a single battery charge, even when sun is not cooperating. For special cases, where solar charging is not suitable as energy source, the SenseInAir® could utilize a industrial grade Lithium battery strong enough to provide several years of maintenance free operation. As I mentioned before, an optional Bluetooth LE can help with initial provisioning and/or field provisioning of the unit, however full provisioning can also be performed over LoRaWan. Units, can also be ordered with custom configuration or pre-provisioned for one of the existing LoRaWan networks, ready to be plugged in and connect without any configuration. The default profile will connect via The Things Network. Affordable cost should allow ordinary citizens to install those units in their backyards. Cities will be able to install hundreds of units  per municipality. Such array of those sensors will provide accurate map indicating changes and trends in air DSCF2205-Editquality and pollution across a City. This information could be valuable for different applications, for instance, cars could be re-directed to alternate roads should the primary roads be over polluted.  For areas without LoRaWan coverage BLE could be used to access the data locally from the single node. Additional sensors for SenseInAir® such as inside VOC ( Volatile Organic Compound), CO2 and radiation (alpha, beta and gamma) will be available at later time. The SenseInAir® will be followed by SenseInWater® and SenseInSoil® devices.

Stay tuned, in the next couple of posts, we will present SenseInAir® dashboard and will discuss sensors calibration and methods to obtain accurate data.

Hands On with RM7201 & RM7601 LoRa modules by Dapu Telecom

During the last LoRa Alliance meeting in Rotterdam we discovered a new LoRa modules  made by Shenzhen (China) based company, Dapu Telecom.

There are 4 options available, 2 radio only modules based on SX1272 and SX1276 Semtech chips and two complete modules with MCUs also based on SX1272 and SX1276 called respectively RM7201 and RM7601.

For this exercise, we obtained radios with MCUs. One important note, there is no specific part number for EU, Asia or North America. According to Dapu, the software stack will set the radio into the respective ISM band for your region. This requires further investigation, as small hardware changes between EU and North America (RF part) are present in Semtech’s reference designs.

Here is the RM7601 with MCU and SX1276 radio chip

Screen Shot 2015-12-21 at 2.49.54 PM

This is theRM7201 with MCU and SX1272 radio chip

Screen Shot 2015-12-21 at 8.51.07 PM

Both of them use the same MCU – STM32L151C8U6, only the radio is different as mentioned above.

If you go to the official Semtech git repository and look at their demo code, you will find out that Semtech uses the STM32L151 MCU series as well, just using a different variant of this MCU. This will most likely allow us to port the Semtech LoraWan stack to DAPU hardware with minimal effort.

First, let’s try the “big one” – RM7601.

Get the latest source code for the Semtech LoRaWan stack from https://github.com/Lora-net/LoRaMac-node  or just download the latest zip file from https://github.com/Lora-net/LoRaMac-node/archive/master.zip.

Store the source code onto your local hard drive, let’s say C:\LORA\ and unzip it, then go to C:\LORA\LoRaMac-node-master\Keil\SensorNode\LoRaMac\classA, use Keil5 (i used Keil5.17 lasted one) to open the project. Why “SensorNode” demo code? because that code uses the same MCU as one used in RM7601 module.

As Semtech used Keil4 to create the LoRaWAN demo code, Keil will first migrate the project to Keil5 when you first open it, just allow it do to so.

In the RM7601 data sheet for the SX1276 radio chip we see the following pin definitions:

Screen Shot 2015-12-21 at 8.57.44 PM

following this table, we can quickly change the Semtech source code and update pin definitions in C:\LORA\LoRaMac-node-master\src\boards\SensorNode\board.h to the following pins as follows:

/*
* Board MCU pins definitions
*/
#define RADIO_RESET PB_10
#define RADIO_MOSI PA_7
#define RADIO_MISO PA_6
#define RADIO_SCLK PA_5
#define RADIO_NSS PA_4
#define RADIO_DIO_0 PB_11
#define RADIO_DIO_1 PC_13
#define RADIO_DIO_2 PB_9
#define RADIO_DIO_3 PB_4
#define RADIO_DIO_4 PB_3
#define RADIO_DIO_5 PA_15

#define RADIO_ANT_SWITCH_HF PA_0
#define RADIO_ANT_SWITCH_LF PA_1

#define OSC_LSE_IN PC_14
#define OSC_LSE_OUT PC_15
#define OSC_HSE_IN PH_0
#define OSC_HSE_OUT PH_1

The most important ones are the SPI bus 4 wires and radio DIO_0 to DIO_5 definitions, just make sure that you have correct pin definition in your code.

Screen Shot 2015-12-21 at 3.41.47 PM

Change the main.c file to join the gateway using OTA mode:

#define OVER_THE_AIR_ACTIVATION 1

add the AppEUI, DevEUI and AppKey based on your gateway settings, here is what I did:

#define LORAWAN_DEVICE_EUI { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }
#define LORAWAN_APPLICATION_EUI { 0xc0, 0xff,0xee, 0x00, 0x00, 0x00,0x00,0x02 }
#define LORAWAN_APPLICATION_KEY { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }

Please pay attention, the AppEUI is reversed (LSB ENDIANNESS).

As my LoRa Gateway is running at 915Mhz frequency, I changed the compiler option to “Loramac-915”. It is important and don’t forget to set this for properly your region.

Here are my gateway settings:

root@mtcdt:~# cat /var/config/lora/lora-network-server.conf
{
  "lora": {
    "netID": "010203", /* netID for beacon packets */
    "frequencyBand": "915", /* US="915", EU="868" */
    "frequencySubBand": 1, /* Sub-band for US operation, 1-8 */
    "rx1DatarateOffset": 0, /* Datarate offset for mote rx window 1 sent in join response (0-3)   */
    "rx2Datarate": 12, /* Datarate for mote rx window 2 sent in join response (7-12) */
    "maxTxPower": 26, /* Max Tx power (dBm), -6 to 26 */
    "frequencyEU": 867500000 /* center freq for extra EU channels (Hz) */
  },
  "udp": {
    "appPortUp": 1784, /* port for user-developed application use */
    "appPortDown": 1786 /* port for user-developed application use */
  },
  "addressRange": {
    "start": "00:00:00:01", /* address range used for mDots */
    "end": "FF:FF:FF:FE"
  },
  "network": {
    "public": true, /* set to false for private LoRa network with mDots + Conduit */
    "leasetime": 1440, /* time until mDot join expires (minutes) */
    "eui": "02:00:00:00:00:ee:ff:c0", /* configure network security */
    "key": "2b:7e:15:16:28:ae:d2:a6:ab:f7:15:88:09:cf:4f:3c"
  },
  "log" : {
    "console" : true,
    "syslog" : false,
    "level" : 100, /* error=10, warn=20, info=30, debug=50, trace=60, max=100 */
    "path": "/var/log/lora-network-server.log"
  },
  "mqtt": {
    "enabled": true
  }
}

Compile the code and flash it to the RM7601, then login via ssh into your gateway and watch for our updated module to join the gateway. For help on how to set up the Multi-tech gateway, please follow our blog posts:

LoRa Hands On Part 1

LoRa Hands On Part 2

LoRa Hands On Part 3

$ ssh -l root 192.168.1.181
root@mtcdt:~# tail -f /var/log/lora-network-server.log
8:19:36:716|DEBUG| Received packet
================================
000 00 c0 ff ee 00 00 00 00
008 02 01 23 45 67 89 ab cd
010 ef 27 9b 5f f0 dd d1

8:19:36:717|DEBUG| Rx on 903700000, rssi: -27 snr: 98
8:19:36:717|DEBUG| Received frame: type: Join Request
8:19:36:717|INFO| Received join request
8:19:36:718|DEBUG| BUFFER: 00c0ffee00000000020123456789abcdef279b
8:19:36:718|DEBUG| App EUI: 02.00.00.00.00.ee.ff.c0
8:19:36:718|DEBUG| Dev EUI: ef.cd.ab.89.67.45.23.01
8:19:36:719|DEBUG| Nonce: 00009b27
8:19:36:719|DEBUG| MIC is valid
8:19:36:720|DEBUG| Got appkey: 2b.7e.15.16.28.ae.d2.a6.ab.f7.15.88.09.cf.4f.3c
8:19:36:720|DEBUG| DEV NONCE: 9b27
8:19:36:720|DEBUG| APP NONCE: 3be317
8:19:36:721|DEBUG| session keys: bac1a83854b7545eec7e3df4f305991d 9839190af648989e6d344ac5078cc4ce
8:19:36:721|TRACE| SQL query = SELECT address FROM nodes WHERE deveui = "efcdab8967452301"
8:19:36:723|INFO| Device found in DB, assigning address: 7
8:19:36:723|DEBUG| Update session keys
8:19:36:724|TRACE| SQL query = UPDATE nodes SET authenticationkey = "bac1a83854b7545eec7e3df4f305991d", encryptionkey = "9839190af648989e6d344ac5078cc4ce" WHERE address = "00000007"
8:19:36:727|DEBUG| Set node active: 1
8:19:36:727|INFO| Queue join response 17 bytes
8:19:36:728|DEBUG| Set node active: 1
8:19:36:728|DEBUG| update bestGateway
8:19:36:728|DEBUG| Time: 39995444
8:19:36:728|DEBUG| App Queue Length: 1
8:19:36:729|DEBUG| Rx Frame seq 0 snr 98
8:19:36:729|DEBUG| SpreadingFactorStore::Add
8:19:36:729|DEBUG| FindSF : snr : 98 100 -2
8:19:36:731|TRACE| SQL query = UPDATE nodes SET jointime = "2015-12-21T08:19:36Z" WHERE address = "00000007"
8:19:36:734|TRACE| SQL query = UPDATE packets SET port = 2, seqno = 0, gateway = "0080000000009f6c", time = "2015-12-21T08:19:36Z", microseconds = 713268000, rssi = -27, channel = 7, lsnr_cB = 98, spread = 10, modulationbandwidth = 125, data = "0123456789abcdef279b" WHERE node = "00000007"
8:19:36:738|TRACE| SQL query = UPDATE nodes SET lastuppacketid = 1, lastmessagems = 51204 WHERE address = "00000007"
8:19:36:740|TRACE| SQL query = UPDATE gateways SET lastuppacketid = 1 WHERE address = "0080000000009f6c"
8:19:36:743|DEBUG| getTimeOnAirMs dr: 10 bw: 2 pl: 8 sz: 16 toa: 82
8:19:36:744|INFO| Send Join Accept - EUI: ef:cd:ab:89:67:45:23:01 ADDR: 00000007
8:19:36:744|INFO| Schedule TX Time on air: 150 ms
8:19:36:752|DEBUG| Send MQTT message
8:19:36:753|DEBUG| UDP message: lora/ef:cd:ab:89:67:45:23:01/joined
8:19:36:753|DEBUG| UDP port: 1784
8:19:36:756|TRACE| Published message: 2
8:19:37:266|TRACE| Parse downstream message 12 bytes
8:19:37:267|TRACE| Gateway 00:80:00:00:00:00:9f:6c seen IP address 127.0.0.1:33742
8:19:41:597|DEBUG| is frame ready?
8:19:41:597|DEBUG| App Queue Length: 1
8:19:41:597|DEBUG| BestGateway: 80000000009f6c
8:19:41:598|DEBUG| Start
8:19:41:598|INFO| Frame transmitted to 00:00:00:07 via GW (00:80:00:00:00:00:9f:6c Chan FC1 127.0.0.1:33742) Seq# 2
8:19:41:599|TRACE| SQL query = UPDATE nodes SET lastdownmsgseqno = 2 WHERE address = "00000007"
8:19:41:602|DEBUG| App Data Queue: 1 front size: 17 available: 242
8:19:41:602|DEBUG| check if front is join request 17 bytes
8:19:41:602|DEBUG| Start
8:19:41:603|TRACE| App Data Queue - Join Popped
8:19:41:603|DEBUG| Transmitted Frame data
================================
000 20 9f aa ac 1f ac d7 bc
008 e5 aa 44 0d 7e ca 24 8a
010 dd

8:19:41:603|DEBUG| rx1Offset: 0 rx1Datarate: 10
8:19:41:604|DEBUG| Use JoinResponse Window Time
8:19:41:606|DEBUG| JSON tx: {
"txpk" : {
  "codr" : "4/5",
  "data" : "IJ+qrB+s17zlqkQNfsokit0",
  "datr" : "SF10BW500",
  "freq" : 927.5,
  "ipol" : true,
  "modu" : "LORA",
  "ncrc" : false,
  "powe" : 26,
  "rfch" : 0,
  "size" : 17,
  "tmst" : 44995444
}
}

Seems that everything worked right away and we’ve joined the gateway!

There are a few parameters we can verify in the gateway log above, which are marked in bold.

Next, let’s try the “small one” – RM7201.

The RM7201 uses same MCU as the RM7601, just the RF radio is  different, SX1272 instead of SX1276. For both the SX1276 and SX1272 data sheets, check the Semtech website: http://www.semtech.com/apps/product.php?pn=sx1272&x=0&y=0 http://www.semtech.com/wireless-rf/rf-transceivers/sx1276/ and http://www.semtech.com/apps/product.php?pn=sx1272&x=0&y=0.

As with RM7601, I expected simply changes in the config files, but unfortunately, it was not that easy . At the beginning, I’ve tried to use the same project – NodeSensor, but I quickly found out that I would have to port the SX1272 driver as this project does not include support for the SX1272. Porting the SX1272 driver should be easy as most likely it would involve just changing some header definitions. However, after looking deeper into Semtech code, I found another project which does have support for the SX1272, the Loramote project.

As the RM7201 uses a smaller header, my connector would not fit, so i soldered 4 wires (SWCLK, SWIO, VDD and GND) to the RM7201 module directly:

 Screen Shot 2015-12-21 at 4.22.42 PM

Change the board.h definition as follows:

/*!
* Board MCU pins definitions
*/

#define RADIO_RESET PB_10

#define RADIO_MOSI PA_7
#define RADIO_MISO PA_6
#define RADIO_SCLK PA_5
#define RADIO_NSS PA_4

#define RADIO_DIO_0 PB_11
#define RADIO_DIO_1 PC_13
#define RADIO_DIO_2 PB_9
#define RADIO_DIO_3 PB_4
#define RADIO_DIO_4 PB_3
#define RADIO_DIO_5 PA_15

#define RADIO_ANT_SWITCH_RX PA_0
#define RADIO_ANT_SWITCH_TX PA_1

#define OSC_LSE_IN PC_14
#define OSC_LSE_OUT PC_15

#define OSC_HSE_IN PH_0
#define OSC_HSE_OUT PH_1

#define USB_DM PA_11
#define USB_DP PA_12

Now use ssh to login to the gateway again and watch the log output:

root@mtcdt:~# tail -f /var/log/lora-network-server.log 

9:12:53:3|DEBUG| Received packet
================================
000 00 c0 ff ee 00 00 00 00
008 02 01 63 34 73 38 31 38
010 32 23 3c 52 a9 11 90

9:12:53:3|DEBUG| Rx on 902300000, rssi: -61 snr: 58
9:12:53:4|DEBUG| Received frame: type: Join Request
9:12:53:4|INFO| Received join request
9:12:53:4|DEBUG| BUFFER: 00c0ffee00000000020163347338313832233c
9:12:53:5|DEBUG| App EUI: 02.00.00.00.00.ee.ff.c0
9:12:53:5|DEBUG| Dev EUI: 32.38.31.38.73.34.63.01
9:12:53:5|DEBUG| Nonce: 00003c23
9:12:53:6|DEBUG| MIC is valid
9:12:53:6|DEBUG| Got appkey: 2b.7e.15.16.28.ae.d2.a6.ab.f7.15.88.09.cf.4f.3c
9:12:53:7|DEBUG| DEV NONCE: 3c23
9:12:53:7|DEBUG| APP NONCE: 2f529e
9:12:53:7|DEBUG| session keys: 99e47e148873a6e32ceff9a3eccd2233 96f44cb0d5c2a3900aaf20e9ef8f931b
9:12:53:8|TRACE| SQL query = SELECT address FROM nodes WHERE deveui = "3238313873346301"
9:12:53:9|INFO| Device found in DB, assigning address: 5
9:12:53:10|DEBUG| Update session keys
9:12:53:10|TRACE| SQL query = UPDATE nodes SET authenticationkey = "99e47e148873a6e32ceff9a3eccd2233", encryptionkey = "96f44cb0d5c2a3900aaf20e9ef8f931b" WHERE address = "00000005"
9:12:53:13|DEBUG| Set node active: 1
9:12:53:13|INFO| Queue join response 17 bytes
9:12:53:13|DEBUG| Set node active: 1
9:12:53:14|DEBUG| update bestGateway
9:12:53:14|DEBUG| Time: 3236312956
9:12:53:14|DEBUG| App Queue Length: 1
9:12:53:14|DEBUG| Rx Frame seq 0 snr 58
9:12:53:15|DEBUG| SpreadingFactorStore::Add
9:12:53:15|DEBUG| FindSF : snr : 58 100 -42
9:12:53:15|TRACE| SQL query = UPDATE nodes SET jointime = "2015-12-21T09:12:53Z" WHERE address = "00000005"
9:12:53:19|TRACE| SQL query = UPDATE packets SET port = 2, seqno = 0, gateway = "0080000000009f6c", time = "2015-12-21T09:12:53Z", microseconds = 308000, rssi = -61, channel = 0, lsnr_cB = 58, spread = 10, modulationbandwidth = 125, data = "0163347338313832233c" WHERE node = "00000005"
9:12:53:22|TRACE| SQL query = UPDATE nodes SET lastuppacketid = 1, lastmessagems = 35856598 WHERE address = "00000005"
9:12:53:25|TRACE| SQL query = UPDATE gateways SET lastuppacketid = 1 WHERE address = "0080000000009f6c"
9:12:53:28|DEBUG| getTimeOnAirMs dr: 10 bw: 2 pl: 8 sz: 16 toa: 82
9:12:53:28|INFO| Send Join Accept - EUI: 32:38:31:38:73:34:63:01 ADDR: 00000005
9:12:53:28|INFO| Schedule TX Time on air: 150 ms
9:12:53:36|DEBUG| Send MQTT message
9:12:53:37|DEBUG| UDP message: lora/32:38:31:38:73:34:63:01/joined
9:12:53:37|DEBUG| UDP port: 1784
9:12:53:39|TRACE| Published message: 6
9:12:53:446|TRACE| Parse downstream message 12 bytes
9:12:53:447|TRACE| Gateway 00:80:00:00:00:00:9f:6c seen IP address 127.0.0.1:33742
9:12:57:885|DEBUG| is frame ready?
9:12:57:886|DEBUG| App Queue Length: 1
9:12:57:888|DEBUG| BestGateway: 80000000009f6c
9:12:57:889|DEBUG| Start
9:12:57:891|INFO| Frame transmitted to 00:00:00:05 via GW (00:80:00:00:00:00:9f:6c Chan LC1 127.0.0.1:33742) Seq# 40
9:12:57:891|TRACE| SQL query = UPDATE nodes SET lastdownmsgseqno = 64 WHERE address = "00000005"
9:12:57:894|DEBUG| App Data Queue: 1 front size: 17 available: 242
9:12:57:894|DEBUG| check if front is join request 17 bytes
9:12:57:894|DEBUG| Start
9:12:57:895|TRACE| App Data Queue - Join Popped
9:12:57:895|DEBUG| Transmitted Frame data
================================
000 20 68 6f ed 76 ea 07 12
008 bd 79 15 dc 99 53 b3 4c
010 cf

9:12:57:896|DEBUG| rx1Offset: 0 rx1Datarate: 10
9:12:57:896|DEBUG| Use JoinResponse Window Time
9:12:57:898|DEBUG| JSON tx: {
"txpk" : {
  "codr" : "4/5",
  "data" : "IGhv7XbqBxK9eRXcmVOzTM8",
  "datr" : "SF10BW500",
  "freq" : 923.29999999999995,
  "ipol" : true,
  "modu" : "LORA",
  "ncrc" : false,
  "powe" : 26,
  "rfch" : 0,
  "size" : 17,
  "tmst" : 3241312956
}
}

and….I can confirm that RM7201 is also operational and registered with my LoRa Gateway.

Again, I have some reservations due to luck of any usable sample code from Dapu as well as a single hardware design for all regions.

You, should also confirm if all necessary approvals are actually available for your region.