
##LYRA MODULE



def reset_Lyra(client,target_unit):
    try:
        builder = BinaryPayloadBuilder(byteorder=Endian.Big)
        builder.add_16bit_uint(0x0002)
        builder.add_16bit_uint(0x0001)
        payload = builder.build()
        result  = client.write_registers(5000, payload, skip_encode=True)
        return
    except:
        raise

def Lyra_factory_reset(client,target_unit):
    try:
        builder = BinaryPayloadBuilder(byteorder=Endian.Big)
        builder.add_16bit_uint(0x0002)
        builder.add_16bit_uint(0x0002)
        payload = builder.build()
        result  = client.write_registers(5000, payload, skip_encode=True)
        return
    except:
        raise


def read_time_register(client,target_unit):
    #ID is composed by two 16-bit digits.
    try:
        request=client.read_holding_registers(address=5004,count=2,unit=target_unit)
        if not request.isError():
            time=int(str(request.registers[0])+str(request.registers[1]))
            #print('Time from unit ',target_unit," is ",time)
            return time
    except:
        raise
    

def read_k1_register(client,target_unit):
    #ID is composed by two 16-bit digits.
    try:
        request=client.read_holding_registers(address=5000,count=2,unit=target_unit)
        if not request.isError():
            return hex(request.registers[0]),hex(request.registers[1])
    except:
        raise

def read_system_status(client,target_unit):
    #ID is composed by two 16-bit digits.
    try:
        request=client.read_holding_registers(address=5016,count=2,unit=target_unit)
        if not request.isError():
            return hex(request.registers[0]),hex(request.registers[1])
    except:
        raise

def reset_time_register(client,target_unit,time_to_write):
    #ID is composed by two 16-bit digits.
    try:
        wrequest=client.write_registers(address=5004,values=[0x0000,time_to_write],unit=target_unit)
        request=client.read_holding_registers(address=5004,count=2,unit=target_unit)
        if not request.isError():
            time=int(str(request.registers[0])+str(request.registers[1]))
            print('Time from unit ',target_unit," is ",time)
            return time
    except:
        raise

def change_id_register_to_default(client,target_unit):
    #ID is composed by two 16-bit digits.
    new_id=2
    try:
        builder = BinaryPayloadBuilder(byteorder=Endian.Big)
        builder.add_16bit_uint(0x5A5A)
        builder.add_16bit_uint(new_id)
        payload = builder.build()
        result  = client.write_registers(5200, payload, skip_encode=True)
        return
        # rq=client.write_registers(5200,[0x0000],unit=target_unit)
        # rq=client.write_registers(5201,[new_id],unit=target_unit)
    except:
        raise
def change_bt_timeout(client,target_unit,new_value):
    #ID is composed by two 16-bit digits.
    try:
        builder = BinaryPayloadBuilder(byteorder=Endian.Big)
        builder.add_32bit_float(new_value)
        payload = builder.build()
        result  = client.write_registers(7220, payload, skip_encode=True)
        return
        # rq=client.write_registers(5200,[0x0000],unit=target_unit)
        # rq=client.write_registers(5201,[new_id],unit=target_unit)
    except:
        raise 

def change_btconfig_parameters(client,target_unit,values):
    #ID is composed by two 16-bit digits.
    for i in range(14):
        value_to_write=values[i]
##        print(value_to_write,7220+2*i)
        try:
            builder = BinaryPayloadBuilder(byteorder=Endian.Big)
            builder.add_32bit_float(value_to_write)
            payload = builder.build()
            result  = client.write_registers(7200+2*i, payload, skip_encode=True)
            time.sleep(0.1)
            print('Value ',value_to_write,' successfully written at register: ',7200+2*i)
            # rq=client.write_registers(5200,[0x0000],unit=target_unit)
            # rq=client.write_registers(5201,[new_id],unit=target_unit)
        except:
            raise
    print('All values succesfully written')
    return

def change_guconfig_parameters(client,target_unit,values):
    #ID is composed by two 16-bit digits.
    for i in range(7):
        value_to_write=values[i]
##        print(value_to_write,7220+2*i)
        try:
            builder = BinaryPayloadBuilder(byteorder=Endian.Big)
            builder.add_32bit_float(value_to_write)
            payload = builder.build()
            result  = client.write_registers(7228+2*i, payload, skip_encode=True)
            time.sleep(0.1)
            print('Value ',value_to_write,' successfully written at register: ',7228+2*i)
            # rq=client.write_registers(5200,[0x0000],unit=target_unit)
            # rq=client.write_registers(5201,[new_id],unit=target_unit)
        except:
            raise
    print('All values succesfully written')
    return

