Frequency plan: Australia and New Zealand using LoPy

I wanted to post this information somewhere on TTN forum as accessible as possible to users of the AU915 frequency plan. If anyone has a better Topic area; please suggest.

For those who use Pycom’s LoPy (or Pycom’s Micropython fork on other microcontrollers) you will no doubt be happy at their recent firmware upgrade which takes the hassle out of selecting the regional LoRaWAN frequencies.
Or so I thought…
Unfortunately, you still need to restrict the frequencies in code. For those lucky enough to be programming in Micropython, the code below does the job.

# Initialize LoRa in LORAWAN mode.
lora = LoRa(mode=LoRa.LORAWAN)

# credentials

print("Joining LoRa")

# remove default channels
for i in range(0, 72):

# adding the Australian channels
print("add channels")
for i in range(8, 15):
lora.add_channel(i, frequency=915200000 + i * 200000, dr_min=0, dr_max=3)
lora.add_channel(65, frequency=917500000, dr_min=4, dr_max=4)

for i in range(0, 7):
lora.add_channel(i, frequency=923300000 + i * 600000, dr_min=0, dr_max=3)

# create an OTA authentication params
app_eui = binascii.unhexlify(APP_EUI.replace(' ',''))
app_key = binascii.unhexlify(APP_KEY.replace(' ',''))

# join a network using OTAA if not previously done
lora.join(activation=LoRa.OTAA, auth=(app_eui, app_key), timeout=0)

# wait until the module has joined the network
while not lora.has_joined():
1 Like

Very useful to a newcomer to TTN / LoPy in particular!

Re the channel adds, shouldn’t the range statements be as follows to get ch15 & ch7?

# adding the Australian channels
print("add channels")
for i in range(8, 16):
lora.add_channel(i, frequency=915200000 + i * 200000, dr_min=0, dr_max=3)
lora.add_channel(65, frequency=917500000, dr_min=4, dr_max=4)

for i in range(0, 8):
lora.add_channel(i, frequency=923300000 + i * 600000, dr_min=0, dr_max=3)

Also, should the dr_min/dr_max align to the following or should they be tailored by use-case?

AU ISM 915	
Ch#	| direc	| f/MHz	| BW/kHz | data rate
8	| up	| 916.8	| 125	| DR0 - DR3	
9	| up	| 917.0	| 125	| DR0 - DR3	
10	| up	| 917.2	| 125	| DR0 - DR3	
11	| up	| 917.4	| 125	| DR0 - DR3	
12	| up	| 917.6	| 125	| DR0 - DR3	
13	| up	| 917.8	| 125	| DR0 - DR3	
14	| up	| 918.0	| 125	| DR0 - DR3	
15	| up	| 918.2	| 125	| DR0 - DR3	
65	| up	| 917.5	| 500	| DR4	
0	| down	| 923.3	| 500	| DR8 - DR13
1	| down	| 923.9	| 500	| DR8 - DR13
2	| down	| 924.5	| 500	| DR8 - DR13
3	| down	| 925.1	| 500	| DR8 - DR13
4	| down	| 925.7	| 500	| DR8 - DR13
5	| down	| 926.3	| 500	| DR8 - DR13
6	| down	| 926.9	| 500	| DR8 - DR13
7	| down	| 927.5	| 500	| DR8 - DR13

Very much in the early stages of working out what is ‘standard’ / convention and what is a hard MUST to connect. Shame the pycom LoRa.AU915 doesn’t align with this. Does it make any sense to try to align pycom lib with this (even if a TTN subset like LoRa.AU915.TTN)?


I think you are right with the ranges. They should be range(0,8) for 0-7, and range(8,16) for 8-15.

I also think that there are other problems with the add channels snippet – I’m planning on raising a ticket and submitting a commit – but I just want to be sure first :slight_smile:

With the new region aware firmware, the downlink channels are not needed. Instead they are setup directly in the file RegionAU915.c. So putting them in the TRANSMIT channel plan just means that we might be trying to transmit on a channel that the gateway isn’t listening too. Or, at least, that’s my current thinking – it could definitely be wrong.

