#!/usr/bin/env python3
# -*- coding utf-8 -*-
#
## clever_v02.py
# 28/04/18 by weigu.lu
#
# Raspi Pins:
# 1 3,3V
# 2,4 5V
# 6, 14, 20 GND
# 8 TXD
# 10 RXD
# 12 GPIO 18
# 16 GPIO 23
# 18 GPIO 24
# 22 GPIO 25

import RPi.GPIO as GPIO
import serial
from time import sleep
import paho.mqtt.client as mqtt
import json

RE_1 = 18 # Receiver enabled if LOW
DE1  =  23 # Transmitter (Data Driver) enabled with HIGH
RE_2 = 24
DE2  =  25

clientID = "clever_raspi"
brokerIP = "127.0.0.1"
brokerPort = 1883
topic1  = "clever_bus1"
topic2  = "clever_bus2"

ser = serial.Serial("/dev/ttyAMA0",baudrate = 250000, timeout = 0.01)
#ser.flushInput()
sleep(0.1)

def initGpio485():
    GPIO.setmode(GPIO.BCM) # Broadcom SOC channel number (numbers after GPIO)
    GPIO.setup(RE_1,GPIO.OUT)  # Bus1 select pins as output
    GPIO.setup(DE1,GPIO.OUT)
    GPIO.setup(RE_2,GPIO.OUT)  # Bus2 select pins as output
    GPIO.setup(DE2,GPIO.OUT)
    sleep(0.01)
    GPIO.output(RE_1,GPIO.LOW) # Receive Bus1
    GPIO.output(DE1,GPIO.LOW)
    GPIO.output(RE_2,GPIO.LOW) # Receive Bus2
    GPIO.output(DE2,GPIO.LOW)
    sleep(0.01)

# Callback that is executed when the client receives a CONNACK from the server.
def onConnect(client, userdata, flags, rc):
   print("Connected with result code " + str(rc))
    # Subscribe to the topics (topic name, QoS)
   mqttc.subscribe([(topic1, 0),(topic2,0)])

# Callback that is executed when we disconnect from the broker.
def onDisconnect(client, userdata, message):
   print("Disconnected from the broker.")

# Callback that is executed when subscribing to a topic.
def onSubscribe(client, userdata, mid, granted_qos):
   print('Subscribed on topic.')

# Callback that is executed when unsubscribing to a topic
def onUnsubscribe(client, userdata, mid, granted_qos):
   print('Unsubscribed on topic.')

# Callback that is executed when a message is received.
def onMessage(client, userdata, message):
    # Subscribing in on_connect() means that if we lose the connection and
    # reconnect then subscriptions will be renewed.
    global message485
    global flagMessage
    io=message.payload.decode("utf-8");
    print ("received message: ",end='')
    print(io)
    try:
        ioj=json.loads(io)
    except:
        ioj={"BusId":"error"}
    print ("json decoded: ",end='')
    print(ioj)
    print("------------")
    try:
        temp = ioj["BusId"]
    except:
        exit
    if temp[0]!='e':
        try:
            BusId =  ioj["BusId"]
            Command = ioj["Command"]
            Parameter = ioj["Parameter"]
            print(Parameter)
            val485 = get485(BusId,Command[0],Parameter)
            print(val485)
            message485 = "{\"BusId\":\""+BusId+"\",\"" + "Command\":\"" \
                         + Command + ' ' +Parameter +"\",\"Payload\":\"" + val485 + "\"}"
            flagMessage=1
        except:
            exit
    else:
        print("an error occured")