def change_sbconfig_parameters(client,target_unit,values):
    #ID is composed by two 16-bit digits.
    for i in range(11):
        value_to_write=values[i]
##        print(value_to_write,7220+2*i)
        try:
            builder = BinaryPayloadBuilder(byteorder=Endian.Big)
            builder.add_32bit_float(value_to_write)
            payload = builder.build()
            result  = client.write_registers(7242+2*i, payload, skip_encode=True)
            time.sleep(0.1)
            print('Value ',value_to_write,' successfully written at register: ',7242+2*i)
            # rq=client.write_registers(5200,[0x0000],unit=target_unit)
            # rq=client.write_registers(5201,[new_id],unit=target_unit)
        except:
            raise
    print('All values successfully written')
    return
            
def change_id_register(client,target_unit,target_id):
    #ID is composed by two 16-bit digits.
    new_id=target_id
    try:
        rq=client.write_registers(5200,[0x5A5A,new_id],unit=target_unit)
        print('ID of unit ',target_unit,' has been changed successfully to ',target_id)
        return
        # rq=client.write_registers(5201,,unit=target_unit)
    except:
        raise   
        
def broadcast_default_ID(client):
    try:
        rq=client.write_registers(5200,[0x5A5A,1],unit=0)
        return
    except:
        raise
        
def broadcast_get_IDs(client):
    #This needs to be improved to associate the response with the incoming ID.
    try:
        print('Trying to get IDs from the network via broadcasting to unit 0...')
        rq=client.read_holding_registers(5200,count=2,unit=0)
        if not rq.isError():
            print('IDs from network gathered successfully...')
        return rq
    except:
        print('Unable to retrieve network devices IDs')
        return client.read_holding_registers(5200,count=2,unit=0)
        raise

def broadcast_reset_Lyra(client):
    try:
        rq=client.write_registers(5000,[0x0002],unit=0)
        rq=client.write_registers(5001,[0x0001],unit=0)
    except:
        raise
        
def K1_contactor_sync(client,target_unit):
    try:
        builder = BinaryPayloadBuilder(byteorder=Endian.Big)
        builder.add_16bit_uint(0x0010)
        builder.add_16bit_uint(0x0001)
        payload = builder.build()
        result  = client.write_registers(5000, payload, skip_encode=True)
        print('Sync attempt of K1 at: ',str(dt.datetime.now()))
        return
    except:
        raise
        
def K1_contactor_forced_closing(client,target_unit):
    try:
        builder = BinaryPayloadBuilder(byteorder=Endian.Big)
        builder.add_16bit_uint(0x0010)
        builder.add_16bit_uint(0x0002)
        payload = builder.build()
        result  = client.write_registers(5000, payload, skip_encode=True)
        print('Forced close of K1 at',str(dt.datetime.now()))
        return
    except: 
        raise

def K1_contactor_forced_opening(client,target_unit):
    try:
        builder = BinaryPayloadBuilder(byteorder=Endian.Big)
        builder.add_16bit_uint(0x0010)
        builder.add_16bit_uint(0x0003)
        payload = builder.build()
        result  = client.write_registers(5000, payload, skip_encode=True)
        print('Forced opening of K1 at',str(dt.datetime.now()))
        return
    except: 
        raise

def K2_contactor_sync(client,target_unit):
    try:
        builder = BinaryPayloadBuilder(byteorder=Endian.Big)
        builder.add_16bit_uint(0x0020)
        builder.add_16bit_uint(0x0001)
        payload = builder.build()
        result  = client.write_registers(5000, payload, skip_encode=True)
        print('Sync attempt of K2 at: ',str(dt.datetime.now()))
        return
    except: 
        raise
        
def K2_contactor_forced_closing(client,target_unit):
    try:
        builder = BinaryPayloadBuilder(byteorder=Endian.Big)
        builder.add_16bit_uint(0x0020)
        builder.add_16bit_uint(0x0002)
        payload = builder.build()
        result  = client.write_registers(5000, payload, skip_encode=True)
        print('Forced close of K2 at',str(dt.datetime.now()))
        #rq = client.write_registers(5001, [0x0002], unit=target_unit)
        return
    except: 
        raise

