#!/usr/bin/env python3
#-*- coding: utf-8 -*-

""" 
    When handling of messages might take long time, then 
    decouple receiving and processing steps by a message queue.
    
    Wrap MQTT in a class,
    use a thread to consume the messages,
    use a queue.Queue to transport messages between threads"""

import queue
import sys
import threading

import gpiozero
import paho.mqtt.client as mqtt

debug = True

HOST = "192.168.1.200"
HOST = "mqttserver"
PORT = 1883

GPIO_LED = 13

msgQueue = queue.Queue()

class MQTT_Wrapper:
    """
       Wrap MQTT connection and subscribe to a topic.
       Place Commands received to an event queue
    """

    def __init__(self):
        self.client = mqtt.Client()
        #client.on_connect = on_connect
        self.client.on_connect = self.on_connect
        self.client.on_message = self.on_message   
        
        self.client.connect(HOST, PORT, keepalive=60)
        if debug:
            print("mqtt connected")
        self.client.loop_start()
    
    def close(self):
        self.client.disconnect()
        self.client.loop_stop()   
        self.t.join()
         
    def on_connect(self, client, userdata, flags, rc):
        if debug:
            print("mqtt Connected with result code ", rc)
    
        # Subscribing in on_connect() means that if we lose the connection and
        # reconnect then subscriptions will be renewed.
        
        self.client.subscribe(
                [
                    ("tutorial/A/LED", 0),
                ]
        )
    
    # The callback for when a PUBLISH message is received from the server.
    def on_message(self, client, userdata, msg):
        if debug:
            print(msg.topic,str(msg.payload), "retain", msg.retain, "qos", msg.qos, str(userdata) )
        # payload is by default binary, so decode to a string.
        msgQueue.put( msg.payload.decode('ascii', errors='ignore') )

        
class LED:
    """Handle a gpiozero.LED which receives commands through an event queue"""
    
    def __init__(self, gpio):
        self.gpio = gpio
        
        self.led = gpiozero.LED(self.gpio)
        self.runIt = True
        self.t = threading.Thread(target=self._run)
        self.t.start()
        
    def _run(self):
        while self.runIt:
            try:
                msg = msgQueue.get(timeout=0.1)
            except queue.Empty:
                continue
            
            if msg == 'ON':
                self.led.on()
            if msg == 'OFF':
                self.led.off()
                
                 
    def close(self):
        self.runIt = False
        self.t.join(0.5)
        self.led.off()
        

if __name__ == "__main__":
    
    led = LED(GPIO_LED)
        
    mqtt_wrapper = MQTT_Wrapper()
    
    wait = threading.Event()
    try:
        wait.wait()
    except KeyboardInterrupt:
        pass
    
    
    led.close()
    mqtt_wrapper.close()
    print("finished")