#!/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()        
       