def K2_contactor_forced_opening(client,target_unit):
    try:
        builder = BinaryPayloadBuilder(byteorder=Endian.Big)
        builder.add_16bit_uint(0x0020)
        builder.add_16bit_uint(0x0003)
        payload = builder.build()
        result  = client.write_registers(5000, payload, skip_encode=True)
        print('Forced opening of K2 at',str(dt.datetime.now()))
        return
    except: 
        raise

def K1_contactor_donothing(client,target_unit):
    try:
        builder = BinaryPayloadBuilder(byteorder=Endian.Big)
        builder.add_16bit_uint(0x0000)
        builder.add_16bit_uint(0x0000)
        payload = builder.build()
        result  = client.write_registers(5000, payload, skip_encode=True)
        print('Registers 5000 with "do nothing" cmd at: ',str(dt.datetime.now()))
        return
    except: 
        raise


def K2_contactor_donothing(client,target_unit):
    try:
        builder = BinaryPayloadBuilder(byteorder=Endian.Big)
        builder.add_16bit_uint(0x0000)
        builder.add_16bit_uint(0x0000)
        payload = builder.build()
        result  = client.write_registers(5000, payload, skip_encode=True)
        print('Registers 5000 with "do nothing" cmd at: ',str(dt.datetime.now()))
        return
    except: 
        raise



def K3_contactor_donothing(client,target_unit):
    try:
        builder = BinaryPayloadBuilder(byteorder=Endian.Big)
        builder.add_16bit_uint(0x0000)
        builder.add_16bit_uint(0x0000)
        payload = builder.build()
        result  = client.write_registers(5000, payload, skip_encode=True)
        print('Registers 5000 with "do nothing" cmd at: ',str(dt.datetime.now()))
        return
    except: 
        raise

def K3_contactor_sync(client,target_unit):
    try:
        builder = BinaryPayloadBuilder(byteorder=Endian.Big)
        builder.add_16bit_uint(0x0030)
        builder.add_16bit_uint(0x0001)
        payload = builder.build()
        result  = client.write_registers(5000, payload, skip_encode=True)
        print('Sync attempt of K3 at: ',str(dt.datetime.now()))
        return
    except: 
        raise
        
def K3_contactor_forced_closing(client,target_unit):
    try:
        builder = BinaryPayloadBuilder(byteorder=Endian.Big)
        builder.add_16bit_uint(0x0030)
        builder.add_16bit_uint(0x0002)
        payload = builder.build()
        result  = client.write_registers(5000, payload, skip_encode=True)
        print('Forced close of K3 at',str(dt.datetime.now()))
        return
    except: 
        raise

def K3_contactor_forced_opening(client,target_unit):
    try:
        builder = BinaryPayloadBuilder(byteorder=Endian.Big)
        builder.add_16bit_uint(0x0030)
        builder.add_16bit_uint(0x0003)
        payload = builder.build()
        result  = client.write_registers(5000, payload, skip_encode=True)
        print('Forced opening of K3 at',str(dt.datetime.now()))
        return
    except: 
        raise

#Reading purpose functions
###
### Functions:
#read_min_volt_conn_register(client,1)
#read_max_volt_conn_register(client,1)

#read_min_volt_disc_register(client,1)
#read_max_volt_disc_register(client,1)

#read_max_volt_diff_disc_register(client,1)
#read_max_volt_diff_conn_register(client,1)

#read_max_freq_diff_conn_register(client,1)

#read_max_angle_diff_conn_register(client,1)
#read_max_angle_diff_disc_register(client,1)

#read_conn_timeout_register(client,1)
def read_k1_status(client,target_unit):
    try:
        rq=client.read_coils(1000,unit=target_unit)
        return rq.bits[0]
    except:
        raise

def read_flags(client,target_unit):
    try:
        values=[]
        for i in range(0,3):
            request=client.read_holding_registers(address=5010+i*2,count=2,unit=target_unit)
            decoder = payload.BinaryPayloadDecoder.fromRegisters(request.registers, byteorder=">", wordorder=">")
            c,d='{0:016b}'.format(client.read_holding_registers(address=5010,count=2,unit=8).registers[0]),'{0:016b}'.format(client.read_holding_registers(address=5010,count=2,unit=8).registers[1])
            if not request.isError():                
                value=decoder.decode_32bit_uint()
##                values.append(['{0:032b}'.format(value),c,d])
                values.append('{0:032b}'.format(value))
        return values
    except:
        raise


