buihuy1203 / A-Complete-LoRaWAN-Image-Transfer

A project that I made on myself, using library to transfer image from one node to gateway.
2 stars 0 forks source link

MQTT Publish #1

Closed hieu0902 closed 4 months ago

hieu0902 commented 4 months ago

import sys import time import json from SX127x.LoRa import import LoRaWAN from LoRaWAN.MHDR import MHDR from SX127x.board_config import BOARD from SX127x.constants import from MergeImage import * from paho.mqtt import client as mqtt_client import logging import random import threading import queue

BOARD.setup()

BROKER = 'broker.emqx.io' PORT = 8883 TOPIC1 = "SANSLAB/gateway/send-data" TOPIC2 = "SANSLAB/user/send-command" TOPIC3 = "SANSLAB/disconnected/server"

CLIENT_ID = f'gateway-{random.randint(0, 1000)}' USERNAME = 'hieu' PASSWORD = '1'

FIRST_RECONNECT_DELAY = 1 RECONNECT_RATE = 2 MAX_RECONNECT_COUNT = 12 MAX_RECONNECT_DELAY = 60

FLAG_EXIT = False global_data = {}

Create a queue to synchronize LoRa and MQTT operations

lora_message_queue = queue.Queue()

MQTT client setup and callback functions

def on_connect(client, userdata, flags, rc): if rc == 0: print("Connected to MQTT Broker!") client.subscribe(TOPIC2, qos=2) client.subscribe(TOPIC3) else: print(f'Failed to connect, return code {rc}')

def on_disconnect(client, userdata, rc): logging.info("Disconnected with result code: %s", rc) reconnect_count, reconnect_delay = 0, FIRST_RECONNECT_DELAY while reconnect_count < MAX_RECONNECT_COUNT: logging.info("Reconnecting in %d seconds...", reconnect_delay) time.sleep(reconnect_delay) try: client.reconnect() logging.info("Reconnected successfully!") return except Exception as err: logging.error("%s. Reconnect failed. Retrying...", err)

    reconnect_delay *= RECONNECT_RATE
    reconnect_delay = min(reconnect_delay, MAX_RECONNECT_DELAY)
    reconnect_count += 1
logging.info("Reconnect failed after %s attempts. Exiting...", reconnect_count)
global FLAG_EXIT
FLAG_EXIT = True

def on_message(client, userdata, msg): print(f'Received {msg.payload.decode()} from {msg.topic} topic')

def connect_mqtt(): client = mqtt_client.Client(mqtt_client.CallbackAPIVersion.VERSION1, CLIENT_ID) client.tls_set(ca_certs='./broker.emqx.io-ca.crt') client.username_pw_set(USERNAME, PASSWORD) client.on_connect = on_connect client.on_message = on_message client.acknowledge = 1 client.will_set("SANSLAB/disconnected/gateway", payload="Gateway suddenly disconnected...", qos=1, retain=False) client.connect(BROKER, PORT, keepalive=120) client.on_disconnect = on_disconnect return client

def publish(client): while not FLAG_EXIT: if not client.is_connected(): logging.error("publish: MQTT client is not connected!") time.sleep(1) continue if not lora_message_queue.empty(): msg = lora_message_queue.get() if msg: msg_json = json.dumps(msg) result = client.publish(TOPIC1, msg_json, qos=2) status = result[0] if status == 0: print(f'Send {msg_json} to topic {TOPIC1}') else: print(f'Failed to send message to topic {TOPIC1}') time.sleep(1)

class LoRaGW(LoRa): def init(self, devaddr=[], nwkey=[], appkey=[], verbose=False): super(LoRaGW, self).init(verbose) self.devaddr = devaddr self.nwkey = nwkey self.appkey = appkey self.set_mode(MODE.SLEEP) self.set_dio_mapping([0, 0, 0, 0, 0, 0]) self.receive_frame = 0 self.image_frame = []

def on_tx_done(self):
    print("TxDone")
    self.set_dio_mapping([0, 0, 0, 0, 0, 0])
    self.set_mode(MODE.STDBY)
    self.reset_ptr_rx()
    self.set_mode(MODE.RXCONT)
    self.clear_irq_flags(RxDone=1)
    BOARD.led_off()