def get485(busId,command,parameter):
    OKStr='$'+busId+"OK"
    if parameter[0:5]=="Print":
        command='$'+busId+command+parameter[0]+parameter[5:]+'\n'
    else:
        command='$'+busId+command+parameter[0]+'\n'

    print ("command: ",end='')
    print (command)
    Cnt = 0
    mytext = "nothing"
    while (mytext[0:5] != OKStr) and (Cnt!=40):
        if busId[0] == '1':
            GPIO.output(RE_1,GPIO.HIGH) # Send
            GPIO.output(DE1,GPIO.HIGH)
        elif busId[0] == '2':
            GPIO.output(RE_2,GPIO.HIGH) # Send
            GPIO.output(DE2,GPIO.HIGH)
        sleep(0.00001)
        #print(command)
        bytes=ser.write(command.encode())
        #print(bytes)
        sleep(0.07) #min 0,05s
        if busId[0] == '1':
            GPIO.output(RE_1,GPIO.LOW) # Receive
            GPIO.output(DE1,GPIO.LOW)
        elif busId[0] == '2':
            GPIO.output(RE_2,GPIO.LOW) # Receive
            GPIO.output(DE2,GPIO.LOW)
        sleep(0.00001)
        try:
            mytext=ser.readline()
            mytext=mytext.decode()
            Cnt=Cnt+1
            print(Cnt,end='')
            print("   ",end='')
            print(mytext)
        except:
            Cnt=Cnt+1
            print(Cnt,end='')
            print("   ",end='')
            print("receiveerror")
    return(mytext[6:-1])

def listen485_bus1():
    mytext = "nothing"
    sleep(0.0001)
    GPIO.output(RE_1,GPIO.LOW) # Receive
    GPIO.output(DE1,GPIO.LOW)
    sleep(0.0001)
    try:
        mytext=ser.readline()
        mytext=mytext.decode()
    except:
        print("receiveerror")
    return(mytext)

def listen485_bus2():
    mytext = "nothing"
    sleep(0.0001)
    GPIO.output(RE_2,GPIO.LOW) # Receive
    GPIO.output(DE2,GPIO.LOW)
    sleep(0.0001)
    try:
        mytext=ser.readline()
        mytext=mytext.decode()
    except:
        print("receiveerror")
    return(mytext)

def publishAsyMessage(message):
    try:
        BusId =  message[1:3]        
        if message[3:5]=="ST":
            AsyMess = "State"
        elif message[3:5]=="RF":
            AsyMess = "RFID NUID"
        Value = message[6:-1]
        message = "{\"BusId\":\""+BusId+"\",\"" + "Message\":\"" \
                  + AsyMess + "\",\"" + "Payload\":\"" + Value + "\"}"
        print(message)
        mqttc.publish(topic2,message)
    except:
        print("error")
    

#-----------------------------------------------------------------------------
# MAIN SETUP
#-----------------------------------------------------------------------------
initGpio485()

mqttc = mqtt.Client(client_id=clientID, clean_session=True) # create client

mqttc.on_connect      = onConnect   # define the callback functions
mqttc.on_disconnect   = onDisconnect
mqttc.on_subscribe    = onSubscribe
mqttc.on_unsubscribe  = onUnsubscribe
mqttc.on_message      = onMessage

#mqttc.username_pw_set(config['MQTT']['userMQTT'], password=config['MQTT']['passwdMQTT'])
mqttc.connect(brokerIP, brokerPort, keepalive=60, bind_address="") # connect to the broker
mqttc.loop_start() # start loop to process callbacks! (new thread!)

message485 = "0"
flagMessage = 0
           
#-----------------------------------------------------------------------------
# MAIN LOOP
#-----------------------------------------------------------------------------
try:
    while (True):
        asyMessage = listen485_bus1()
        if asyMessage == '':
            asyMessage = listen485_bus2()
        if asyMessage[3:5]=="ST" or asyMessage[3:5]=="RF":
            print(asyMessage)
            publishAsyMessage(asyMessage)
        if flagMessage==1:
            mqttc.publish(topic1,message485)
            flagMessage=0
        sleep(0.1)

except KeyboardInterrupt:
    ser.close()
    GPIO.cleanup()
    mqttc.loop_stop() # clean up
    mqttc.disconnect()           
    print("Keyboard interrupt by user")