def read_config_parameters(client,target_unit,app):
    if app=='bt':
        #ID is composed by two 16-bit digits.
        try:
            values=[]
            for i in range(0,14):
                request=client.read_holding_registers(address=7200+i*2,count=2,unit=target_unit)
                decoder = payload.BinaryPayloadDecoder.fromRegisters(request.registers, byteorder=">", wordorder=">")
                if not request.isError():
                    value=decoder.decode_32bit_float()
                    values.append(value)
            return values
        except:
            raise

    if app=='gu':
        #ID is composed by two 16-bit digits.
        try:
            values=[]
            for i in range(7):
                request=client.read_holding_registers(address=7228+i*2,count=2,unit=target_unit)
                decoder = payload.BinaryPayloadDecoder.fromRegisters(request.registers, byteorder=">", wordorder=">")
                if not request.isError():
                    value=decoder.decode_32bit_float()
                    values.append(value)
            return values
        except:
            raise
        
    if app=='sb':
        #ID is composed by two 16-bit digits.
        try:
            values=[]
            for i in range(0,11):
                request=client.read_holding_registers(address=7242+i*2,count=2,unit=target_unit)
                decoder = payload.BinaryPayloadDecoder.fromRegisters(request.registers, byteorder=">", wordorder=">")
                if not request.isError():
                    value=decoder.decode_32bit_float()
                    values.append(value)
            return values
        except:
            raise


def read_id_register(client,target_unit):
    #ID is composed by two 16-bit digits.
    try:
        request=client.read_holding_registers(address=5200,count=2,unit=target_unit)
        if not request.isError():
            print('ID from unit ',target_unit," is ",request.registers)
        return request.registers
    except:
        raise


def read_min_volt_conn_register(client,target_unit):
    #ID is composed by two 16-bit digits.
    try:
        request=client.read_holding_registers(address=7204,count=2,unit=target_unit)
        decoder = payload.BinaryPayloadDecoder.fromRegisters(request.registers, byteorder=">", wordorder=">")
        if not request.isError():
            value=decoder.decode_32bit_float()
            print('Min voltage for connection from unit ',target_unit," is ",value)
        return value

    except:
        raise

def read_max_volt_conn_register(client,target_unit):
    #ID is composed by two 16-bit digits.
    try:
        request=client.read_holding_registers(address=7206,count=2,unit=target_unit)
        decoder = payload.BinaryPayloadDecoder.fromRegisters(request.registers, byteorder=">", wordorder=">")
        if not request.isError():
            value=decoder.decode_32bit_float()
            print('Max voltage for connection from unit ',target_unit," is ",value)
        return value

    except:
        raise
        

def read_min_volt_disc_register(client,target_unit):
    #ID is composed by two 16-bit digits.
    try:
        request=client.read_holding_registers(address=7214,count=2,unit=target_unit)
        decoder = payload.BinaryPayloadDecoder.fromRegisters(request.registers, byteorder=">", wordorder=">")
        if not request.isError():
            value=decoder.decode_32bit_float()
            print('Min voltage for disconnection from unit ',target_unit," is ",value)
        return value

    except:
        raise

def read_max_volt_disc_register(client,target_unit):
    #ID is composed by two 16-bit digits.
    try:
        request=client.read_holding_registers(address=7216,count=2,unit=target_unit)
        decoder = payload.BinaryPayloadDecoder.fromRegisters(request.registers, byteorder=">", wordorder=">")
        if not request.isError():
            value=decoder.decode_32bit_float()
            print('Max voltage for disconnection from unit ',target_unit," is ",value)
        return value

    except:
        raise

def read_max_volt_diff_disc_register(client,target_unit):
    #ID is composed by two 16-bit digits.
    try:
        request=client.read_holding_registers(address=7218,count=2,unit=target_unit)
        decoder = payload.BinaryPayloadDecoder.fromRegisters(request.registers, byteorder=">", wordorder=">")
        if not request.isError():
            value=decoder.decode_32bit_float()
            print('Max voltage difference for disconnection from unit ',target_unit," is ",value)
        return value

    except:
        raise

def read_max_volt_diff_conn_register(client,target_unit):
    #ID is composed by two 16-bit digits.
    try:
        request=client.read_holding_registers(address=7210,count=2,unit=target_unit)
        decoder = payload.BinaryPayloadDecoder.fromRegisters(request.registers, byteorder=">", wordorder=">")
        if not request.isError():
            value=decoder.decode_32bit_float()
            print('Max voltage difference for connection from unit ',target_unit," is ",value)
        return value

    except:
        raise