def on_rx_done(self):
    print("RxDone")
    self.clear_irq_flags(RxDone=1)
    lorawan = LoRaWAN.new(nwskey, appskey)
    payload = self.read_payload(nocheck=True)
    lorawan.read(payload)
    frame_number = int(''.join(f'{byte:02x}' for byte in (lorawan.get_mac_payload().get_fhdr().get_fcnt()[::-1])), 16)
    print("Payload: ", lorawan.get_payload())
    print("Mac Version: ", lorawan.get_mhdr().get_mversion())
    print("Mac Type: ", lorawan.get_mhdr().get_mtype())
    print("Mic: ", lorawan.get_mic())
    print("Compute mic: ", lorawan.compute_mic())
    print("Check mic: ", lorawan.valid_mic())
    print("Dev Addr", lorawan.get_devaddr())
    print("Frame Number: ", frame_number)
    print("Data: ")
    data_payload = "".join(list(map(chr, lorawan.get_payload())))
    print(data_payload)
    time.sleep(1)
    self.reset_ptr_tx()
    if payload is None:
        self.set_mode(MODE.SLEEP)
        self.set_dio_mapping([1, 0, 0, 0, 0, 0])  # TX
        time.sleep(.5)
        lora.set_pa_config(pa_select=1)
        self.set_mode(MODE.STDBY)
        time.sleep(.5)
        print("Send ACK")
        lorawan.create(MHDR.UNCONF_DATA_UP, {'devaddr': devaddr, 'fcnt': 0, 'data': list(map(ord, '0'))})
        self.write_payload(lorawan.to_raw())
        self.set_mode(MODE.TX)
        print("Cannot Fetch Data")
    else:
        if data_payload == 'End Of Data':
            with open('/home/huymb/Desktop/receivefile/result.jpeg', 'wb') as f:
                f.write(hex_to_image(list_to_hex(self.image_frame)))
            print("Save Image")
        else:
            self.image_frame.append(data_payload)
            global_data["data"] = data_payload
            print("Update Frame")
        lora_message_queue.put(global_data)
        lorawan.create(MHDR.UNCONF_DATA_UP, {'devaddr': devaddr, 'fcnt': 0, 'data': list(map(ord, 'OK'))})
        self.write_payload(lorawan.to_raw())
        print("Save Data Successful")
        self.receive_frame += 1
        self.set_mode(MODE.TX)

def start(self):
    self.reset_ptr_rx()
    self.set_mode(MODE.RXCONT)
    while not FLAG_EXIT:
        BOARD.led_on()
        time.sleep(1)
        rssi_value = self.get_rssi_value()
        status = self.get_modem_status()
        sys.stdout.flush()
        sys.stdout.write("\r%d %d %d" % (rssi_value, status['rx_ongoing'], status['modem_clear']))

Setup LoRaGW instance

devaddr = [0xFF, 0xFF, 0xFF, 0x00] nwskey = [0xC3, 0x24, 0x64, 0x98, 0xDE, 0x56, 0x5D, 0x8C, 0x55, 0x88, 0x7C, 0x05, 0x86, 0xF9, 0x82, 0x26] appskey = [0x15, 0xF6, 0xF4, 0xD4, 0x2A, 0x95, 0xB0, 0x97, 0x53, 0x27, 0xB7, 0xC1, 0x45, 0x6E, 0xC5, 0x45] lora = LoRaGW(devaddr, nwskey, appskey)

lora.set_mode(MODE.SLEEP) lora.set_dio_mapping([0, 0, 0, 0, 0, 0]) lora.set_freq(915) lora.set_pa_config(pa_select=1) lora.set_spreading_factor(7) lora.set_pa_config(max_power=0x0F, output_power=0x0E) lora.set_sync_word(0x63) lora.set_rx_crc(True) lora.set_bw(BW.BW125) lora.set_coding_rate(CODING_RATE.CR4_5) lora.set_preamble(😎 print(lora) lora.start()

Define the main threads for LoRa and MQTT

def run_mqtt(client): logging.basicConfig(format='%(asctime)s - %(levelname)s: %(message)s', level=logging.DEBUG) client.loop_start() time.sleep(1) if client.is_connected(): publish(client) else: client.loop_stop()

def run_lora(lora_instance): lora_instance.start()

Main function to initiate threads

def main(): client = connect_mqtt() mqtt_thread = threading.Thread(target=run_mqtt, args=(client,)) lora_thread = threading.Thread(target=run_lora, args=(lora,))

mqtt_thread.start()
lora_thread.start()

mqtt_thread.join()
lora_thread.join()

if name == "main": main() `