# Andy Menon - 04.03.2016 - Use at your own risk!
# The Signalr Python Client with the Pi-Arduino Serial Bridge

# Client Function:
# Client receives the pipe-delimited IR Signal code as a single string
# Once received, this client breaks up each pipe-delimited segment into a separate string
# Each string is then written in succession to the Serial Port communicating the segment to Arduino
# The last segment of this string will contain a leading "E" as pre-fix - This will indicate to 
# Arduino that it has received the last segment of the IRSignal Code and stop reading.
# REFER: To the SignalR Hub and Client application code that accompanies this client code

# Arduino Function:
# Arduino will read each of the pipe-delimited code segment
# Once it receives the last segment with an "E" prefix, it stops reading
# Arduino will assemble the IRSignal signal string into an IR Signal Buffer Array
# Using the IRLib library, Arduino will trigger a transmit by submitting this IR Signal Buffer
# If the appliance to which this IR Code is limited is within range, the appliance (may) react
# to the IR Signal transmitted by the Arduino
# REFER: To the Arduino sketch that accompanies this client code

# progam constants | variables

# TEST_CODE_NAME: A pre-defined test code requested as soon as this client establishes connection with the hub
# SEGMENT_DELIMITER: The delimiting character that this client has to look for, and parse code segments
# TERMINAL_PREFIX: (future) - Client may use this to communicate back to the server that it has received all segments
# SERIAL_BAUD_RATE: The baud rate (the speed) at which the Python client communicates with the Arduino UNO

# debug: 1 = output messages (test mode) | 0 = no output messages except failures (operational or production mode)
# mode: 1 = production | 0 = local (or test) hub
# hubUrl: The URL to the Signalr hub that changes based on the value of mode
# hubName:  Name of the Signal hub - the server hub name is HomeAutomationHub,
#           but the signalr client must refer to this hub as "homeAutomationHub" (camel-notation)
# port:     The address of the Arduino UNO Serial port (your port may actually be different)


from requests import Session
from signalr import Connection
import serial

debug = 1
mode = 1
hubUrl =""
hubName = "homeAutomationHub"
TEST_CODE_NAME = "galaxy"
SEGMENT_DELIMITER = "|"
TERMINAL_PREFIX = "E"
port = "/dev/ttyACM0"           # this will have to match with your Arduino UNO Port!!!
SERIAL_BAUD_RATE = 9600         # this will have to match the Baud Rate on the Ardunio side if the Arduino is communicating back to this client program

with Session() as session:
    #create a connection - URL pattern is: http://<your_server_name>:<your_port_num>/signalr
    if(mode==1):
        hubUrl="http://yourDomain.com/signalr"
    else:
        hubUrl="http://localhost:54521/signalr"
    
    connection = Connection(hubUrl, session)
    ser = serial.Serial(port,SERIAL_BAUD_RATE)
    
    #MAKE SURE THAT signlar v0.0.6 is installed for register_hub() availability    
    homeAutoHub = connection.register_hub(hubName)


    #create new haHub message handler - This handler will be triggered when this 
    #client receives a notification from the Hubs sendCommandToClient() method
    def print_command_from_hub(buttonId, cmdSrc):
        if(mode==1):
            if(debug==1):
                print('Received Signal from Hub - Signal Id {0} : Source {1}'.format(buttonId,cmdSrc))
            if(len(cmdSrc)>0 and buttonId <> TEST_CODE_NAME ):
                transmitToArduino(cmdSrc,SEGMENT_DELIMITER,TERMINAL_PREFIX)              
        else:
            if(debug==1):
                print('TEST: Received Signal from Hub - Signal Id {0} : Source {1}'.format(buttonId,cmdSrc))
            
    
    # when new messages are received from the hub, pass them on to the handler for processing
    # 'sendCommandToClient' is the server side method that pushes notificationS to the clients
    homeAutoHub.client.on('sendCommandToClient', print_command_from_hub)


    def transmitToArduino(IRSignalCode,delim,endPrefix):
        while(len(IRSignalCode)>0):
            pos = IRSignalCode.index(delim)
            segment=IRSignalCode[:pos+1]
            if(debug==1):
                print("Found {0} at position {1} - segment parsed is {2}".format(delim,pos,segment))
            if(debug==1):
                print("Serial port {0} is open ".format(ser.name))        
            # CAUTION! segment value is UNICODE,convert to string before writing!
            ser.write(str(segment))
            segment=""
            # Remove segment already processed.
            IRSignalCode = IRSignalCode[(pos+1):]
          
        # WARNING! Do not close Serial port! Closing and opening each time
        # will cause Arduino to reset the execution of the Sketch
        #ser.close()
        

   
    # start connection - for always connected clients, use 'with (connection):'
    # for a one time connection, use connection.start()
    # call the 'automationCommand' SERVER-side method to send a message to the Automation Hub
    print("starting connection to haHub...")

    # once started, this SignalR client will run forever unless killed explicitly
    with (connection):
        print("connection to haHub active...requesting test code '{0}' ... ".format(TEST_CODE_NAME))
        homeAutoHub.server.invoke('automationCommand', 'galaxy','galaxy')
        print("awaiting commands from automation hub ...")
        while(1==1):
            connection.wait(5)
            print("...")

    ser.close()
    print("haHub exited....")
        