def read_max_freq_diff_conn_register(client,target_unit):
    #ID is composed by two 16-bit digits.
    try:
        request=client.read_holding_registers(address=7208,count=2,unit=target_unit)
        decoder = payload.BinaryPayloadDecoder.fromRegisters(request.registers, byteorder=">", wordorder=">")
        if not request.isError():
            value=decoder.decode_32bit_float()
            print('Max frequency difference for connect from unit ',target_unit," is ",value)
        return value

    except:
        raise



def read_max_angle_diff_disc_register(client,target_unit):
    #ID is composed by two 16-bit digits.
    try:
        request=client.read_holding_registers(address=7212,count=2,unit=target_unit)
        decoder = payload.BinaryPayloadDecoder.fromRegisters(request.registers, byteorder=">", wordorder=">")
        if not request.isError():
            value=decoder.decode_32bit_float()
            print('Max angle difference for connection from unit ',target_unit," is ",value)
        return value

    except:
        raise
        
def read_max_angle_diff_conn_register(client,target_unit):
    #ID is composed by two 16-bit digits.
    try:
        request=client.read_holding_registers(address=7202,count=2,unit=target_unit)
        decoder = payload.BinaryPayloadDecoder.fromRegisters(request.registers, byteorder=">", wordorder=">")
        if not request.isError():
            value=decoder.decode_32bit_float()
            print('Max angle tolerance from unit ',target_unit," is ",value)
        return value

    except:
        raise
        
def read_conn_timeout_register(client,target_unit):
    #ID is composed by two 16-bit digits.
    try:
        request=client.read_holding_registers(address=7220,count=2,unit=target_unit)
        decoder = payload.BinaryPayloadDecoder.fromRegisters(request.registers, byteorder=">", wordorder=">")
        if not request.isError():
            value=decoder.decode_32bit_float()
            print('Timeout value for connection from unit ',target_unit," is ",value)
        return value

    except:
        raise
        


#Phase Reading functions
#Phase Reading functions
#Phase Reading functions

def read_side_1_info(client,target_unit):
    try:
        
        result=client.read_input_registers(address=7000,count=36,unit=target_unit)
        decoder = payload.BinaryPayloadDecoder.fromRegisters(result.registers, byteorder=">", wordorder=">")
        data=[]
        for i in range(int(36/2)):
            data.append(decoder.decode_32bit_float())
        return data
    except Exception as e:
        raise
        
def read_phase_1_info_side_1(client,target_unit):
    try:
        data=[]
        for i in range(6):
            result=client.read_input_registers(address=7000+i*2,count=2,unit=target_unit)
            decoder = payload.BinaryPayloadDecoder.fromRegisters(result.registers, byteorder=">", wordorder=">")
            data.append(decoder.decode_32bit_float())
        return data
    except Exception as e:
        raise

def read_phase_2_info_side_1(client,target_unit):
    try:
        data=[]
        for i in range(6):
            result=client.read_input_registers(address=7012+i*2,count=2,unit=target_unit)
            decoder = payload.BinaryPayloadDecoder.fromRegisters(result.registers, byteorder=">", wordorder=">")
            data.append(decoder.decode_32bit_float())
        return data
    except Exception as e:
        raise
    
def read_phase_3_info_side_1(client,target_unit):
    try:
        data=[]
        for i in range(6):
            result=client.read_input_registers(address=7024+i*2,count=2,unit=target_unit)
            decoder = payload.BinaryPayloadDecoder.fromRegisters(result.registers, byteorder=">", wordorder=">")
            data.append(decoder.decode_32bit_float())
        return data
    except Exception as e:
        raise
    
def read_phase_1_info_side_2(client,target_unit):
    try:
        data=[]
        for i in range(6):
            result=client.read_input_registers(address=7036+i*2,count=2,unit=target_unit)
            decoder = payload.BinaryPayloadDecoder.fromRegisters(result.registers, byteorder=">", wordorder=">")
            data.append(decoder.decode_32bit_float())
        return data
    except Exception as e:
        return result

def read_phase_2_info_side_2(client,target_unit):
    try:
        data=[]
        for i in range(6):
            result=client.read_input_registers(address=7048+i*2,count=2,unit=target_unit)
            decoder = payload.BinaryPayloadDecoder.fromRegisters(result.registers, byteorder=">", wordorder=">")
            data.append(decoder.decode_32bit_float())
        return data
    except Exception as e:
        raise
    