Also, I think there is an issue with the method RegionAU915ChannelManualAdd::RegionAU915.c. It checks to see that dr_min is ALWAYS 0, which is true for the 125kHz channels but not for channel 65. So adding channel 65 with min dr = 4 will currently fail.

There is also a mismatch with RegionAU915ChanMaskSet (it requires 20 125kHz channels to be setup) but as the LoPy firmware doesn’t support the two commands which use it, it shouldn’t affect us for the time being.

I’m in the process of trying a simpler channel setup where the 8 uplink 125kHz channels are in 0-7, and the one 500kHz channel is on channel 65. Of course to get the channel 65 setup requires the change in the
RegionAU915ChannelManualAdd() function first.

Please anyone point out holes in my reasoning! Else I’ll report on my tests and if they are successful I’ll raise a ticket and submit a pull request.

Kind Regards,

Very handy information. Does anything need to be put into the TTN gateway setup, or is just selecting AU915 as the frequency plan in the console enough? Have a device sending join requests on 917.0 MHz SF12 BW125 at 4.5 SNR and the gateway is sending join accepts at 923.3 MHz SF12 BW500.

I thought the join accept response used the same frequency and SF/BW as the join request? Seems unlikely message is getting through if the BW has been pushed to 500 when I am only get SNR of 4.5

Any ideas?



Hi Simon,

I’m using a Multitech Conduit for my gateway, and I used the script referred to in the TTN instructions for that gateway - using the AU915 region when prompted. Then looking in /var/config/lora/global_conf.json all of the frequencies that it listens too are the same frequencies that we set for transmission in the lopy. But if you have a different gateway, then I’m not sure how it needs to be setup.

As for the join accept, it uses the same channels for downstream as a normal receive, except with longer delays.

For the first receive window, in AU915, it uses the upstream stream channel modulo 8 – 917.0 is channel 9(0-based) so it should use the second (channel 1, 0-based) downstream channel. That’s 923.9 (assuming that my calculations hold up). That is meant to be sent at the same SF as what you transmitted.

923.3 MHz / BW500 / SF12, is the second receive channel (it is always the same) so that is compliant. So it seems that you didn’t get the accept in the first join/receive window, but got it in the second. I don’t know if the gateway has to send in both windows or if it can choose only the second.

I haven’t looked at OTAA much myself – my knowledge is just from the LoRaWAN 1.1 documents. So there could be holes in my understanding.


Finished my testing with patched firmware to allow channel 65 to have a non-zero DR and now I’ve got good communications on all 9 channels! In fact now the channels can be setup as per the LoRaWAN regional parameters list. This means:
Channels 8-15 with DR 0 to DR 5, and
Channel 65 with DR6 to DR 6.

So setting the socket option socket.SO_DR to 4, will now use one of channels 8-15. To use channel 65 you must set the option to 6

Even better, you don’t have to wait for the patch to get everything working. With the v1.17.3.b1firmware all of the channels are correctly set up. Instead of removing ALL channels, and re-adding them (which is currently broken in the last firmware), you can just remove the channels that aren’t support on the TTN and Multitech gateways.

I.e. (with object lora of type network.LoRa):

# leave channels 8-15 and 65
for index in range(0, 8):
   lora.remove_channel(index)  # remove 0-7
for index in range(16, 65):
   lora.remove_channel(index)  # remove 16-64
for index in range(66, 72):
  lora.remove_channel(index)   # remove 66-71

(Note – I saw someone else on this forum use this method)

Hello everyone

Greetings from Argentina.
I think I am facing the same issue as you. I had my scripts working fine when I was working in EU for months but now I moved to this side of the globe and therefore had to re configure my LoPy’s firmware.
My main issue right now is that the node never goes beyond the activation, it is always prompting:

Screen Shot 2020-12-17 at 12.37.11

My GW is a Dragino LG308 multichannel. Do you see anything wrong in the config?

Screen Shot 2020-12-17 at 12.40.02

Screen Shot 2020-12-17 at 12.39.46

You might try seeing if a join on an ordinary 125 KHz channel works.

