Hi,
I'm trying to set up a direct peer-to-peer (P2P) LoRa communication, without using a LoRaWAN gateway, between two different modules:
- The transmitter is a Wio-E5 LE Mini from Seeed Studio, connected to sensors (ENS160 and BME280). It’s programmed in MicroPython using a Raspberry Pi Pico and Thonny IDE.
- The receiver is a LILYGO LoRa32 T3 V1.6.1 board, which should receive the LoRa data and then upload it to a server. For this board, I plan to upload the code using the Arduino IDE.
My goal is for the Wio-E5 to send raw sensor data directly to the LILYGO board via LoRa (not using LoRaWAN), and for the LILYGO to handle the data upload.
Below is my initial MicroPython code attempt for the Wio-E5 (transmitter):
from machine import Pin, UART, I2C
from time import sleep_ms
# Inițializare LED și GPIO
led = Pin('LED', Pin.OUT)
GPIO_22 = Pin(22, Pin.OUT)
GPIO_22.value(0)
# Adrese corecte verificate
BME280_ADDR = 0x77
ENS160_ADDR = 0x53
# Inițializare I2C
i2c = I2C(0, scl=Pin(9), sda=Pin(8), freq=100000)
# Inițializare UART pentru LoRa E5
uart1 = UART(1, baudrate=9600, tx=Pin(4), rx=Pin(5))
def init_bme280():
"""Inițializare și calibrare BME280"""
try:
# Reset
i2c.writeto_mem(BME280_ADDR, 0xE0, bytes([0xB6]))
sleep_ms(100)
# Citește calibrarea
cal_data = i2c.readfrom_mem(BME280_ADDR, 0x88, 24)
cal_T1 = cal_data[1] << 8 | cal_data[0]
cal_T2 = cal_data[3] << 8 | cal_data[2]
if cal_T2 > 32767:
cal_T2 -= 65536
cal_T3 = cal_data[5] << 8 | cal_data[4]
if cal_T3 > 32767:
cal_T3 -= 65536
# Configurare
i2c.writeto_mem(BME280_ADDR, 0xF2, bytes([0x01])) # humidity oversampling x1
i2c.writeto_mem(BME280_ADDR, 0xF4, bytes([0x27])) # temp/pressure oversampling x1, normal mode
return cal_T1, cal_T2, cal_T3
except Exception as e:
print(f"Eroare inițializare BME280: {e}")
return None
def read_bme280(calibration):
"""Citire și compensare date BME280"""
try:
if calibration is None:
return 20.0, 1013.25, 50.0
cal_T1, cal_T2, cal_T3 = calibration
# Citire date brute
data = i2c.readfrom_mem(BME280_ADDR, 0xF7, 8)
# Temperatura
temp_raw = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4)
var1 = ((((temp_raw >> 3) - (cal_T1 << 1))) * cal_T2) >> 11
var2 = (((((temp_raw >> 4) - cal_T1) * ((temp_raw >> 4) - cal_T1)) >> 12) * cal_T3) >> 14
t_fine = var1 + var2
temperature = ((t_fine * 5 + 128) >> 8) / 100
# Presiune și umiditate (simplificat)
pressure = (((data[0] << 16) | (data[1] << 8) | data[2]) >> 4) / 256.0
humidity = ((data[6] << 8) | data[7]) / 1024.0
return temperature, pressure, humidity
except Exception as e:
print(f"Eroare citire BME280: {e}")
return 20.0, 1013.25, 50.0
def read_ens160():
"""Citire date ENS160"""
try:
# Citire registri
aqi = i2c.readfrom_mem(ENS160_ADDR, 0x21, 1)[0]
tvoc_data = i2c.readfrom_mem(ENS160_ADDR, 0x22, 2)
eco2_data = i2c.readfrom_mem(ENS160_ADDR, 0x24, 2)
tvoc = (tvoc_data[1] << 8) | tvoc_data[0]
eco2 = (eco2_data[1] << 8) | eco2_data[0]
return aqi, tvoc, eco2
except Exception as e:
print(f"Eroare citire ENS160: {e}")
return 1, 0, 400
def send_at_command(cmd, timeout=1000): # Timeout mărit
"""Trimite comandă AT și așteaptă răspuns"""
print(f"Trimitere comandă: AT{cmd}")
uart1.write(f'AT{cmd}\r\n')
sleep_ms(timeout)
response = ''
while uart1.any():
response += uart1.read(1).decode('utf-8')
print(f"Răspuns: {response}")
return response
def configure_lora():
"""Configurează modulul LoRa E5 pentru EU868"""
print("Configurare LoRa...")
# Reset
send_at_command('+RESET')
sleep_ms(1000)
# Test conexiune
response = send_at_command('')
if '+AT: OK' not in response:
print("Eroare comunicare LoRa")
return False
# Configurare mod și parametri RF
send_at_command('+MODE=TEST')
send_at_command('+TEST=RFCFG,868100000,SF7,125,12,15,14')
# Verificare configurare
response = send_at_command('+TEST=RFCFG?')
return True
def send_data_packet(data):
"""Trimite pachet de date prin LoRa"""
print(f"Trimitere date: {data}")
response = send_at_command(f'+TEST=TXLRSTR,"{data}"', timeout=2000)
success = 'TX DONE' in response or 'TX OK' in response
print(f"Status transmisie: {'Succes' if success else 'Eșec'}")
return success
def main():
print("Inițializare sistem...")
# Inițializare BME280
bme280_cal = init_bme280()
# Configurare LoRa
if not configure_lora():
print("Eroare configurare LoRa!")
return
try:
# Citire senzori
temp, press, hum = read_bme280(bme280_cal)
print(f"BME280: T={temp:.1f}°C, P={press:.1f}hPa, H={hum:.1f}%")
aqi, tvoc, eco2 = read_ens160()
print(f"ENS160: AQI={aqi}, TVOC={tvoc}ppb, eCO2={eco2}ppm")
# Formatare date
sign = 1 if temp >= 0 else 2
temp_clean = abs(int(temp * 100))
press_clean = int(press * 100)
hum_clean = int(hum * 100)
# Construire pachet
data_packet = f"{sign}{temp_clean:05d}{press_clean:07d}{hum_clean:06d}{aqi}{tvoc:06d}{eco2:06d}"
print(f"Pachet de date format: {data_packet}")
# Trimitere date
led.on()
if send_data_packet(data_packet):
print("Date trimise cu succes!")
for _ in range(3):
led.off()
sleep_ms(200)
led.on()
sleep_ms(200)
else:
print("Eroare trimitere date!")
for _ in range(5):
led.off()
sleep_ms(100)
led.on()
sleep_ms(100)
except Exception as e:
print(f"Eroare generală: {e}")
led.on()
finally:
print("Activare Deep Sleep")
led.off()
sleep_ms(2000)
GPIO_22.value(1)
if __name__ == "__main__":
main()
Could anyone guide me on:
- How to configure both boards for P2P communication (modulation settings, frequency, etc.)?
- How to make sure they are compatible in raw LoRa mode?
- Any example code or documentation for the LilyGO side that supports receiving raw LoRa messages?
Thanks in advance!