def read_phase_3_info_side_2(client,target_unit):
    try:
        data=[]
        for i in range(6):
            result=client.read_input_registers(address=7060+i*2,count=2,unit=target_unit)
            decoder = payload.BinaryPayloadDecoder.fromRegisters(result.registers, byteorder=">", wordorder=">")
            data.append(decoder.decode_32bit_float())
        return data
    except Exception as e:
        raise
        
#Writing registers purpose functions
###
###
def write_max_angle_diff_conn_register(client,target_unit,new_value):
    #ID is composed by two 16-bit digits.
    try:
        builder=BinaryPayloadBuilder()
        builder.add_16bit_float(new_value)
        payload=builder.build()
        print(payload)
        #wrequest=client.write_registers(address=7202,values=[new_value,0],unit=target_unit)
        wrequest=client.write_registers(address=7202,values=payload,skip_encode=True,unit=target_unit)
        if not wrequest.isError():
            print('Max angle tolerance from unit ',target_unit," now is ",new_value)
        return new_value

    except Exception as e:
        print(e)
        raise
  
def write_min_vol_conn_register(client,target_unit,new_value):
    #ID is composed by two 16-bit digits.
    try:
        wrequest=client.write_registers(address=7204,values=[new_value],unit=target_unit)
        if not wrequest.isError():
            print('Min voltage  connection tolerance from unit ',target_unit," now is ",new_value)
        return new_value

    except:
        raise

def write_max_vol_conn_register(client,target_unit,new_value):
    #ID is composed by two 16-bit digits.
    try:
        wrequest=client.write_registers(address=7206,values=[new_value],unit=target_unit)
        if not wrequest.isError():
            print('Max voltage connection tolerance from unit ',target_unit," now is ",new_value)
        return new_value

    except:
        raise


def write_max_freq_diff_conn_register(client,target_unit,new_value):
    #ID is composed by two 16-bit digits.
    try:
        wrequest=client.write_registers(address=7208,values=[0x0028],unit=target_unit)
        if not wrequest.isError():
            print('Max angle tolerance from unit ',target_unit," now is ",new_value)
        return new_value

    except:
        raise

def write_max_volt_diff_conn_register(client,target_unit,new_value):
    #ID is composed by two 16-bit digits.
    try:
        wrequest=client.write_registers(address=7210,values=[0x0028],unit=target_unit)
        if not wrequest.isError():
            print('Max voltage difference tolerance from unit ',target_unit," now is ",new_value)
        return new_value

    except:
        raise
  
def write_max_agl_diff_disc_register(client,target_unit,new_value):
    #ID is composed by two 16-bit digits.
    try:
        wrequest=client.write_registers(address=7212,values=[],unit=target_unit)
        if not wrequest.isError():
            print('Max angle disconnection tolerance from unit ',target_unit," now is ")
        return new_value

    except:
        raise
        
def write_min_vol_disc_register(client,target_unit,new_value):
    #ID is composed by two 16-bit digits.
    try:
        wrequest=client.write_registers(address=7214,values=[0x0028],unit=target_unit)
        if not wrequest.isError():
            print('Min voltage tolerance for disconnection from unit ',target_unit," now is ",new_value)
        return new_value

    except:
        raise
   
def write_max_vol_disc_register(client,target_unit,new_value):
    #ID is composed by two 16-bit digits.
    try:
        wrequest=client.write_registers(address=7216,values=[0x0028],unit=target_unit)
        if not wrequest.isError():
            print('Max voltage tolerance for connection from unit ',target_unit," now is ",new_value)
        return new_value

    except:
        raise
        
def write_max_vol_diff_disc_register(client,target_unit,new_value):
    #ID is composed by two 16-bit digits.
    try:
        wrequest=client.write_registers(address=7218,values=[0x0028],unit=target_unit)
        if not wrequest.isError():
            print('Max voltage difference tolerance for disconnection from unit ',target_unit," now is ",new_value)
        return new_value

    except:
        raise
 
def write_conn_timeout_register(client,target_unit,new_value):
    #ID is composed by two 16-bit digits.
    try:
        wrequest=client.write_registers(address=7220,values=[0x0028],unit=target_unit)
        if not wrequest.isError():
            print('Max angle tolerance from unit ',target_unit," now is ",new_value)
        return new_value

    except:
        raise
      




####RELAY MODULES

