#!/usr/bin/python3 """ A bridge between APRS messaging and MQTT, designed to control my lora_aprs_node_pico (C)2022-2023 M.T. Konstapel https://meezenest.nl/mees This file is part of aprs-mqtt-bridge. aprs-mqtt-bridge is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. aprs-mqtt-bridge is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with aprs-mqtt-bridge. If not, see . """ import sys import random import time import os from pathlib import Path import yaml from yaml.loader import SafeLoader from paho.mqtt import client as mqtt_client import csv configuration_file = "aprs_telemetry_to_mqtt.yml" # This is where we keep our settings class mqtt_settings: #broker #topic_root #port #client_id #transmit_rate #retry #topics #poll state = 'ready' aprs_state = 'idle' pass mqtt = mqtt_settings() def connect_mqtt(): def on_connect(client, userdata, flags, rc): if rc == 0: print("Connected to MQTT Broker!") else: print("Failed to connect, return code %d\n", rc) # Set Connecting Client ID client = mqtt_client.Client(mqtt.client_id) #client.username_pw_set(username, password) client.on_connect = on_connect client.connect(mqtt.broker, mqtt.port) return client def publish(client, topic, message): result = client.publish(topic, message) status = result[0] if status == 0: print(f"Send `{message}` to topic `{topic}`") else: print(f"Failed to send message to topic {topic}") def subscribe(client: mqtt_client, topic): def on_message(client, userdata, message): received_payload = message.payload.decode() received_topic = Path(message.topic).name print(f"Received `{received_payload}` from `{message.topic}` topic") # Find corresponding topic in configuration-file and send this to the next function for topics in mqtt.topics: if received_topic == topics['name']: #print ('Found topic in list!') #print (topics) process_message(topics, received_payload) break # print(topic['name']) # print(topic['command']) client.subscribe(topic) client.on_message = on_message def read_config(): try: with open(configuration_file) as f: cfg = yaml.load(f, Loader=SafeLoader) mqtt.topics = cfg['topics'] #print(mqtt.topics) #for topic in mqtt.topics: # print(topic['name']) # print(topic['command']) except: print ("Configuration file ./" + configuration_file + " not found.") sys.exit(1) try: mqtt.broker = cfg['global']['broker'] except: print ("Error in configuration file: no broker defined.") sys.exit(1) try: mqtt.port = cfg['global']['port'] except: print ("Error in configuration file: no port defined.") sys.exit(1) try: mqtt.topic_root = cfg['global']['topic_root'] except: print ("Error in configuration file: no topic defined.") sys.exit(1) try: mqtt.poll_rate = cfg['global']['poll_rate'] except: print ("Error in configuration file: no poll_rate defined.") sys.exit(1) mqtt.client_id = f'{mqtt.topic_root}-{random.randint(0, 1000)}' print (mqtt.broker) print (mqtt.topic_root) print (mqtt.port) print (mqtt.client_id) # Loop through all topics and activate them def add_subscribtions_from_configfile(client): for topics in mqtt.topics: current_topic = mqtt.topic_root + '/' + topics['name'] subscribe(client,current_topic) print('Topic ' + topics['name'] + ' added') # Loop through all topics and send telemtry to broker def send_telemetry_to_broker(client): for topics in mqtt.topics: #for topics in topics.description: #print('Description ' + topics['description'] + ' added') #print(topics['description']) # Loop through descriptions and send values from telemtry file along with it #for descr in topics['description']: for index, descr in enumerate(topics['description'], start=0): #print(descr) # Read telemetry data with open(topics['telemetry_file'], newline='') as csvfile: telemetry_reader = csv.reader(csvfile, delimiter=',', quotechar='|') # there should only be one row in the telemetry file, but try to read all lines anyway for row in telemetry_reader: current_topic = mqtt.topic_root + '/' + topics['name'] + '/' + descr publish(client,current_topic,row[index]) #print(current_topic + '=' + row[index]) def run(): read_config() client = connect_mqtt() add_subscribtions_from_configfile(client) #topic = mqtt.topic_root + '/set' #subscribe(client,topic) client.loop_start() while True: #topic = mqtt.topic_root + '/test' #publish(client,topic,mqtt.aprs_state) send_telemetry_to_broker(client) time.sleep(mqtt.poll_rate) # Sleep (time defined in yml file) if __name__ == '__main__': #sys.stdout = sys.stderr = open('debug.log', 'w') run()