LoPy ABP Example


So after a lot of de-compiling i found the way to do ABP. Here by example code:

lora = LoRa(mode=LoRa.LORAWAN, sf=7, tx_power=14)

create an OTAA authentication tuple (NWSkey, AppSKey, DevAddr)
auth = (bytes([0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX]), bytes([0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX]), 0x69128CD3 )

lora.join(activation=LoRa.ABP, auth=auth, timeout=0)

while not lora.has_joined():
print(‘Trying to join LoRa network’)
print(‘Joined LoRa Network’)

s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)

while True:
print(‘Sending Packet’)
s.send(‘Hello from the LoPy’)
print(‘Done sending’)

I dont think i need to explain the 16 byte keys, but the devAddr is a decimal address for your addresses. You can use the hex in 0xDevAddr or 1762823379 as the int of that using a calculator, but make sure you padd the 0’s if a hex did not yield a 8 bit value.

example : 69128CD3 = 0x69, 0x12, 0x8C, 0xD3

0x69 = 1101001 -> 01101001 (pad 1 zero)
0x12 = 10010 -> 00010010 (pad 3 zeros)
0x8C = 10001100
0xD3 = 11010011

Combine it all:


convert that to decimal should result it 1762823379, this is the INT you will need to use. Using the Bytes() method will just result in a error that it cannot be converted into a INT, so this way i am bypassing this problem (assuming bug here)

Now that said, the code will just continue looping and sending packets, but for some reason even when explicitly defining SF7 it will still be SF12 in addition it only sends out a single packet and then the radio just ‘dies’ and with dies i mean its no longer responding until you do a HARD reset. With a soft reset and running the code again it will just hang on lora.join

LoPy OTAA Example
LoPy: micro-python LoRaWAN nano gateway board with WiFi/BLE

Great! Thx

Can't we just use an integer in hex representation like:

>>> dev = 0x69128CD3
>>> dev


lol i was walking thru it all to make sure i had the right ID's but your right, you can hex2int it directly

of just add 0x69128CD3 as the dev addr, i just tested it an it works

(Hylke Visser) #4

Great work, @kruisdraad! Maybe nice to write this down in a Labs story:




The radio doesn't actually die, it just take ages to complete the sending of some packets. I guess that this happens when the Gateway is not able to listen on all the channels (like the Multi-Tech conduit):


If you wait a minute or two, the radio will respond again. Obviously this is an issue, we'll analyze it provide a solution for the next release.



once the LoPy actually works, perhaps ... at this moment i have loads of negative feedback on this :frowning:


@danicampora Well first off waiting 1 or 2 minutes doesnt really matter since its forced on SF12 and even calling the methods to set SF7 its not accepted. Also its unconfirmed data up (at least the packets that i've seen) so why would a gateway even bother? I use a IMST 8 channel gateway, which listens to all channels and i am seeing 'round robin' packets being receivfed on several channels.

Does the LoPy send out on 64 channels? If so i reallly really really hope you will make this configurable. I have no idea exactly but i was under the impression the default channel was 1-3 and extended 4-8.

If i load the program and reboot after every transmit, it will just work. Sending any other packet (e.g. counter 2 and up) simply will not work even with i introduce a sleep of 1 hour (!)

secondly the radio (or better the socket) will not respond anymore. When using the blocking method (aka returns / continues when completed) then it will hang forever. Using the non-blocking method i can actually keep sending data into the socket but nothing happens.

And i really mean HANG even after doing a soft-reset it still hangs, and when running the join it would hang again at the Lora.Join command (not even at TX). So that socket will not respond until a power reset has been issued.

Also there is no 'radio reply', i sooooo wish the serial was avaiable to the radio and getting OK replies back.

Then again, officially there are no docs on this, so who says i am doing this right at all ...


In addition i used my SDR to check the radio, its not transmitting anything on other channels ...

while writing this i think perhaps the socket thinks its confirmed and waits for a reply that never comes because its unconfirmed?


@kruisdraad thanks for the detailed reply. You are right, it's not because the Gateway is not replying as even with all messages sent as unconfirmed this happens. I'm currently debugging the issue, I'll report back soon.


OK, I know the root cause now. It's because of the ETSI duty cycle limitations. This is what happens:

  1. At the moment only Data rate 0 is used.
  2. At the moment there are only 2 active sub-bands on the 868 band.
  3. The 2 sub bands enabled have the 1% duty cycle limitation.

So, sending 2 short packets works fine, but the third one waits until the delay to comply with the duty cycle limitation expires (which depends on the size of the packet sent before and the data rate used, and it's always 0 at the moment). In my case with a 6 byte packet, I have to wait ~2 minutes between transmissions.

Here's what I propose:

  1. Make the socket raise an exception if sending is not possible due to the duty cycle limitation.
  2. Add an option to set the data rate (using socket.setsockopt()).
  3. Add an option to enable the desired channels and their data rate ranges (this will be in the LoRa class).

Views? All suggestions are welcome.

I understand the frustration about the LoPy software being incomplete and buggy, but we are working hard to fix all this ASAP.


(Gonzalo Casas) #11

Thanks @danicampora, for all the hard work you're putting to get the LoPy right! And kudos for being very transparent about the progress all along the way.

Your proposals make sense to me, but probably someone with deeper knowledge of the standard should chime in.. /cc @Thomas

About the enabled sub bands, I might be wrong, but I was under the impression that only 1 sub band is active (at least on the TTN frequency plan).



@danicampora - I am sorry, but i dont think thats true

simple tests (all sending 1 byte):

1: i have the node running in a loop sending messages without blocking, it sends out msg 1, but after 4 hours (!) still the count is 1 at any gateway, and the SDR confirms nothing is send
2: same loop but with a 30 minute (!) sleep between each transmit, more then enough to be in the duty cycle, but still never a message 2 after 2,5 hours (5 cycles) of waiting
3: same loop again with 60 minutes sleep, same deal

so i don't really think its a duty cycle thing, but rather something with the socket/API not handling the radio correctly, but hey thats just a guess since the stuff aint open source :wink:

Now to the proposes:

@1 yeah, i would suggest passing allong the radio reply 1:1, it not only makes senses and everyone knows those messages since their working with the radio. Dont know the exact error, but some libs say 'no free channel' or 'busy'. e.g. lora.tx returns OK, if not OK, throw it as a catchable error. You could also go simple with a true/false which makes it easier to code arround (or do both, lora.tx true/false, lora.debugtx return radio reply)

@2 Not only data rate, but only SF, bandwidth and coding should be settable. I found the methods and when i call them the code/radio seems to accept them, however when trying to send the packet (not even the first) is ever send. I think there is some kind if init() failure there (which does not throw an exception)

@3 selecting a channel (or a group) would be handy. e.g. a sane default should be 1-3 from your end, which i've seen most nodes use. Thereafter most people would change that to either a single channel or 8 channel, since most of the GW's use these.

@4 It feels as if their is something blocking. so i'd suggest options to get a radio status (e.g. dump all the set values/settings and a radio status) and a option to reset the radio itself (prolly in the INIT() already, but calling init, again just blocks)

@frustration about the LoPy software being incomplete and buggy
I am sorry to say, but simple stuff like documentation and mostly a copy/paste what you used to test ABP with is not that much work. Yeah there is no guide, but you know most people can handle some coding, and not only that people might post updates/ideas for changes. (i couldnt find one) but if the docs where a github repo people might submit changes or stuff in the /examples/ dir.

Sending out and update stating 'we fixed ABP' and not even updating a docs/example is really bad. And now you have someone that figured it out and found problems, issues others would be able to have reported if the example was posted (e.g. in the forum of TTN or your own, where active topics are there).

Finally being active only gets you thus far, regurlar updates and suchs are a real pre, however some examples are flatout wrong, and not going open source set a few bad people. I was really really waiting on the LoPy and it looked really great, but its starting to be the first node that doesnt really do much. I was really hoping to try the GW options, but looking at the current status i wont think its going to be working this year and as such i rather have waited a month more ...

so thats just my ranting :wink: i really hope stuff gets back on track and make this the great product it could be!

(Arjan) #13

Small chance, but just in case the Python code suffers the same problem: in LMiC people have seen that truly sleeping confuses the library;


Great work can you edit the startpost with the dev adr 0x69128CD3
@kruisdraad ?


updated first post


I always get:

>>> lora.join(activation=LoRa.ABP, auth=auth, timeout=0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: overflow converting long int to machine word

wether I use 0x9A662B6B or 2590387051


What does your auth tuple look like? And what firmware version are you using?
Note that Pycom posted an example for ABP on their website


Here's my code:

# main.py -- put your code here!
from network import LoRa
import socket

# Initialize LoRa in LORAWAN mode.
lora = LoRa(mode=LoRa.LORAWAN, sf=7, tx_power=14)

# create an ABP authentication tuple (NwkSKey, AppSKey, DevAddr)
auth = (bytes([0x58, 0xB9, 0x47, 0x74, 0xAF, 0x6F, 0x97, 0x43, 0xEA, 0x0C, 0x58, 0xC5, 0x12, 0xA1, 0xDE, 0x68]), bytes([0x32, 0x83, 0xB1, 0xD7, 0x99, 0x05, 0x83, 0x29, 0x8F, 0xE5, 0xE4, 0xE8, 0x1A, 0xE7, 0x0E, 0xD6]), 0x9A662B6B)

# join a network using ABP (Activation By Personalization)
lora.join(activation=LoRa.ABP, auth=auth, timeout=0)

while not lora.has_joined():
	print('Trying to join LoRa network')
print('Joined LoRa Network')

s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)

while True:
	print('Sending Packet')
	s.send('Hello from the LoPy')
	print('Done sending')

In their example they use 0x01 as DevAddr... that won't work i guess?



until they fixed the API's sending more the n1 packet still fails ... no further updates from pycom so no idea when a fix is provided


no, ofc not you will needto add the DevAddr assign to you by TTN. Adding the HEX to valid int works for me ... IF you run the latest firmware, older firmwares will not work.