def create_connection(comport):
    num_retries=10
    try:
        #client=ModbusSerialClient(method='rtu',port='/dev/ttyUSB'+str(comport),stopbits=1,bytesize=8,parity='N',baudrate=115200)
        client=ModbusSerialClient(method='rtu',port='COM'+str(comport),stopbits=1,bytesize=8,parity='N',baudrate=115200)
        client.connect()
        return client
    
    except:
        i=0
        while i<=num_retries:
            try:
                client=ModbusSerialClient(method='rtu',port='/dev/ttyUSB'+str(comport),stopbits=1,bytesize=8,parity='N',baudrate=115200)
                client.connect()
                i+=1
                return client
            except:
                i+=1
                pass
        raise

def close_connection(client):
    try:
        client.close()
    except:
        raise



#IDs van desde 1 a 256 (0x01 a 0xFF), broadcast ID is 0x00    
def read_slave_id_address(client,slave_id):
    # return client.read_holding_registers(address=16384,count=1,unit=slave_id).registers
    return client.read_holding_registers(address=0x4000,count=1,unit=slave_id).registers[0]

def change_slave_id(client,slave_id,target_id):
    rq=client.write_register(address=0x4000,value=target_id,unit=slave_id)
    return

def change_slave_baudrate(client,slave_id,target_baudrate):
    #     The baud rate
    # 0x0000  : 4800
    # 0x0001  : 9600
    # 0x0002  : 19200
    # 0x0003  : 38400
    # 0x0004  : 57600
    # 0x0005  : 115200
    # 0x0006  : 128000
    # 0x0007  : 256000
    try:
        client.write_register(address=0x2000,value=target_baudrate,unit=slave_id)
        print("Baudrate was modified successfully to option: ",target_baudrate)
        return
    except:
        raise


#Status readings
def read_relays_status(client,slave_id):
    #Returns a list with bools indicating status of the relays.
    #Register=0, count=8, unit=11 to 14.
    #output -> [True, True, True, True, True, True, True, True]
#   If it fails, it will give an error.
    
    retries=10
    j=0
    while j<=retries:
        #time.sleep(0.1)
        if j!=0:
            print('Attempt: ',j+1)
        req=client.read_coils(address=0,count=8,unit=slave_id)
        if not req.isError():
            req = req.bits
            out={}
            for i in range(8):
                out.update({i:req[i]})
            if j!=0:
                print('Num_Tries: ',j+1)
            return out
        time.sleep(0.1)
        j+=1
        #{0:False,1:False,2:False,3:False,4:False,5:False,6:False,7:False,8:False}
    return req 




#Individual relay handling
def close_relay(client,slave_id,relay_to_close):
    #values for relay_to_close from 0 to 7
    status=read_relays_status(client,slave_id)
    state=status[relay_to_close]
    while state==False:
        try:
            if client.is_socket_open():
                client.write_coil(address=relay_to_close,value=1,unit=slave_id)
                time.sleep(0.1)
                state=read_relays_status(client,slave_id)[relay_to_close]
        except Exception as e:
            print(e)
            raise
    return

def open_relay(client,slave_id,relay_to_close):
    #values for relay_to_close from 0 to 7
    status=read_relays_status(client,slave_id)
    state=status[relay_to_close]
    while state==True:
        try:
            if client.is_socket_open():
                client.write_coil(address=relay_to_close,value=0,unit=slave_id)
                time.sleep(0.1)
                state=read_relays_status(client,slave_id)[relay_to_close]
        except Exception as e:
            print(e)
            raise
    return

    

#Relays group handling
#Close all relays for a 
def close_all_module_relays(client,slaves_id):
    #Grid Unifying contactor data
    grid_unifying_module=14
    grid_unifying_contactor_id=0
    try:
        for slave_id in slaves_id:
            #Slave ID that contains GUC.
            try:
                status=read_relays_status(client,slave_id)
            except:
                time.sleep(0.1)
                status=read_relays_status(client,slave_id)

            if slave_id==grid_unifying_module:
                for i in range(7,0,-1):
                    if status[i]==False and i!=grid_unifying_contactor_id:
                        close_relay(client,slave_id,i)
                    else:
                        pass
            else:
                try:
                    client.write_coil(address=0x00ff,value=1,unit=slave_id)
                    time.sleep(0.1)
                    status=read_relays_status(client,slave_id)
                    for i in range(8):
                        #if its not closed
                        if status[i]==False:
                            close_relay(client,slave_id,i)
                except:
                    raise
    except:
        raise
  