It seems a bit odd that the join on SF8BW500 is resulting in an SF10BW125 reply from the network on what does not appear to be the RX2 setting, so maybe some unexpected case or bug server side is getting triggered.

See if it works with an SF7BW125 uplink channel…

Hello @cslorabox, thanks for your reply

You might try seeing if a join on an ordinary 125 KHz channel works.

Would you mind showing me a sketch to do that?
My code looks like

from network import LoRa
import socket
import time
import ubinascii
import machine
import pycom

adc = machine.ADC()

# create an OTAA authentication parameters
APP_EUI = ubinascii.unhexlify('bbbbbbb')
APP_KEY = ubinascii.unhexlify('aaaaaaaaa')

def enter_deepsleep(interval=1):
    print("Deep Sleeping for {0} minutes".format(interval))
    machine.deepsleep(interval * 60000)
    print("AWAKE!!! entering normal operation mode")

def connect_to_ttn(lora_object):
    """Receives a lora object and tries to join"""
    # join a network using OTAA (Over the Air Activation)
    lora_object.join(activation=LoRa.OTAA, auth=(APP_EUI, APP_KEY), timeout=0)
    # wait until the module has joined the network
    while not lora_object.has_joined():
        print('Not yet joined...')

def get_supercap_voltage():
    samples = []
    supercap_pin ='P13', attn=adc.ATTN_11DB)   #analog pin on P13
    for sample in range(20):
        val = supercap_pin()# read an analog value
    average = sum(samples)/len(samples)
    return average

def compress_analog_reading_payload(mediciones):
     payload = 0
     tribble_shifts = len(mediciones) - 1
     for medicion in mediciones:
         payload = payload | (medicion << (12 * tribble_shifts))
         tribble_shifts -=1

# Initialise LoRa in LORAWAN mode.
# Please pick the region that matches where you are using the device:
# United States = LoRa.US915
#lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.EU868)
lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.AU=915)
for index in range(0, 8): lora.remove_channel(index)
for index in range(16, 65): lora.remove_channel(index)
for index in range(66, 72): lora.remove_channel(index)

lora.nvram_restore() #if there is nothing to restore it will return a False

if not lora.has_joined():

# create a LoRa socket
s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)

# set the LoRaWAN data rate
s.setsockopt(socket.SOL_LORA, socket.SO_DR, 3)

# make the socket blocking
# (waits for the data to be sent and for the 2 receive windows to expire)

# send some data
while lora.has_joined():
    supercap_voltage = int(get_supercap_voltage())
    payload = compress_analog_reading_payload([1700, 1000, 2800, 300, supercap_voltage])
    payload_in_bytes = list(payload.to_bytes(8, 'big'))

# make the socket non-blocking
#(because if there's no data received it will block forever...)

# get any data received (if any...)
    data = s.recv(64)

    if data:##print(data)

Additionally I have tried removing channel 65 and now the same behaviour is seen on other frequencies when activating.
Screen Shot 2020-12-17 at 18.36.34

It seems like maybe your gateway isn’t correctly configured with TTN, eg, registered in a different region or pointing at the wrong server.

My guess would be it’s trying to push your AU915 uplink reports through the AS923 cases in the TTN server code:

  • your downlink frequency often matches the uplink, which is true in AS923 but not AU915
  • your downlink seems to prefer DR2 (SF10BW125) which is a sort of initial default in AS923, while in AU915 it should be the uplink spreading factor but at BW500
  • when downlink doesn’t match the uplink, it’s on the AS923 RX2 setting

Ok, so it seems like a firmware update on my LG308 did the job!
The code running on the LoPy4 is fine and I am now able to join successfully without retries.
Screen Shot 2020-12-18 at 12.37.32

Thanks everyone for all the valuable help.

No, that wouldn’t matter at all, except that maybe it forced re-registering or re-configuring.

The issue was not the gateway, but how it was registered or pointed at TTN.

Gateways themselves have no role at all in the decisionmaking that was going wrong here.

I did not remove the GW from my console nor changed the config since the first day.
I just downloaded the latest OpenWRT for this GW and that was all.
Maybe you are right, and forced re-registering/configuring.