I am a roaming journeyman, I roam from town to town,
And when I get a job of work I’m willing to sit down.
With my bundle on my shoulder, with my stick all in my hand,
And it’s round the country I will go, like a roaming journeyman.
Tom Willett – The Roving Journeyman
Spring is here, Morris Men are celebrating May Day and folk music is in the air, so you’ll forgive me if my mind turns to roaming…
…of course I mean roaming LoRaWAN devices – I’m a happily married man these days, haven’t you heard?!
The lovely people at the Digital Catapult are promoting LPWAN as an opportunity for enterprise in the UK, and have worked with Everynet to install a LoRaWAN network across London for people like us to experiment with. There are even rumours that it will be installed in cities and towns beyond the M25… those crazy kids!
Thingitude has been involved in the beta testing of Things Connected and one of the things I was keen to understand is how much work is involved in creating a roaming device. As you know, we have built a pretty good LoRaWAN network here in the guise of The Things Network Reading, but wouldn’t it be nice to take one of our devices from Reading to London and back, and get a connection on either Things Connected or The Things Network, depending on what was in range?
The Use Case I have in mind is the LoRaVAN burglar alarm – pun very much intended! My lovely big white van gets parked all over the place and I would like to be alerted if someone breaks into it, whether I am in Reading, London, Manchester or Amsterdam. Three of these great places are covered by The Things Network, but London is the anomaly.
I’ve broken the problem down into three parts – two of which I can tackle directly:
- Getting the device to join different networks
- Getting the application to accept data from different networks
- Getting the networks to pass data between them
Getting the device to join different networks
My device uses Microchip’s RN2483 LoRaWAN radio module, and so this post is written with that in mind. You may need to make changes if you are using another radio module.
Both networks are LoRaWAN so we know the protocol will be the same. I want my device to use over the air activation (OTAA) so I need to provide it with 3 bits of data:
- Device EUI – an 8 byte end device identifier. Not unique, but fairly unique!
- App EUI – an 8 byte identifier given to us when we register an application on the network server
- App Key – this 16 byte key is used to derive the session keys
It is easy enough to imagine some code that sets the right values depending on which network we are using:
# Subroutine to reset the RN2483 radio for TTN or TC def resetRadio(network): if network == "TTN": deveui="2A05502164xxxxxx" appeui="70B3D57EF0xxxxxx" appkey="3D6C7401664D4BD6C8AFFE914xxxxxx" elif network =="TC": deveui="295C9002B8xxxxxx" appeui="5E5B5A16F2xxxxxx" appkey="42853BC9EF2E3D578CF62360BCxxxxxx" print("Resetting to " + (network)) ...
So how do we tell which network is in range?
Ah, maybe the “mac get status” command will help us? It returns a hex code which, when converted to binary gives you the current status of the radio module. For example the least significant bit tells you whether it is joined to a network (1) or not (0):
However, it only tells you that the radio module *thinks* it is joined to a network. It doesn’t know that you’ve driven from Reading to London and are now out of range.
Grrr! We can’t tell what networks are in range unless we try to join a network and see if we succeed. But my friends at The Things Network tell me it is bad practice to join a network each time you want to send a message, because it uses up the limited bandwidth and airtime available. Hmmm…
An alternative approach is to send a message and see if it is delivered. If it is – happy days; if it isn’t then we can try joining the other network(s) we know about. If we can join one of those then we can resend the same message data but using the right keys for the network.
This approach feels like it would work, as long as we send confirmed and not unconfirmed messages, because only receipt of confirmed messages gets acknowledged.
The Microchip RN2483 radio module has a rather good command reference manual. It tells me I can send a message with:
mac_tx cnf <port> <message>
…and then I should get back an
"ok" followed shortly by
"mac_rx <port>" if the message has been received.
It is rather quiet if the message hasn’t been received, presumably because it retries over the next couple of minutes. Eventually it will send back a
"mac_err" to let me know.
This means I can use the receipt of a
"mac_err" to instruct the device to try joining another network, and if that works then I can send the message again. The code snippet below sits in a while loop:
print("Getting response..") tdata = readlineCR(port) response=tdata.strip() print(response) if response == "mac_tx_ok": print("UNCONFIRMED SUCCESS - message tx.") break elif response == "mac_rx 1": print("CONFIRMED SUCCESS - message tx and rx.") break elif response == "ok": print("Data Sent to TX buffer") time.sleep(1) elif response == "mac_err": print("UNSUCCESSFUL TRANSMISSION - will try joining again") networkJoined=joinFirstAvailableNetwork() if networkJoined=="None": print("UNSUCCESSFUL - No networks to join.") break else: print("Device reset. Sending message to: "+(networkJoined)) port.write("mac tx cnf 1 " + thisMsg + "\r\n" )
So this should work nicely, and it *nearly* does. Except I get different responses from The Things Network and Things Connected! the Things Network returns
"mac_rx 1" upon receipt of a message, but Things Connected is returning
"mac_tx_ok" upon receipt.
This is not a show-stopper because at least I know it got there! I’ll raise it as an inconsistency because I think it ought to return
"mac_rx 1" as per the Microchip manual.
Next time I’ll write about connecting the application end so it can receive data from both networks.
Now I need to get back to sneezing and defending my cider from wasps 🙂
UPDATE: 4 May 2017 – As of this morning the Things Connected server is now behaving the same as TTN, ie it is sending back
"mac_rx" to confirm receipt.