def open_all_module_relays(client,slaves_id):
    #Grid Unifying contactor data
    grid_unifying_module=14
    grid_unifying_contactor_id=0
    try:
        for slave_id in slaves_id:
            #Slave ID that contains GUC.
            try:
                status=read_relays_status(client,slave_id)
            except:
                time.sleep(0.1)
                status=read_relays_status(client,slave_id)

            if slave_id==grid_unifying_module:
                for i in range(7,0,-1):
                    if status[i]==True and i!=grid_unifying_contactor_id:
                        open_relay(client,slave_id,i)
                    else:
                        pass
            else:
                try:
                    client.write_coil(address=0x00ff,value=0,unit=slave_id)
                    time.sleep(0.1)
                    status=read_relays_status(client,slave_id)
                    for i in range(8):
                        #if its not closed
                        if status[i]==True:
                            open_relay(client,slave_id,i)
                except:
                    raise
    except:
        raise
    






####UGRID CONTROL

#list devices in terminal ls /dev/*USB*

def connect_all(client):
    modules=[11,12,13,14]
    relays=[0,1,2,3,4,5,6,7]
    for module in modules:
        for relay in relays:
            close_relay(client,module,relay)
    return

def disconnect_all(client):
    modules=[14,13,12,11]
    relays=[7,6,5,4,3,2,1,0]
    for module in modules:
        for relay in relays:
            open_relay(client,module,relay)
    return

def connect_der(client,ders_to_connect):
    #ders_to_connect takes values from 1 to 6
    #der_locations={DER:(module_id,contactor)}
    der_locations={1:(11,2),2:(12,6),3:(12,2),4:(13,2),5:(14,6),6:(14,2)}
    for der in ders_to_connect:
        module=der_locations[der][0]
        contactor=der_locations[der][1]
        close_relay(client,module,contactor)
    return
    

def disconnect_der(client,ders_to_disconnect):
    #ders_to_discconnect is a list that takes values from 1 to 6
    #der_locations={DER:(module_id,contactor)}
    der_locations={1:(11,2),2:(12,6),3:(12,2),4:(13,2),5:(14,6),6:(14,2)}
    for der in ders_to_disconnect:
        module=der_locations[der][0]
        contactor=der_locations[der][1]
        open_relay(client,module,contactor)
    return

def connect_load(client,loads_to_connect):
    #loads_to_connect takes values from 1 to 12(?)
    load_locations={1:(11,3),2:(11,1),3:(12,7),4:(12,5),5:(12,3),6:(12,1),7:(13,3),8:(13,1),9:(14,7),10:(14,5),11:(14,4)}
    for load in loads_to_connect:
        module=load_locations[load][0]
        contactor=load_locations[load][1]
        close_relay(client,module,contactor)
    return
    
def disconnect_load(client,loads_to_disconnect):
    #loads_to_connect takes values from 1 to 12(?)
    load_locations={1:(11,3),2:(11,1),3:(12,7),4:(12,5),5:(12,3),6:(12,1),7:(13,3),8:(13,1),9:(14,7),10:(14,5),11:(14,4)}
    for load in loads_to_disconnect:
        module=load_locations[load][0]
        contactor=load_locations[load][1]
        open_relay(client,module,contactor)
    return
    

def connect_all_load(client):
    load_locations={1:(11,3),2:(11,1),3:(12,7),4:(12,5),5:(12,3),6:(12,1),7:(13,3),8:(13,1),9:(14,7),10:(14,4),11:(14,4)}
    for load in load_locations.keys():
        module=load_locations[load][0]
        contactor=load_locations[load][1]
        close_relay(client,module,contactor)
    return

def disconnect_all_load(client):
    load_locations={1:(11,3),2:(11,1),3:(12,7),4:(12,5),5:(12,3),6:(12,1),7:(13,3),8:(13,1),9:(14,7),10:(14,4),11:(14,4)}
    for load in load_locations.keys():
        module=load_locations[load][0]
        contactor=load_locations[load][1]
        open_relay(client,module,contactor)
    return

def connect_all_der(client):
    der_locations={1:(11,2),2:(12,6),3:(12,2),4:(13,2),5:(14,6),6:(14,2)}
    for der in der_locations.keys():
        module=der_locations[der][0]
        contactor=der_locations[der][1]
        close_relay(client,module,contactor)
    return
    
def disconnect_all_der(client):
    der_locations={1:(11,2),2:(12,6),3:(12,2),4:(13,2),5:(14,6),6:(14,2)}
    for der in der_locations.keys():
        module=der_locations[der][0]
        contactor=der_locations[der][1]
        open_relay(client,module,contactor)
    return
