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.png

    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.png

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

    Screen Shot 2020-03-03 at 6.21.29 pm.png

    Screen Shot 2020-03-03 at 6.22.30 pm.png

    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.png

    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

    Could this be that

    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
    
    



  • @xavier where are you running that encoder? I'm trying to do something similar with node-red.



  • @xavier

    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;
    }
    

Log in to reply
 

Pycom on Twitter