LoRa-MAC Nano-Gateway

Last updated last month

This example allows a raw LoRa connection between two LoPys (nodes) to a single LoPy acting as a Nano-Gateway.

For more information and discussions about this code, see this forum post.

Gateway Code

import socket
import struct
from network import LoRa
# A basic package header, B: 1 byte for the deviceId, B: 1 byte for the pkg size, %ds: Formatted string for string
_LORA_PKG_FORMAT = "!BB%ds"
# A basic ack package, B: 1 byte for the deviceId, B: 1 byte for the pkg size, B: 1 byte for the Ok (200) or error messages
_LORA_PKG_ACK_FORMAT = "BBB"
# Open a LoRa Socket, use rx_iq to avoid listening to our own messages
# Please pick the region that matches where you are using the device:
# Asia = LoRa.AS923
# Australia = LoRa.AU915
# Europe = LoRa.EU868
# United States = LoRa.US915
lora = LoRa(mode=LoRa.LORA, rx_iq=True, region=LoRa.EU868)
lora_sock = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
lora_sock.setblocking(False)
while (True):
recv_pkg = lora_sock.recv(512)
if (len(recv_pkg) > 2):
recv_pkg_len = recv_pkg[1]
device_id, pkg_len, msg = struct.unpack(_LORA_PKG_FORMAT % recv_pkg_len, recv_pkg)
# If the uart = machine.UART(0, 115200) and os.dupterm(uart) are set in the boot.py this print should appear in the serial port
print('Device: %d - Pkg: %s' % (device_id, msg))
ack_pkg = struct.pack(_LORA_PKG_ACK_FORMAT, device_id, 1, 200)
lora_sock.send(ack_pkg)

The _LORA_PKG_FORMAT is used as a method of identifying the different devices within a network. The _LORA_PKG_ACK_FORMAT is a simple ack package as a response to the nodes package.

Node

import os
import socket
import time
import struct
from network import LoRa
# A basic package header, B: 1 byte for the deviceId, B: 1 byte for the pkg size
_LORA_PKG_FORMAT = "BB%ds"
_LORA_PKG_ACK_FORMAT = "BBB"
DEVICE_ID = 0x01
# Open a Lora Socket, use tx_iq to avoid listening to our own messages
# Please pick the region that matches where you are using the device:
# Asia = LoRa.AS923
# Australia = LoRa.AU915
# Europe = LoRa.EU868
# United States = LoRa.US915
lora = LoRa(mode=LoRa.LORA, tx_iq=True, region=LoRa.EU868)
lora_sock = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
lora_sock.setblocking(False)
while(True):
# Package send containing a simple string
msg = "Device 1 Here"
pkg = struct.pack(_LORA_PKG_FORMAT % len(msg), DEVICE_ID, len(msg), msg)
lora_sock.send(pkg)
# Wait for the response from the gateway. NOTE: For this demo the device does an infinite loop for while waiting the response. Introduce a max_time_waiting for you application
waiting_ack = True
while(waiting_ack):
recv_ack = lora_sock.recv(256)
if (len(recv_ack) > 0):
device_id, pkg_len, ack = struct.unpack(_LORA_PKG_ACK_FORMAT, recv_ack)
if (device_id == DEVICE_ID):
if (ack == 200):
waiting_ack = False
# If the uart = machine.UART(0, 115200) and os.dupterm(uart) are set in the boot.py this print should appear in the serial port
print("ACK")
else:
waiting_ack = False
# If the uart = machine.UART(0, 115200) and os.dupterm(uart) are set in the boot.py this print should appear in the serial port
print("Message Failed")
time.sleep(5)

The node is always sending packages and waiting for the ack from the gateway.

To adapt this code to user specific needs:

  • Put a max waiting time for the ack to arrive and resend the package or mark it as invalid

  • Increase the package size changing the _LORA_PKG_FORMAT to BH%ds. The H will allow the keeping of 2 bytes for size (for more information about struct format)

  • Reduce the package size with bitwise manipulation

  • Reduce the message size (for this demo, a string) to something more useful for specific development