You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
188 lines
6.1 KiB
188 lines
6.1 KiB
1 year ago
|
#!/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 <https://www.gnu.org/licenses/>.
|
||
|
"""
|
||
|
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()
|
||
|
|