LoPy4 - TTN Lora - Uplink OK - Downlink not working

Hi from Australia,

Project --> IoT with LoRaWAN, Pycom, The Things Network & Node-RED
https://core-electronics.com.au/tutorials/iot-with-lorawan-pycom-the-things-network-and-node-red.html

Lorawan gateway at home --> Sentrius Gateway

Device --> LoPy4 + PyTrack
Firmware version --> 1.20.2.rc3

I searched on different forum on the different ways to join in OTAA mode in adding the Australian channels and most of the configurations were working.

Basically I can join the gateway
I can send data from the LoPy, it is received by the Application and I can received it in Node-RED.
So far, so good.

Screen Shot 2020-03-03 at 6.25.33 pm

Data received from the LoPy - Application Traffic
The LoPy is sending “water_level: 0”
and in response, Node-RED is transmitting --> “pump_running: 1”

Screen Shot 2020-03-03 at 6.20.25 pm

Data received from the LoPy - Gateway Traffic
Screen Shot 2020-03-03 at 6.21.02 pm

Screen Shot 2020-03-03 at 6.21.29 pm

Screen Shot 2020-03-03 at 6.22.30 pm

The Application receives the data sent by Node-RED but the LoPy doesn’t received it from the gateway.
I tried different ports but no luck.

The Node-RED code is pretty simple:
Screen Shot 2020-03-03 at 6.50.45 pm

I don’t know if this is a problem with how I join the network? (Channels created, …)
or maybe the is something in the LoPy code that is not correct

Would anyone have an idea of what am I doing wrong?

Could it be that the JSON sent from node-RED is not correct?
See --> link

I looked there without any luck:
–> link
–> link
–> link
–> link
–> link

Thank you for your help.

Xavier

CODE LOPY4

from network import LoRa
import struct
import socket
import pycom
import time
import binascii
import utime

LORA_FREQUENCY = 916800000
LORA_GW_DR = "SF7BW125" # DR_5
LORA_NODE_DR = 5

COLOUR_WHITE = 0xFFFFFF
COLOUR_BLACK = 0x000000
COLOUR_RED   = 0xFF0000
COLOUR_GREEN = 0x00FF00
COLOUR_BLUE  = 0x0000FF

pycom.heartbeat(False)
pycom.rgbled(COLOUR_BLACK)

print("****** Farmer App OTAA *******")

# lora config
lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.AU915)
# access info from ttn console (note; we just need the app id & app key)
dev_eui = binascii.unhexlify('WWWWWWWWWWWW') # these settings can be found from TTN
app_eui = binascii.unhexlify('ZZZZZZZZZZZZZZZZZ')
app_key = binascii.unhexlify('XXXXXXXXXXXXXXXXXXXXXXXXXXXX')

for i in range(0, 72):
    lora.remove_channel(i)

# 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)

# attempt join - continues attempts background every 15 seconds
lora.join(activation=LoRa.OTAA, auth=(dev_eui, app_eui, app_key), timeout=0)

# wait for a connection to be established
print('Waiting for LoRaWAN network connection...')
while not lora.has_joined():
    utime.sleep(1)
    if utime.time() > 15:
        print("possible timeout or collision")
        machine.reset()
    pass

print('Network joined!')

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

s.setsockopt(socket.SOL_LORA, socket.SO_DR, LORA_NODE_DR)

s.setblocking(False)

pump_running = False
water_level = 0
empty_level = 0
full_level = 5

def check_downlink_messages():

    global pump_running # We need to tell Python to use the variable
                        # defined outside this function

    downlink_message, port = s.recvfrom(256) # See if a downlink message arrived
    #print(downlink_message)
    #print(port)

    if not downlink_message: # If there was no message, get out now
        return

    print("Downlink message received!")

    if downlink_message[0]: # The first byte is non-zero
        print("Starting the pump")
        pump_running = True
    else:
        print("Stopping the pump")
        pump_running = False

def send_level():

    print('Sending water level: {}'.format(water_level))
    uplink_message = bytes([water_level])
    s.send(uplink_message)

def adjust_water_level():

    global water_level  # We need to tell Python to use the variable
                        # defined outside this function

    if pump_running:
        if water_level < full_level:    # Can't be overfilled
            water_level += 1            # Water level rises
    else:
        if water_level > empty_level:   # Can't be less than empty
            water_level -= 1            # Water level drops

while(True):

    # Code at the indent happens every 10 seconds

    adjust_water_level()

    send_level()

    for i in range (10):        # 10 x 1 second delay

        # Code at this indent happens every second
        check_downlink_messages()

        if pump_running:    # At any time the pump might be stopped
            pycom.rgbled(COLOUR_GREEN)
        else:
            pycom.rgbled(COLOUR_RED)

        time.sleep(1)           # 1 second delay


Hi all,

Problem solved, I didn’t have the Encoder setup properly:

function Encoder(object, port) {

  var bytes = [];

  if (object.pump_running === 0 || object.pump_running === 1) {
    bytes[0] = object.pump_running ? 1 : 0;
  }

  // There is no separate converter and validator function for this direction. Return an empty array to drop the message.
  // https://www.thethingsnetwork.org/docs/devices/uno/quick-start.html
  return bytes;
}
1 Like