Beispiel #1
0
class PyModbusClient(BaseModbusClient):
    def __init__(self, *args, **kwargs):

        super(PyModbusClient, self).__init__(*args, **kwargs)

        if self.method == "tcp":
            from pymodbus.client.sync import ModbusTcpClient
            self.client = ModbusTcpClient(self.host, self.port)
        else:
            from pymodbus.client.sync import ModbusSerialClient
            argnames = ("stopbits", "bytesize", "parity", "baudrate",
                        "timeout")
            kwargs = dict((k, getattr(self, k)) for k in argnames)
            kwargs.update({
                "port": self.host,
            })
            self.client = ModbusSerialClient(self.method, **kwargs)

    def read_coils(self, address, count):
        resp = self.client.read_coils(address, count, unit=self.unit)
        if resp is None:
            raise NoDeviceResponse()
        return resp.bits[:count]

    def write_coil(self, address, value):
        resp = self.client.write_coil(address, int(value), unit=self.unit)
        if resp is None:
            raise NoDeviceResponse()
        return resp.value
Beispiel #2
0
class EPsolarTracerClient:
    ''' EPsolar Tracer client
    '''

    def __init__(self, unit = 1, serialclient = None, **kwargs):
        ''' Initialize a serial client instance
        '''
        self.unit = unit
        if serialclient == None:
            port = kwargs.get('port', '/dev/ttyXRUSB0')
            baudrate = kwargs.get('baudrate', 115200)
            self.client = ModbusClient(method = 'rtu', port = port, baudrate = baudrate, kwargs = kwargs)
        else:
            self.client = serialclient

    def connect(self):
        ''' Connect to the serial
        :returns: True if connection succeeded, False otherwise
        '''
        return self.client.connect()

    def close(self):
        ''' Closes the underlying connection
        '''
        return self.client.close()

    def read_device_info(self):
        request = ReadDeviceInformationRequest (unit = self.unit)
        response = self.client.execute(request)
        return response

    def read_input(self, name):
        register = registerByName(name)
        if register.is_coil():
            response = self.client.read_coils(register.address, register.size, unit = self.unit)
        elif register.is_discrete_input():
            response = self.client.read_discrete_inputs(register.address, register.size, unit = self.unit)
        elif register.is_input_register():
            response = self.client.read_input_registers(register.address, register.size, unit = self.unit)
        else:
            response = self.client.read_holding_registers(register.address, register.size, unit = self.unit)
        return register.decode(response)

    def write_output(self, name, value):
        register = registerByName(name)
        values = register.encode(value)
        response = False
        if register.is_coil():
            self.client.write_coil(register.address, values, unit = self.unit)
            response = True
        elif register.is_discrete_input():
            _logger.error("Cannot write discrete input " + repr(name))
            pass
        elif register.is_input_register():
            _logger.error("Cannot write input register " + repr(name))
            pass
        else:
            self.client.write_registers(register.address, values, unit = self.unit)
            response = True
        return response
Beispiel #3
0
class PyModbusClient(BaseModbusClient):
    
    def __init__(self, *args, **kwargs):
        
        super(PyModbusClient, self).__init__(*args, **kwargs)

        if self.method == "tcp":
            from pymodbus.client.sync import ModbusTcpClient
            self.client = ModbusTcpClient(self.host, self.port)
        else:
            from pymodbus.client.sync import ModbusSerialClient
            argnames = ("stopbits", "bytesize", "parity", "baudrate", "timeout")
            kwargs = dict((k, getattr(self, k)) for k in argnames)
            kwargs.update({
                "port": self.host,
            })
            self.client = ModbusSerialClient(self.method, **kwargs)
    
    def read_coils(self, address, count):
        resp = self.client.read_coils(address, count, unit=self.unit)
        if resp is None:
            raise NoDeviceResponse()
        return resp.bits[:count]
    
    def write_coil(self, address, value):
        resp = self.client.write_coil(address, int(value), unit=self.unit)
        if resp is None:
            raise NoDeviceResponse()
        return resp.value
Beispiel #4
0
def write_via_rtu_modbus(state):
    client = ModbusSerialClient(method='rtu',
                                port=PORT,
                                timeout=1,
                                baudrate=460800)
    log.debug("Writing Coils")
    rq = client.write_coil(1, state, unit=UNIT)
    log.debug(rq)
    log.debug("Reading Coils")
    rr = client.read_coils(1, 1, unit=UNIT)
    log.debug(rr)
    client.close()
Beispiel #5
0
class IOController():

    __client = None
    """Instance of the controller.
    """

    __coils = [False] * 12

    def __init__(self):

        self.__client = ModbusClient(method="rtu",
                                     port="COM5",
                                     timeout=1,
                                     stopbits=1,
                                     bytesize=8,
                                     parity="N",
                                     baudrate=9600)

        # Create a connection with the controller
        connection = self.__client.connect()

        if connection:
            print("Connected with the controller")
        else:
            print("No connection with controller")

    def set_gpio(self, pin, state):
        """Write coil if given token is whitelisted.

        Args:
            pin (int): Relay index
            state (bool): Relay state
        """

        # Pin is index 0 by default
        self.__coils[pin] = state
        response = self.__client.write_coils(0, self.__coils, unit=1)

        print("set_gpio({}, {})".format(pin, state))

        # Read all the coils
        response = self.__client.read_coils(address=0, count=12, unit=1)

        print(response.bits[:12])
Beispiel #6
0
def read_coils(unit, baud_value):
    """Function to read the coils.

    Args:
        unit (int): The ID of the device.
    """

    global client

    # Make a connection
    client = ModbusClient(method="rtu",
                          port="COM3",
                          timeout=0.5,
                          stopbits=1,
                          bytesize=8,
                          parity="N",
                          baudrate=baud_value)
    connection = client.connect()

    response = client.read_coils(address=16, count=4, unit=unit)

    print(response.bits[:4])
Beispiel #7
0
# examples how to write to coil registers 
# https://pymodbus.readthedocs.io/en/v1.3.2/examples/synchronous-client.html

from pymodbus.client.sync import ModbusSerialClient as ModbusClient
import logging
logging.basicConfig()
log = logging.getLogger()
log.setLevel(logging.DEBUG)

client = ModbusClient(method='rtu', port='/dev/ttyUSB0', timeout=1)
client.connect()

log.debug("Reading Coils")
# starting register, number of registers, slave unit id
rr = client.read_coils(12, 1, unit=0x01)

# read holding registers from register 1 to 45 next ones
hh = client.read_holding_registers(1,45,unit=0x01)

print "holding registers:"
print hh.registers

print "coild register:"
print rr.bits
print("{}: {}".format("summernight cooling status:", rr.bits[0]))


#write coil  
# turn on ylipaineistus/overpressure program
#rq = client.write_coil(10, 1, unit=0x01)
Beispiel #8
0
        logging.info("Holding registers: %s" % ex.registers)
    else:
        logging.error("Error pidiendo HRs")
        continue
    
    regs = ex.registers

    led_value = 0 if regs[0] == 1 else 1
    count += 1
    
    regs[2] = count
    regs[0] = led_value
    
    ex = client.write_registers(0, regs, unit=client_id)
    if ex is not None:
        logging.debug("Nuevo valor para el led: %d, respuesta: %s" % (led_value, ex))
    else:
        logging.error("Error seteando led con valor %d" % led_value)

    logging.info("%02d/%02d/%d %02d:%02d:%02d:\tLed %03s, Light: %s ohms, Counter: %d" % (regs[4], regs[5], regs[6], regs[7], regs[8], regs[9], ("ON" if led_value == 1 else "OFF"), regs[1], regs[3]))

    # testeo errores en invocacion a funcion invalida
    ex = client.read_coils(address=0, count=20, unit=client_id);
    if ex is not None:
        logging.debug("read_coils with error: %s" % ex)
    else:
        logging.error("Error invocando read_coils con argumentos invalidos")


client.close()
Beispiel #9
0
    def onHeartbeat(self):
        Domoticz.Log("onHeartbeat called")

        ########################################
        # SET HARDWARE - pymodbus: RTU / ASCII
        ########################################
        if (self.Domoticz_Setting_Communication_Mode == "rtu"
                or self.Domoticz_Setting_Communication_Mode == "ascii"):
            Domoticz.Debug("MODBUS DEBUG - INTERFACE: Port=" +
                           self.Domoticz_Setting_Serial_Port + ", BaudRate=" +
                           self.Domoticz_Setting_Baudrate + ", StopBits=" +
                           str(self.StopBits) + ", ByteSize=" +
                           str(self.ByteSize) + " Parity=" + self.Parity)
            Domoticz.Debug("MODBUS DEBUG - SETTINGS: Method=" +
                           self.Domoticz_Setting_Communication_Mode +
                           ", Device ID=" + self.Domoticz_Setting_Device_ID +
                           ", Register=" +
                           self.Domoticz_Setting_Register_Number +
                           ", Function=" +
                           self.Domoticz_Setting_Modbus_Function +
                           ", Data type=" + self.Domoticz_Setting_Data_Type +
                           ", Pollrate=" +
                           self.Domoticz_Setting_Device_Pollrate)
            try:
                client = ModbusSerialClient(
                    method=self.Domoticz_Setting_Communication_Mode,
                    port=self.Domoticz_Setting_Serial_Port,
                    stopbits=self.StopBits,
                    bytesize=self.ByteSize,
                    parity=self.Parity,
                    baudrate=int(self.Domoticz_Setting_Baudrate),
                    timeout=2,
                    retries=2)
            except:
                Domoticz.Error("Error opening Serial interface on " +
                               self.Domoticz_Setting_Serial_Port)
                Devices[1].Update(1, "0")  # Set value to 0 (error)

        ########################################
        # SET HARDWARE - pymodbus: RTU over TCP
        ########################################
        if (self.Domoticz_Setting_Communication_Mode == "rtutcp"):
            Domoticz.Debug("MODBUS DEBUG - INTERFACE: IP=" +
                           self.Domoticz_Setting_TCP_IP + ", Port=" +
                           self.Domoticz_Setting_TCP_PORT)
            Domoticz.Debug("MODBUS DEBUG - SETTINGS: Method=" +
                           self.Domoticz_Setting_Communication_Mode +
                           ", Device ID=" + self.Domoticz_Setting_Device_ID +
                           ", Register=" +
                           self.Domoticz_Setting_Register_Number +
                           ", Function=" +
                           self.Domoticz_Setting_Modbus_Function +
                           ", Data type=" + self.Domoticz_Setting_Data_Type +
                           ", Pollrate=" +
                           self.Domoticz_Setting_Device_Pollrate)
            try:
                client = ModbusTcpClient(host=self.Domoticz_Setting_TCP_IP,
                                         port=int(
                                             self.Domoticz_Setting_TCP_PORT),
                                         framer=ModbusRtuFramer,
                                         auto_open=True,
                                         auto_close=True,
                                         timeout=2)
            except:
                Domoticz.Error(
                    "Error opening RTU over TCP interface on address: " +
                    self.Domoticz_Setting_TCP_IPPORT)
                Devices[1].Update(1, "0")  # Set value to 0 (error)

        ########################################
        # SET HARDWARE - pymodbusTCP: TCP/IP
        ########################################
        if (self.Domoticz_Setting_Communication_Mode == "tcpip"):
            Domoticz.Debug("MODBUS DEBUG - INTERFACE: IP=" +
                           self.Domoticz_Setting_TCP_IP + ", Port=" +
                           self.Domoticz_Setting_TCP_PORT)
            Domoticz.Debug("MODBUS DEBUG - SETTINGS: Method=" +
                           self.Domoticz_Setting_Communication_Mode +
                           ", Device ID=" + self.Domoticz_Setting_Device_ID +
                           ", Register=" +
                           self.Domoticz_Setting_Register_Number +
                           ", Function=" +
                           self.Domoticz_Setting_Modbus_Function +
                           ", Data type=" + self.Domoticz_Setting_Data_Type +
                           ", Pollrate=" +
                           self.Domoticz_Setting_Device_Pollrate)
            try:
                client = ModbusClient(host=self.Domoticz_Setting_TCP_IP,
                                      port=int(self.Domoticz_Setting_TCP_PORT),
                                      unit_id=int(
                                          self.Domoticz_Setting_Device_ID),
                                      auto_open=True,
                                      auto_close=True,
                                      timeout=2)
            except:
                Domoticz.Error("Error opening TCP/IP interface on address: " +
                               self.Domoticz_Setting_TCP_IPPORT)
                Devices[1].Update(1, "0")  # Set value to 0 (error)

        ########################################
        # GET DATA - pymodbus: RTU / ASCII / RTU over TCP
        ########################################
        if (self.Domoticz_Setting_Communication_Mode == "rtu"
                or self.Domoticz_Setting_Communication_Mode == "ascii"
                or self.Domoticz_Setting_Communication_Mode == "rtutcp"):
            try:
                # Function to execute
                if (self.Domoticz_Setting_Modbus_Function == "1"):
                    data = client.read_coils(
                        int(self.Domoticz_Setting_Register_Number),
                        self.Register_Count,
                        unit=int(self.Domoticz_Setting_Device_ID))
                if (self.Domoticz_Setting_Modbus_Function == "2"):
                    data = client.read_discrete_inputs(
                        int(self.Domoticz_Setting_Register_Number),
                        self.Register_Count,
                        unit=int(self.Domoticz_Setting_Device_ID))
                if (self.Domoticz_Setting_Modbus_Function == "3"):
                    data = client.read_holding_registers(
                        int(self.Domoticz_Setting_Register_Number),
                        self.Register_Count,
                        unit=int(self.Domoticz_Setting_Device_ID))
                if (self.Domoticz_Setting_Modbus_Function == "4"):
                    data = client.read_input_registers(
                        int(self.Domoticz_Setting_Register_Number),
                        self.Register_Count,
                        unit=int(self.Domoticz_Setting_Device_ID))
                if (self.Read_Scale_Factor == 1):
                    decoder = BinaryPayloadDecoder.fromRegisters(
                        data, byteorder=Endian.Big, wordorder=Endian.Big)
                    decoder.skip_bytes((self.Register_Count - 1) * 2)
                    sf_value = decoder.decode_16bit_int()
                    data = data[0:self.Register_Count - 1]
                else:
                    sf_value = 0
                Domoticz.Debug("MODBUS DEBUG - RESPONSE: " + str(data))
            except:
                Domoticz.Error(
                    "Modbus error communicating! (RTU/ASCII/RTU over TCP), check your settings!"
                )
                Devices[1].Update(1, "0")  # Set value to 0 (error)

        ########################################
        # GET DATA - pymodbusTCP: TCP/IP
        ########################################
        if (self.Domoticz_Setting_Communication_Mode == "tcpip"):
            try:
                # Function to execute
                if (self.Domoticz_Setting_Modbus_Function == "1"):
                    data = client.read_coils(
                        int(self.Domoticz_Setting_Register_Number),
                        self.Register_Count)
                if (self.Domoticz_Setting_Modbus_Function == "2"):
                    data = client.read_discrete_inputs(
                        int(self.Domoticz_Setting_Register_Number),
                        self.Register_Count)
                if (self.Domoticz_Setting_Modbus_Function == "3"):
                    data = client.read_holding_registers(
                        int(self.Domoticz_Setting_Register_Number),
                        self.Register_Count)
                if (self.Domoticz_Setting_Modbus_Function == "4"):
                    data = client.read_input_registers(
                        int(self.Domoticz_Setting_Register_Number),
                        self.Register_Count)
                if (self.Read_Scale_Factor == 1):
                    decoder = BinaryPayloadDecoder.fromRegisters(
                        data, byteorder=Endian.Big, wordorder=Endian.Big)
                    decoder.skip_bytes((self.Register_Count - 1) * 2)
                    sf_value = decoder.decode_16bit_int()
                    data = data[0:self.Register_Count - 1]
                else:
                    sf_value = 0
                Domoticz.Debug("MODBUS DEBUG RESPONSE: " + str(data))
            except:
                Domoticz.Error(
                    "Modbus error communicating! (TCP/IP), check your settings!"
                )
                Devices[1].Update(1, "0")  # Set value to 0 (error)

        ########################################
        # DECODE DATA TYPE
        ########################################
        # pymodbus (RTU/ASCII/RTU over TCP) will reponse in ARRAY, no matter what values read e.g. MODBUS DEBUG RESPONSE: [2] = data.registers
        # pymodbusTCP (TCP/IP) will give the value back e.g. MODBUS DEBUG RESPONSE: [61, 44] = data
        if (self.Domoticz_Setting_Communication_Mode == "rtu"
                or self.Domoticz_Setting_Communication_Mode == "ascii"
                or self.Domoticz_Setting_Communication_Mode == "rtutcp"):
            try:
                Domoticz.Debug("MODBUS DEBUG - VALUE before conversion: " +
                               str(data.registers[0]))
                # Added option to swap bytes (little endian)
                if (self.Domoticz_Setting_Data_Type == "int16s"
                        or self.Domoticz_Setting_Data_Type == "uint16s"):
                    decoder = BinaryPayloadDecoder.fromRegisters(
                        data.registers,
                        byteorder=Endian.Little,
                        wordorder=Endian.Big)
                # Added option to swap words (little endian)
                elif (self.Domoticz_Setting_Data_Type == "int32s"
                      or self.Domoticz_Setting_Data_Type == "uint32s"
                      or self.Domoticz_Setting_Data_Type == "int64s"
                      or self.Domoticz_Setting_Data_Type == "uint64s"
                      or self.Domoticz_Setting_Data_Type == "float32s"
                      or self.Domoticz_Setting_Data_Type == "float64s"):
                    decoder = BinaryPayloadDecoder.fromRegisters(
                        data.registers,
                        byteorder=Endian.Big,
                        wordorder=Endian.Little)
                # Otherwise always big endian
                else:
                    decoder = BinaryPayloadDecoder.fromRegisters(
                        data.registers,
                        byteorder=Endian.Big,
                        wordorder=Endian.Big)
            except:
                Domoticz.Error(
                    "Modbus error decoding or received no data (RTU/ASCII/RTU over TCP)!, check your settings!"
                )
                Devices[1].Update(1, "0")  # Set value to 0 (error)

        if (self.Domoticz_Setting_Communication_Mode == "tcpip"):
            try:
                Domoticz.Debug("MODBUS DEBUG - VALUE before conversion: " +
                               str(data))
                #value = data[0]
                # Added option to swap bytes (little endian)
                if (self.Domoticz_Setting_Data_Type == "int16s"
                        or self.Domoticz_Setting_Data_Type == "uint16s"):
                    decoder = BinaryPayloadDecoder.fromRegisters(
                        data, byteorder=Endian.Little, wordorder=Endian.Big)
                # Added option to swap words (little endian)
                elif (self.Domoticz_Setting_Data_Type == "int32s"
                      or self.Domoticz_Setting_Data_Type == "uint32s"
                      or self.Domoticz_Setting_Data_Type == "int64s"
                      or self.Domoticz_Setting_Data_Type == "uint64s"
                      or self.Domoticz_Setting_Data_Type == "float32s"
                      or self.Domoticz_Setting_Data_Type == "float64s"):
                    decoder = BinaryPayloadDecoder.fromRegisters(
                        data, byteorder=Endian.Big, wordorder=Endian.Little)
                # Otherwise always big endian
                else:
                    decoder = BinaryPayloadDecoder.fromRegisters(
                        data, byteorder=Endian.Big, wordorder=Endian.Big)
            except:
                Domoticz.Error(
                    "Modbus error decoding or received no data (TCP/IP)!, check your settings!"
                )
                Devices[1].Update(1, "0")  # Set value to 0 (error)

        ########################################
        # DECODE DATA VALUE
        ########################################
        try:
            if (self.Domoticz_Setting_Data_Type == "noco"):
                value = data.registers[0]
            if (self.Domoticz_Setting_Data_Type == "bool"):
                value = bool(data.registers[0])
            if (self.Domoticz_Setting_Data_Type == "int8LSB"):
                ignored = decoder.skip_bytes(1)
                value = decoder.decode_8bit_int()
            if (self.Domoticz_Setting_Data_Type == "int8MSB"):
                value = decoder.decode_8bit_int()
            if (self.Domoticz_Setting_Data_Type == "int16"):
                value = decoder.decode_16bit_int()
            if (self.Domoticz_Setting_Data_Type == "int16s"):
                value = decoder.decode_16bit_int()
            if (self.Domoticz_Setting_Data_Type == "int32"):
                value = decoder.decode_32bit_int()
            if (self.Domoticz_Setting_Data_Type == "int32s"):
                value = decoder.decode_32bit_int()
            if (self.Domoticz_Setting_Data_Type == "int64"):
                value = decoder.decode_64bit_int()
            if (self.Domoticz_Setting_Data_Type == "int64s"):
                value = decoder.decode_64bit_int()
            if (self.Domoticz_Setting_Data_Type == "uint8LSB"):
                ignored = decoder.skip_bytes(1)
                value = decoder.decode_8bit_uint()
            if (self.Domoticz_Setting_Data_Type == "uint8MSB"):
                value = decoder.decode_8bit_uint()
            if (self.Domoticz_Setting_Data_Type == "uint16"):
                value = decoder.decode_16bit_uint()
            if (self.Domoticz_Setting_Data_Type == "uint16s"):
                value = decoder.decode_16bit_uint()
            if (self.Domoticz_Setting_Data_Type == "uint32"):
                value = decoder.decode_32bit_uint()
            if (self.Domoticz_Setting_Data_Type == "uint32s"):
                value = decoder.decode_32bit_uint()
            if (self.Domoticz_Setting_Data_Type == "uint64"):
                value = decoder.decode_64bit_uint()
            if (self.Domoticz_Setting_Data_Type == "uint64s"):
                value = decoder.decode_64bit_uint()
            if (self.Domoticz_Setting_Data_Type == "float32"):
                value = decoder.decode_32bit_float()
            if (self.Domoticz_Setting_Data_Type == "float32s"):
                value = decoder.decode_32bit_float()
            if (self.Domoticz_Setting_Data_Type == "float64"):
                value = decoder.decode_64bit_float()
            if (self.Domoticz_Setting_Data_Type == "float64s"):
                value = decoder.decode_64bit_float()
            if (self.Domoticz_Setting_Data_Type == "string2"):
                value = decoder.decode_string(2)
            if (self.Domoticz_Setting_Data_Type == "string4"):
                value = decoder.decode_string(4)
            if (self.Domoticz_Setting_Data_Type == "string6"):
                value = decoder.decode_string(6)
            if (self.Domoticz_Setting_Data_Type == "string8"):
                value = decoder.decode_string(8)

            # Apply a scale factor (decimal)
            if (self.Domoticz_Setting_Scale_Factor == "div0"):
                value = str(value)
            if (self.Domoticz_Setting_Scale_Factor == "div10"):
                value = str(round(value / 10, 1))
            if (self.Domoticz_Setting_Scale_Factor == "div100"):
                value = str(round(value / 100, 2))
            if (self.Domoticz_Setting_Scale_Factor == "div1000"):
                value = str(round(value / 1000, 3))
            if (self.Domoticz_Setting_Scale_Factor == "div10000"):
                value = str(round(value / 10000, 4))
            if (self.Domoticz_Setting_Scale_Factor == "mul10"):
                value = str(value * 10)
            if (self.Domoticz_Setting_Scale_Factor == "mul100"):
                value = str(value * 100, 2)
            if (self.Domoticz_Setting_Scale_Factor == "mul1000"):
                value = str(value * 1000, 3)
            if (self.Domoticz_Setting_Scale_Factor == "mul10000"):
                value = str(value * 10000, 4)
            if (self.Domoticz_Setting_Scale_Factor == "sfnextreg"):
                if (sf_value == 0): value = str(value)
                if (sf_value == 1): value = str(round(value * 10, 1))
                if (sf_value == 2): value = str(round(value * 100, 1))
                if (sf_value == -1): value = str(round(value / 10, 1))
                if (sf_value == -2): value = str(round(value / 100, 1))
            Domoticz.Debug("MODBUS DEBUG - VALUE after conversion: " +
                           str(value))
            Devices[1].Update(1, value)  # Update value

        except:
            Domoticz.Error(
                "Modbus error decoding or received no data!, check your settings!"
            )
            Devices[1].Update(1, "0")  # Set value to 0 (error)
Beispiel #10
0
response = client.execute(request)
print repr(response.information)

for reg in registers:
    print
    print "reg.address: %x" % reg.address
    rr = client.read_input_registers(reg.address, 1, unit=1)
    if hasattr(rr, "getRegister"):
        print "read_input_registers:", rr.getRegister(0)
    else:
        print "read_input_registers", str(rr)
    rr = client.read_holding_registers(reg.address, 1, unit=1)
    if hasattr(rr, "getRegister"):
        print "read_holding_registers:", rr.getRegister(0)
    else:
        print "read_holding_registers:", str(rr)

for reg in coils:
    print
    print reg
    rr = client.read_coils(reg.address, unit=1)
    if hasattr(rr, "bits"):
        print "read_coils:", str(rr.bits)
    else:
        print "read_coils:", str(rr)
    rr = client.read_discrete_inputs(reg.address, unit=1)
    if hasattr(rr, "bits"):
        print "read_discrete_inputs:", str(rr.bits)
    else:
        print "read_discrete_inputs:", str(rr)
Beispiel #11
0
#Connect to the serial modbus server
connection = client.connect()
print(connection)

#Starting add, num of reg to read, slave unit.
# result= client.read_holding_registers(0x00, 5 ,unit= 0x01)
# print(result)

#Starting add, num of reg to read, slave unit.
t1 = time.perf_counter()
for x in range(0, 1):
    #print ("sending..")
    #time.sleep(1)
    # result= client.read_holding_registers(41,1,unit= 1)
    #print(result)
    result= client.read_coils(0,1,unit=1)
    #result=client.read_discrete_inputs(40132,3,unit=1)
    # result=client.read_input_registers(251,2,unit=1)
    #result=client.write_coil(3,1,unit=1)
    #result=client.write_register(11,70000,unit=1)
    #result=client.write_coils(1, [1,0,1], unit= 0x01)
    #result=client.write_registers(1, [1,2,3], unit= 0x01)

t2 = time.perf_counter()

print('Time %f' % (t2 - t1))

# result= client.read_holding_registers(1, 10 ,unit= 0x0a)
# print(result)
#rr = client.read_discrete_inputs(1, 1, unit=0x01)
#print(rr)
Beispiel #12
0
class EPsolarTracerClient:
    ''' EPsolar Tracer client
    '''

    def __init__(self, unit=1, serialclient=None, **kwargs):
        ''' Initialize a serial client instance
        '''
        self.unit = unit
        if serialclient is None:
            port = kwargs.get('port', 'COM1')
            baudrate = kwargs.get('baudrate', 115200)
            self.client = ModbusClient(
                method="rtu",
                port=port,
                stopbits=1,
                bytesize=8,
                parity='N',
                baudrate=baudrate,
                timeout = 1.0
            )
        else:
            self.client = serialclient

    def connect(self):
        ''' Connect to the serial
        :returns: True if connection succeeded, False otherwise
        '''
        cc = self.client.connect()
        if cc is False:
            print("Unable to open port. Quitting")
            quit()

        return cc

    def close(self):
        ''' Closes the underlying connection
        '''
        return self.client.close()

    def read_device_info(self):
        #request = ReadDeviceInformationRequest(unit = self.unit)
        request = ReadDeviceInformationRequest(unit=self.unit)
        response = self.client.execute(request)
        return response

    def read_input(self, name):
        register = registerByName(name)
        if register.is_coil():
            response = self.client.read_coils(register.address, register.size, unit=self.unit)
        elif register.is_discrete_input():
            response = self.client.read_discrete_inputs(register.address, register.size, unit=self.unit)
        elif register.is_input_register():
            response = self.client.read_input_registers(register.address, register.size, unit=self.unit)
        else:
            response = self.client.read_holding_registers(register.address, register.size, unit=self.unit)
        return register.decode(response)

    def write_output(self, name, value):
        register = registerByName(name)
        values = register.encode(value)
        response = False
        if register.is_coil():
            self.client.write_coil(register.address, values, unit=self.unit)
            response = True
        elif register.is_discrete_input():
            log.error("Cannot write discrete input " + repr(name))
            pass
        elif register.is_input_register():
            log.error("Cannot write input register " + repr(name))
            pass
        else:
            self.client.write_registers(register.address, values, unit=self.unit)
            response = True
        return response

    def __enter__(self):
        self.connect()
        print("Context mngr connect")
        return self
    def __exit__(self,type,value,traceback):
        self.close()
        print("Context mngr close")
Beispiel #13
0
    def onHeartbeat(self):
        #Domoticz.Log("onHeartbeat called")

        # Wich serial port settings to use?
        if (Parameters["Mode3"] == "S1B7PN"):
            StopBits, ByteSize, Parity = 1, 7, "N"
        if (Parameters["Mode3"] == "S1B7PE"):
            StopBits, ByteSize, Parity = 1, 7, "E"
        if (Parameters["Mode3"] == "S1B7PO"):
            StopBits, ByteSize, Parity = 1, 7, "O"
        if (Parameters["Mode3"] == "S1B8PN"):
            StopBits, ByteSize, Parity = 1, 8, "N"
        if (Parameters["Mode3"] == "S1B8PE"):
            StopBits, ByteSize, Parity = 1, 8, "E"
        if (Parameters["Mode3"] == "S1B8PO"):
            StopBits, ByteSize, Parity = 1, 8, "O"
        if (Parameters["Mode3"] == "S2B7PN"):
            StopBits, ByteSize, Parity = 2, 7, "N"
        if (Parameters["Mode3"] == "S2B7PE"):
            StopBits, ByteSize, Parity = 2, 7, "E"
        if (Parameters["Mode3"] == "S2B7PO"):
            StopBits, ByteSize, Parity = 2, 7, "O"
        if (Parameters["Mode3"] == "S2B8PN"):
            StopBits, ByteSize, Parity = 2, 8, "N"
        if (Parameters["Mode3"] == "S2B8PE"):
            StopBits, ByteSize, Parity = 2, 8, "E"
        if (Parameters["Mode3"] == "S2B8PO"):
            StopBits, ByteSize, Parity = 2, 8, "O"

        # How many registers to read (depending on data type)?
        # Added additional options for byte/word swapping
        registercount = 1  # Default
        if (Parameters["Mode6"] == "noco"): registercount = 1
        if (Parameters["Mode6"] == "int8LSB"): registercount = 1
        if (Parameters["Mode6"] == "int8MSB"): registercount = 1
        if (Parameters["Mode6"] == "int16"): registercount = 1
        if (Parameters["Mode6"] == "int16s"): registercount = 1
        if (Parameters["Mode6"] == "int32"): registercount = 2
        if (Parameters["Mode6"] == "int32s"): registercount = 2
        if (Parameters["Mode6"] == "int64"): registercount = 4
        if (Parameters["Mode6"] == "int64s"): registercount = 4
        if (Parameters["Mode6"] == "uint8LSB"): registercount = 1
        if (Parameters["Mode6"] == "uint8MSB"): registercount = 1
        if (Parameters["Mode6"] == "uint16"): registercount = 1
        if (Parameters["Mode6"] == "uint16s"): registercount = 1
        if (Parameters["Mode6"] == "uint32"): registercount = 2
        if (Parameters["Mode6"] == "uint32s"): registercount = 2
        if (Parameters["Mode6"] == "uint64"): registercount = 4
        if (Parameters["Mode6"] == "uint64s"): registercount = 4
        if (Parameters["Mode6"] == "float32"): registercount = 2
        if (Parameters["Mode6"] == "float32s"): registercount = 2
        if (Parameters["Mode6"] == "float64"): registercount = 4
        if (Parameters["Mode6"] == "float64s"): registercount = 4
        if (Parameters["Mode6"] == "string2"): registercount = 2
        if (Parameters["Mode6"] == "string4"): registercount = 4
        if (Parameters["Mode6"] == "string6"): registercount = 6
        if (Parameters["Mode6"] == "string8"): registercount = 8

        # Split address to support TCP/IP device ID
        AddressData = Parameters["Address"].split("/")  # Split on "/"
        UnitAddress = AddressData[0]

        # Is there a unit ID given after the IP? (e.g. 192.168.2.100/56)
        UnitIdForIp = 1  # Default
        if len(AddressData) > 1:
            UnitIdForIp = AddressData[1]

        ###################################
        # pymodbus: RTU / ASCII
        ###################################
        if (Parameters["Mode1"] == "rtu" or Parameters["Mode1"] == "ascii"):
            Domoticz.Debug("MODBUS DEBUG USB SERIAL HW - Port=" +
                           Parameters["SerialPort"] + ", BaudRate=" +
                           Parameters["Mode2"] + ", StopBits=" +
                           str(StopBits) + ", ByteSize=" + str(ByteSize) +
                           " Parity=" + Parity)
            Domoticz.Debug("MODBUS DEBUG USB SERIAL CMD - Method=" +
                           Parameters["Mode1"] + ", Address=" + UnitAddress +
                           ", Register=" + Parameters["Password"] +
                           ", Function=" + Parameters["Username"] +
                           ", Data type=" + Parameters["Mode6"])
            try:
                client = ModbusSerialClient(method=Parameters["Mode1"],
                                            port=Parameters["SerialPort"],
                                            stopbits=StopBits,
                                            bytesize=ByteSize,
                                            parity=Parity,
                                            baudrate=int(Parameters["Mode2"]),
                                            timeout=1,
                                            retries=2)
            except:
                Domoticz.Log("Error opening Serial interface on " +
                             Parameters["SerialPort"])
                Devices[1].Update(0, "0")  # Update device in Domoticz

        ###################################
        # pymodbus: RTU over TCP
        ###################################
        if (Parameters["Mode1"] == "rtutcp"):
            Domoticz.Debug("MODBUS DEBUG TCP CMD - Method=" +
                           Parameters["Mode1"] + ", Address=" + UnitAddress +
                           ", Port=" + Parameters["Port"] + ", Register=" +
                           Parameters["Password"] + ", Data type=" +
                           Parameters["Mode6"])
            try:
                client = ModbusTcpClient(host=UnitAddress,
                                         port=int(Parameters["Port"]),
                                         framer=ModbusRtuFramer,
                                         auto_open=True,
                                         auto_close=True,
                                         timeout=5)
            except:
                Domoticz.Log("Error opening TCP interface on address: " +
                             UnitAddress)
                Devices[1].Update(0, "0")  # Update device in Domoticz

        ###################################
        # pymodbusTCP: TCP/IP
        ###################################
        if (Parameters["Mode1"] == "tcpip"):
            Domoticz.Debug("MODBUS DEBUG TCP CMD - Method=" +
                           Parameters["Mode1"] + ", Address=" + UnitAddress +
                           ", Port=" + Parameters["Port"] + ", Unit ID=" +
                           UnitIdForIp + ", Register=" +
                           Parameters["Password"] + ", Data type=" +
                           Parameters["Mode6"])
            try:
                client = ModbusClient(host=UnitAddress,
                                      port=int(Parameters["Port"]),
                                      unit_id=UnitIdForIp,
                                      auto_open=True,
                                      auto_close=True,
                                      timeout=5)
            except:
                Domoticz.Log("Error opening TCP/IP interface on address: " +
                             UnitAddress)
                Devices[1].Update(0, "0")  # Update device in Domoticz

        ###################################
        # pymodbus section
        ###################################
        if (Parameters["Mode1"] == "rtu" or Parameters["Mode1"] == "ascii"
                or Parameters["Mode1"] == "rtutcp"):
            try:
                # Which function to execute? RTU/ASCII/RTU over TCP
                if (Parameters["Username"] == "1"):
                    data = client.read_coils(int(Parameters["Password"]),
                                             registercount,
                                             unit=int(UnitIdForIp))
                if (Parameters["Username"] == "2"):
                    data = client.read_discrete_inputs(int(
                        Parameters["Password"]),
                                                       registercount,
                                                       unit=int(UnitIdForIp))
                if (Parameters["Username"] == "3"):
                    data = client.read_holding_registers(int(
                        Parameters["Password"]),
                                                         registercount,
                                                         unit=int(UnitIdForIp))
                if (Parameters["Username"] == "4"):
                    data = client.read_input_registers(int(
                        Parameters["Password"]),
                                                       registercount,
                                                       unit=int(UnitIdForIp))
                Domoticz.Debug("MODBUS DEBUG RESPONSE: " + str(data))
            except:
                Domoticz.Log(
                    "Modbus error communicating! (RTU/ASCII/RTU over TCP), check your settings!"
                )
                Devices[1].Update(0, "0")  # Update device to OFF in Domoticz

            try:
                # How to decode the input?
                # Added option to swap bytes (little endian)
                if (Parameters["Mode6"] == "int16s"
                        or Parameters["Mode6"] == "uint16s"):
                    decoder = BinaryPayloadDecoder.fromRegisters(
                        data, byteorder=Endian.Little, wordorder=Endian.Big)
                # Added option to swap words (little endian)
                elif (Parameters["Mode6"] == "int32s"
                      or Parameters["Mode6"] == "uint32s"
                      or Parameters["Mode6"] == "int64s"
                      or Parameters["Mode6"] == "uint64s"
                      or Parameters["Mode6"] == "float32s"
                      or Parameters["Mode6"] == "float64s"):
                    decoder = BinaryPayloadDecoder.fromRegisters(
                        data, byteorder=Endian.Big, wordorder=Endian.Little)
                # Otherwise always big endian
                else:
                    decoder = BinaryPayloadDecoder.fromRegisters(
                        data, byteorder=Endian.Big, wordorder=Endian.Big)

                if (Parameters["Mode6"] == "noco"): value = data
                if (Parameters["Mode6"] == "int8LSB"):
                    ignored = decoder.skip_bytes(1)
                    value = decoder.decode_8bit_int()
                if (Parameters["Mode6"] == "int8MSB"):
                    value = decoder.decode_8bit_int()
                if (Parameters["Mode6"] == "int16"):
                    value = decoder.decode_16bit_int()
                if (Parameters["Mode6"] == "int16s"):
                    value = decoder.decode_16bit_int()
                if (Parameters["Mode6"] == "int32"):
                    value = decoder.decode_32bit_int()
                if (Parameters["Mode6"] == "int32s"):
                    value = decoder.decode_32bit_int()
                if (Parameters["Mode6"] == "int64"):
                    value = decoder.decode_64bit_int()
                if (Parameters["Mode6"] == "int64s"):
                    value = decoder.decode_64bit_int()
                if (Parameters["Mode6"] == "uint8LSB"):
                    ignored = decoder.skip_bytes(1)
                    value = decoder.decode_8bit_uint()
                if (Parameters["Mode6"] == "uint8MSB"):
                    value = decoder.decode_8bit_uint()
                if (Parameters["Mode6"] == "uint16"):
                    value = decoder.decode_16bit_uint()
                if (Parameters["Mode6"] == "uint16s"):
                    value = decoder.decode_16bit_uint()
                if (Parameters["Mode6"] == "uint32"):
                    value = decoder.decode_32bit_uint()
                if (Parameters["Mode6"] == "uint32s"):
                    value = decoder.decode_32bit_uint()
                if (Parameters["Mode6"] == "uint64"):
                    value = decoder.decode_64bit_uint()
                if (Parameters["Mode6"] == "uint64s"):
                    value = decoder.decode_64bit_uint()
                if (Parameters["Mode6"] == "float32"):
                    value = decoder.decode_32bit_float()
                if (Parameters["Mode6"] == "float32s"):
                    value = decoder.decode_32bit_float()
                if (Parameters["Mode6"] == "float64"):
                    value = decoder.decode_64bit_float()
                if (Parameters["Mode6"] == "float64s"):
                    value = decoder.decode_64bit_float()
                if (Parameters["Mode6"] == "string2"):
                    value = decoder.decode_string(2)
                if (Parameters["Mode6"] == "string4"):
                    value = decoder.decode_string(4)
                if (Parameters["Mode6"] == "string6"):
                    value = decoder.decode_string(6)
                if (Parameters["Mode6"] == "string8"):
                    value = decoder.decode_string(8)
                Domoticz.Debug("MODBUS DEBUG VALUE: " + str(value))

                # Divide the value (decimal)?
                if (Parameters["Mode5"] == "div0"): value = str(value)
                if (Parameters["Mode5"] == "div10"):
                    value = str(round(value / 10, 1))
                if (Parameters["Mode5"] == "div100"):
                    value = str(round(value / 100, 2))
                if (Parameters["Mode5"] == "div1000"):
                    value = str(round(value / 1000, 3))
                if (Parameters["Mode5"] == "div10000"):
                    value = str(round(value / 10000, 4))

                Devices[1].Update(0, value)  # Update value in Domoticz

            except:
                Domoticz.Log(
                    "Modbus error decoding or received no data (RTU/ASCII/RTU over TCP)!, check your settings!"
                )
                Devices[1].Update(0, "0")  # Update value in Domoticz

        ###################################
        # pymodbusTCP section
        ###################################
        if (Parameters["Mode1"] == "tcpip"):
            try:
                # Which function to execute? TCP/IP
                if (Parameters["Username"] == "1"):
                    data = client.read_coils(int(Parameters["Password"]),
                                             registercount)
                if (Parameters["Username"] == "2"):
                    data = client.read_discrete_inputs(
                        int(Parameters["Password"]), registercount)
                if (Parameters["Username"] == "3"):
                    data = client.read_holding_registers(
                        int(Parameters["Password"]), registercount)
                if (Parameters["Username"] == "4"):
                    data = client.read_input_registers(
                        int(Parameters["Password"]), registercount)
                Domoticz.Debug("MODBUS DEBUG RESPONSE: " + str(data))
            except:
                Domoticz.Log(
                    "Modbus error communicating! (TCP/IP), check your settings!"
                )
                Devices[1].Update(0, "0")  # Update device to OFF in Domoticz

            try:
                # How to decode the input?
                # Added option to swap bytes (little endian)
                if (Parameters["Mode6"] == "int16s"
                        or Parameters["Mode6"] == "uint16s"):
                    decoder = BinaryPayloadDecoder.fromRegisters(
                        data.registers,
                        byteorder=Endian.Little,
                        wordorder=Endian.Big)
                # Added option to swap words (little endian)
                elif (Parameters["Mode6"] == "int32s"
                      or Parameters["Mode6"] == "uint32s"
                      or Parameters["Mode6"] == "int64s"
                      or Parameters["Mode6"] == "uint64s"
                      or Parameters["Mode6"] == "float32s"
                      or Parameters["Mode6"] == "float64s"):
                    decoder = BinaryPayloadDecoder.fromRegisters(
                        data.registers,
                        byteorder=Endian.Big,
                        wordorder=Endian.Little)
                # Otherwise always big endian
                else:
                    decoder = BinaryPayloadDecoder.fromRegisters(
                        data.registers,
                        byteorder=Endian.Big,
                        wordorder=Endian.Big)

                if (Parameters["Mode6"] == "noco"): value = data
                if (Parameters["Mode6"] == "int8LSB"):
                    ignored = decoder.skip_bytes(1)
                    value = decoder.decode_8bit_int()
                if (Parameters["Mode6"] == "int8MSB"):
                    value = decoder.decode_8bit_int()
                if (Parameters["Mode6"] == "int16"):
                    value = decoder.decode_16bit_int()
                if (Parameters["Mode6"] == "int16s"):
                    value = decoder.decode_16bit_int()
                if (Parameters["Mode6"] == "int32"):
                    value = decoder.decode_32bit_int()
                if (Parameters["Mode6"] == "int32s"):
                    value = decoder.decode_32bit_int()
                if (Parameters["Mode6"] == "int64"):
                    value = decoder.decode_64bit_int()
                if (Parameters["Mode6"] == "int64s"):
                    value = decoder.decode_64bit_int()
                if (Parameters["Mode6"] == "uint8LSB"):
                    ignored = decoder.skip_bytes(1)
                    value = decoder.decode_8bit_uint()
                if (Parameters["Mode6"] == "uint8MSB"):
                    value = decoder.decode_8bit_uint()
                if (Parameters["Mode6"] == "uint16"):
                    value = decoder.decode_16bit_uint()
                if (Parameters["Mode6"] == "uint16s"):
                    value = decoder.decode_16bit_uint()
                if (Parameters["Mode6"] == "uint32"):
                    value = decoder.decode_32bit_uint()
                if (Parameters["Mode6"] == "uint32s"):
                    value = decoder.decode_32bit_uint()
                if (Parameters["Mode6"] == "uint64"):
                    value = decoder.decode_64bit_uint()
                if (Parameters["Mode6"] == "uint64s"):
                    value = decoder.decode_64bit_uint()
                if (Parameters["Mode6"] == "float32"):
                    value = decoder.decode_32bit_float()
                if (Parameters["Mode6"] == "float32s"):
                    value = decoder.decode_32bit_float()
                if (Parameters["Mode6"] == "float64"):
                    value = decoder.decode_64bit_float()
                if (Parameters["Mode6"] == "float64s"):
                    value = decoder.decode_64bit_float()
                if (Parameters["Mode6"] == "string2"):
                    value = decoder.decode_string(2)
                if (Parameters["Mode6"] == "string4"):
                    value = decoder.decode_string(4)
                if (Parameters["Mode6"] == "string6"):
                    value = decoder.decode_string(6)
                if (Parameters["Mode6"] == "string8"):
                    value = decoder.decode_string(8)
                Domoticz.Debug("MODBUS DEBUG VALUE: " + str(value))

                # Divide the value (decimal)?
                if (Parameters["Mode5"] == "div0"): value = str(value)
                if (Parameters["Mode5"] == "div10"):
                    value = str(round(value / 10, 1))
                if (Parameters["Mode5"] == "div100"):
                    value = str(round(value / 100, 2))
                if (Parameters["Mode5"] == "div1000"):
                    value = str(round(value / 1000, 3))
                if (Parameters["Mode5"] == "div10000"):
                    value = str(round(value / 10000, 4))

                if (value != "0"):
                    Devices[1].Update(1, value)  # Update value in Domoticz

            except:
                Domoticz.Log(
                    "Modbus error decoding or received no data (TCP/IP)!, check your settings!"
                )
                Devices[1].Update(0, "0")  # Update value in Domoticz
class modbusHandler:
    def __init__(self, type, tcpIp, tcpPort, Method, Port, Stopbits, Bytesize,
                 Parity, Baudrate):
        self.modValConverter = ModValConverter()
        self.exceptionHandler = ModbusHandlerExceptions()
        self.tcpNumberOfRetries = 20

        if (type == "TCP"):
            self.ModbusClient = ModbusTcpClient(tcpIp, tcpPort, timeout=0.5)
        else:
            if (type == "RTU"):
                if (len(Port) == 0):
                    self.exceptionHandler.generateException(
                        "NoPortSpecifiedError")
                self.ModbusClient = ModbusClient(method=Method,
                                                 port=Port,
                                                 stopbits=Stopbits,
                                                 bytesize=Bytesize,
                                                 parity=Parity,
                                                 baudrate=Baudrate,
                                                 timeout=1)
        self.ModbusClient.register(self.ReadFifoRequest.ReadFifoResponse)
        self.ModbusClient.register(self.Read2FifosRequest.Read2FifosResponse)
        self.ModbusClient.register(
            self.ReadFifoAndTimeRequest.ReadFifoAndTimeResponse)

    def setNumberOfRetriesTCP(self, number):
        self.tcpNumberOfRetries = number

    class DataOut:
        registers = []

    class DataOutTwoRegs:
        registers0 = []
        registers1 = []

    class Read2FifosRequest(ModbusRequest):
        function_code = 66
        _rtu_frame_size = 8

        class Read2FifosResponse(ModbusResponse):
            function_code = 65
            _rtu_byte_count_pos = 3

            def __init__(self, values=None, **kwargs):
                ModbusResponse.__init__(self, **kwargs)
                self.values = values or []

            def encode(self):
                result = bytes([len(self.values) * 2])
                for register in self.values:
                    result += struct.pack('>H', register)
                return result

            def decode(self, data):
                byte_count = int(data[1])
                self.values = []
                for i in range(2, byte_count + 1, 2):
                    self.values.append(struct.unpack('>H', data[i:i + 2])[0])

        def __init__(self, address=None, **kwargs):
            ModbusRequest.__init__(self, **kwargs)
            self.address = address
            self.count = 2

        def encode(self):
            return struct.pack('>HH', self.address, self.count)

        def decode(self, data):
            self.address, self.count = struct.unpack('>HH', data)

        def execute(self, context):
            if not (1 <= self.count <= 0x7d0):
                return self.doException(ModbusExceptions.IllegalValue)
            if not context.validate(self.function_code, self.address,
                                    self.count):
                return self.doException(ModbusExceptions.IllegalAddress)
            values = context.getValues(self.function_code, self.address,
                                       self.count)
            return self.Read2FifosResponse(values)

    class ReadFifoRequest(ModbusRequest):

        function_code = 66
        _rtu_frame_size = 8

        class ReadFifoResponse(ModbusResponse):
            function_code = 24
            _rtu_byte_count_pos = 3

            def __init__(self, values=None, **kwargs):
                ModbusResponse.__init__(self, **kwargs)
                self.values = values or []

            def encode(self):
                """ Encodes response pdu

                :returns: The encoded packet message
                """
                # print(len(self.values))
                result = bytes([len(self.values) * 2])
                for register in self.values:
                    result += struct.pack('>H', register)
                return result

            def decode(self, data):
                """ Decodes response pdu

                :param data: The packet data to decode
                """
                # print(data)
                byte_count = int(data[1])
                self.values = []
                for i in range(2, byte_count + 1, 2):
                    self.values.append(struct.unpack('>H', data[i:i + 2])[0])

    class ReadFifoAndTimeRequest(ModbusRequest):

        function_code = 67

        # _rtu_frame_size = 8
        # fifoFreq = 100
        class ReadFifoAndTimeResponse(ModbusResponse):
            function_code = 67
            _rtu_double_byte_count_pos = 10

            def __init__(self, values=None, **kwargs):
                ModbusResponse.__init__(self, **kwargs)
                self.values = values or []
                # print(kwargs)

            def encode(self):
                """ Encodes response pdu

                :returns: The encoded packet message
                """
                return self.values

            def decode(self, data):
                """ Decodes response pdu

                :param data: The packet data to decode
                """
                timeFromStart = struct.unpack('>Q', data[0:8])[0]
                byte_count = struct.unpack('>H', data[8:10])[0]
                # print(data.hex())
                # print(timeFromStart)

                # print(byte_count)
                byteCounter = 10
                fifoAllRegs = []
                sampleFreqs = []

                while (byteCounter - 6 < byte_count):
                    sampleFreqs.append(
                        struct.unpack('>H',
                                      data[byteCounter:byteCounter + 2])[0])
                    byteCounter = byteCounter + 2
                    nextRegCount = struct.unpack(
                        '>H', data[byteCounter:byteCounter + 2])[0]
                    byteCounter = byteCounter + 2
                    fifoRegs = []

                    for i in range(nextRegCount):
                        fifoRegs.append(
                            struct.unpack(
                                '>H', data[byteCounter + i * 2:byteCounter +
                                           i * 2 + 2])[0])
                        # fifoTimes.append(timeFromStart - (1/self.fifoFreq)*1000000*i)
                    byteCounter = byteCounter + nextRegCount * 2

                    fifoAllRegs.append(fifoRegs)
                # print(fifoAllRegs)

                self.values = [timeFromStart, fifoAllRegs, sampleFreqs]

        def __init__(self, address=None, count=1, **kwargs):
            ModbusRequest.__init__(self, **kwargs)
            self.address = address
            self.count = count
            # print(kwargs)

        def encode(self):
            return struct.pack('>HH', self.address, self.count)

        def decode(self, data):
            self.address, self.count = struct.unpack('>HH', data)

        def execute(self, context):
            if not (1 <= self.count <= 0x7d0):
                return self.doException(ModbusExceptions.IllegalValue)
            if not context.validate(self.function_code, self.address,
                                    self.count):
                return self.doException(ModbusExceptions.IllegalAddress)
            values = context.getValues(self.function_code, self.address,
                                       self.count)
            return self.ReadFifoResponse(values)

    def connect(self):
        self.ModbusClient.connect()

    def isSlaveIsNotResponding(self, result):
        if (type(result) == pymodbus.exceptions.ModbusIOException):
            return True
        return False

    def writeCoils(self, addresS, valuE, uniT):
        addresS = addresS - 1  # when I ask 30001, python sends request for 30002, why??? Bug???
        for x in range(self.tcpNumberOfRetries):
            try:
                result = self.ModbusClient.write_coils(address=addresS,
                                                       values=valuE,
                                                       unit=uniT)
                if (not self.isSlaveIsNotResponding(result)):
                    break
            except pymodbus.exceptions.ConnectionException:
                pass
        if (type(result) == pymodbus.exceptions.ModbusIOException):
            self.exceptionHandler.generateException("ModbusIOError")
        return result

    def write16BitUnsignedRegister(self, addresS, valuE, uniT):
        addresS = addresS - 1  # when I ask 30001, python sends request for 30002, why??? Bug???
        for x in range(self.tcpNumberOfRetries):
            try:
                result = self.ModbusClient.write_register(address=addresS,
                                                          value=valuE,
                                                          unit=uniT)
                if (not self.isSlaveIsNotResponding(result)):
                    break
            except pymodbus.exceptions.ConnectionException:
                pass
        if (type(result) == pymodbus.exceptions.ModbusIOException):
            self.exceptionHandler.generateException("ModbusIOError")
        return result

    def write16BitUnsignedRegisters(self, addresS, valuE, uniT):
        addresS = addresS - 1  # when I ask 30001, python sends request for 30002, why??? Bug???
        for x in range(self.tcpNumberOfRetries):
            try:
                result = self.ModbusClient.write_registers(address=addresS,
                                                           values=valuE,
                                                           unit=uniT)
                if (not self.isSlaveIsNotResponding(result)):
                    break
            except pymodbus.exceptions.ConnectionException:
                pass
        if (type(result) == pymodbus.exceptions.ModbusIOException):
            self.exceptionHandler.generateException("ModbusIOError")
        return result

    def readCoils(self, addresS, counT, uniT):
        addresS = addresS - 1  # when I ask 30001, python sends request for 30002, why??? Bug???
        for x in range(self.tcpNumberOfRetries):
            try:
                result = self.ModbusClient.read_coils(address=addresS,
                                                      count=counT,
                                                      unit=uniT)
                if (not self.isSlaveIsNotResponding(result)):
                    break
            except pymodbus.exceptions.ConnectionException:
                pass
        if (type(result) == pymodbus.exceptions.ModbusIOException):
            self.exceptionHandler.generateException("ModbusIOError")
        return result

    def readDiscreteInputs(self, addresS, counT, uniT):
        addresS = addresS - 1  # when I ask 30001, python sends request for 30002, why??? Bug???
        for x in range(self.tcpNumberOfRetries):
            try:
                result = self.ModbusClient.read_discrete_inputs(
                    address=addresS, count=counT, unit=uniT)
                if (not self.isSlaveIsNotResponding(result)):
                    break
            except pymodbus.exceptions.ConnectionException:
                pass
        if (type(result) == pymodbus.exceptions.ModbusIOException):
            self.exceptionHandler.generateException("ModbusIOError")
        return result

    def readInputRegisters(self, addresS, counT, uniT):
        addresS = addresS - 1  # when I ask 30001, python sends request for 30002, why??? Bug???
        for x in range(self.tcpNumberOfRetries):
            try:
                result = self.ModbusClient.read_input_registers(
                    address=addresS, count=counT, unit=uniT)
                if (not self.isSlaveIsNotResponding(result)):
                    break
            except pymodbus.exceptions.ConnectionException:
                pass
        if (type(result) == pymodbus.exceptions.ModbusIOException):
            self.exceptionHandler.generateException("ModbusIOError")
        return result

    def readHoldingRegisters(self, addresS, counT, uniT):
        addresS = addresS - 1  # when I ask 30001, python sends request for 30002, why??? Bug???
        for x in range(self.tcpNumberOfRetries):
            try:
                result = self.ModbusClient.read_holding_registers(
                    address=addresS, count=counT, unit=uniT)
                if (not self.isSlaveIsNotResponding(result)):
                    break
            except pymodbus.exceptions.ConnectionException:
                pass
        if (type(result) == pymodbus.exceptions.ModbusIOException):
            self.exceptionHandler.generateException("ModbusIOError")
        return result

    def getFifoAndTime(self, addresS, number, uniT):
        addresS = addresS - 1  # when I ask 30001, python sends request for 30002, why??? Bug???

        for x in range(self.tcpNumberOfRetries):
            # print(x)
            try:
                request = self.ReadFifoAndTimeRequest(address=addresS,
                                                      count=number,
                                                      unit=uniT)
                result = self.ModbusClient.execute(request)
                if (not self.isSlaveIsNotResponding(result)):
                    break
            except pymodbus.exceptions.ConnectionException:
                pass

        if (type(result) == pymodbus.exceptions.ModbusIOException):
            self.exceptionHandler.generateException("ModbusIOError")

        try:
            encoded = result.encode()
        except AttributeError:
            self.exceptionHandler.generateException("EncodeError")
            return result

        if type(encoded) is not list:
            if (type(result) == pymodbus.pdu.ExceptionResponse):
                self.exceptionHandler.generateException(encoded)
            else:
                self.exceptionHandler.generateException("NotAListReturned")
        dataOut = []
        # encoded[0] = encoded[0]
        # print(encoded)
        for i in range(number):
            fifoLocal = []
            timeLineLocal = []
            rang = len(encoded[1][i])
            timeStep = (1 / encoded[2][i]) * 1000
            for j in range(rang):
                fifoLocal.append(encoded[1][i][j])
                timeLineLocal.append(encoded[0] - (rang - j) * timeStep)
            newAr = [fifoLocal, timeLineLocal]
            dataOut.append(newAr)

        return dataOut

    def getFifoAndTime16BitUnsigned(self, addresS, number, uniT):
        result = self.getFifoAndTime(addresS, number, uniT)
        result = list(map(tuple, result))
        return result

    def getFifoAndTime16BitSigned(self, addresS, number, uniT):
        result = self.getFifoAndTime(addresS, number, uniT)
        for x in range(len(result)):
            result[x][0] = list(
                map(self.modValConverter.modTo16BitSigned, result[x][0]))
        result = list(map(tuple, result))
        return result

    def getFifoAndTime32BitUnsigned(self, addresS, number, uniT):
        result = self.getFifoAndTime(addresS, number * 2, uniT)
        outData = []
        for x in range(number):
            timeLine = result[x * 2][1]
            if (len(result[x * 2][0]) != len(result[x * 2][1])):
                self.exceptionHandler.generateException(
                    "RegsFIFOsHaveDifferentSizes")
            for i in range(len(result[x * 2][0])):
                result[x * 2][0][i] = self.modValConverter.modTo32BitUnsigned(
                    result[x * 2][0][i], result[x * 2 + 1][0][i])
            dataLine = result[x * 2][0]
            outData.append((dataLine, timeLine))
        return outData

    def getFifoAndTime32BitSigned(self, addresS, number, uniT):
        result = self.getFifoAndTime(addresS, number * 2, uniT)
        outData = []
        for x in range(number):
            timeLine = result[x * 2][1]
            if (len(result[x * 2][0]) != len(result[x * 2][1])):
                self.exceptionHandler.generateException(
                    "RegsFIFOsHaveDifferentSizes")
            for i in range(len(result[x * 2][0])):
                result[x * 2][0][i] = self.modValConverter.modTo32BitSigned(
                    result[x * 2][0][i], result[x * 2 + 1][0][i])
            dataLine = result[x * 2][0]
            outData.append((dataLine, timeLine))
        return outData

    def getFifoAndTimeFloat(self, addresS, number, uniT):
        result = self.getFifoAndTime(addresS, number * 2, uniT)
        outData = []
        for x in range(number):
            timeLine = result[x * 2][1]
            if (len(result[x * 2][0]) != len(result[x * 2][1])):
                self.exceptionHandler.generateException(
                    "RegsFIFOsHaveDifferentSizes")
            for i in range(len(result[x * 2][0])):
                result[x * 2][0][i] = self.modValConverter.modToFloat(
                    result[x * 2][0][i], result[x * 2 + 1][0][i])
            dataLine = result[x * 2][0]
            outData.append((dataLine, timeLine))
        return outData
Beispiel #15
0
    def onHeartbeat(self):
        #Domoticz.Log("onHeartbeat called")

        # Wich serial port settings to use?
        if (Parameters["Mode3"] == "S1B7PN"):
            StopBits, ByteSize, Parity = 1, 7, "N"
        if (Parameters["Mode3"] == "S1B7PE"):
            StopBits, ByteSize, Parity = 1, 7, "E"
        if (Parameters["Mode3"] == "S1B7PO"):
            StopBits, ByteSize, Parity = 1, 7, "O"
        if (Parameters["Mode3"] == "S1B8PN"):
            StopBits, ByteSize, Parity = 1, 8, "N"
        if (Parameters["Mode3"] == "S1B8PE"):
            StopBits, ByteSize, Parity = 1, 8, "E"
        if (Parameters["Mode3"] == "S1B8PO"):
            StopBits, ByteSize, Parity = 1, 8, "O"
        if (Parameters["Mode3"] == "S2B7PN"):
            StopBits, ByteSize, Parity = 2, 7, "N"
        if (Parameters["Mode3"] == "S2B7PE"):
            StopBits, ByteSize, Parity = 2, 7, "E"
        if (Parameters["Mode3"] == "S2B7PO"):
            StopBits, ByteSize, Parity = 2, 7, "O"
        if (Parameters["Mode3"] == "S2B8PN"):
            StopBits, ByteSize, Parity = 2, 8, "N"
        if (Parameters["Mode3"] == "S2B8PE"):
            StopBits, ByteSize, Parity = 2, 8, "E"
        if (Parameters["Mode3"] == "S2B8PO"):
            StopBits, ByteSize, Parity = 2, 8, "O"

        # How many registers to read (depending on data type)?
        registercount = 1  # Default
        if (Parameters["Mode6"] == "noco"): registercount = 1
        if (Parameters["Mode6"] == "int8"): registercount = 1
        if (Parameters["Mode6"] == "int16"): registercount = 1
        if (Parameters["Mode6"] == "int32"): registercount = 2
        if (Parameters["Mode6"] == "int64"): registercount = 4
        if (Parameters["Mode6"] == "uint8"): registercount = 1
        if (Parameters["Mode6"] == "uint16"): registercount = 1
        if (Parameters["Mode6"] == "uint32"): registercount = 2
        if (Parameters["Mode6"] == "uint64"): registercount = 4
        if (Parameters["Mode6"] == "float32"): registercount = 2
        if (Parameters["Mode6"] == "float64"): registercount = 4
        if (Parameters["Mode6"] == "string2"): registercount = 2
        if (Parameters["Mode6"] == "string4"): registercount = 4
        if (Parameters["Mode6"] == "string6"): registercount = 6
        if (Parameters["Mode6"] == "string8"): registercount = 8

        ###################################
        # pymodbus: RTU / ASCII
        ###################################
        if (Parameters["Mode1"] == "rtu" or Parameters["Mode1"] == "ascii"):
            Domoticz.Debug("MODBUS DEBUG USB SERIAL HW - Port=" +
                           Parameters["SerialPort"] + ", BaudRate=" +
                           Parameters["Mode2"] + ", StopBits=" +
                           str(StopBits) + ", ByteSize=" + str(ByteSize) +
                           " Parity=" + Parity)
            Domoticz.Debug("MODBUS DEBUG USB SERIAL CMD - Method=" +
                           Parameters["Mode1"] + ", Address=" +
                           Parameters["Address"] + ", Register=" +
                           Parameters["Password"] + ", Function=" +
                           Parameters["Username"] + ", Data type=" +
                           Parameters["Mode6"])
            try:
                client = ModbusSerialClient(method=Parameters["Mode1"],
                                            port=Parameters["SerialPort"],
                                            stopbits=StopBits,
                                            bytesize=ByteSize,
                                            parity=Parity,
                                            baudrate=int(Parameters["Mode2"]),
                                            timeout=1,
                                            retries=2)
            except:
                Domoticz.Log("Error opening Serial interface on " +
                             Parameters["SerialPort"])
                Devices[1].Update(0, "0")  # Update device in Domoticz

        ###################################
        # pymodbus: RTU over TCP
        ###################################
        if (Parameters["Mode1"] == "rtutcp"):
            Domoticz.Debug("MODBUS DEBUG TCP CMD - Method=" +
                           Parameters["Mode1"] + ", Address=" +
                           Parameters["Address"] + ", Port=" +
                           Parameters["Port"] + ", Register=" +
                           Parameters["Password"] + ", Data type=" +
                           Parameters["Mode6"])
            try:
                client = ModbusTcpClient(host=Parameters["Address"],
                                         port=int(Parameters["Port"]),
                                         timeout=5)
            except:
                Domoticz.Log("Error opening TCP interface on address: " +
                             Parameters["Address"])
                Devices[1].Update(0, "0")  # Update device in Domoticz

        ###################################
        # pymodbusTCP: TCP/IP
        ###################################
        if (Parameters["Mode1"] == "tcpip"):
            Domoticz.Debug("MODBUS DEBUG TCP CMD - Method=" +
                           Parameters["Mode1"] + ", Address=" +
                           Parameters["Address"] + ", Port=" +
                           Parameters["Port"] + ", Register=" +
                           Parameters["Password"] + ", Data type=" +
                           Parameters["Mode6"])
            try:
                client = ModbusClient(host=Parameters["Address"],
                                      port=int(Parameters["Port"]),
                                      auto_open=True,
                                      auto_close=True,
                                      timeout=5)
            except:
                Domoticz.Log("Error opening TCP/IP interface on address: " +
                             Parameters["Address"])
                Devices[1].Update(0, "0")  # Update device in Domoticz

        ###################################
        # pymodbus section
        ###################################
        if (Parameters["Mode1"] == "rtu" or Parameters["Mode1"] == "ascii"
                or Parameters["Mode1"] == "rtutcp"):
            try:
                # Which function to execute? RTU/ASCII/RTU over TCP
                if (Parameters["Username"] == "1"):
                    data = client.read_coils(int(Parameters["Password"]),
                                             registercount,
                                             unit=int(Parameters["Address"]))
                if (Parameters["Username"] == "2"):
                    data = client.read_discrete_inputs(
                        int(Parameters["Password"]),
                        registercount,
                        unit=int(Parameters["Address"]))
                if (Parameters["Username"] == "3"):
                    data = client.read_holding_registers(
                        int(Parameters["Password"]),
                        registercount,
                        unit=int(Parameters["Address"]))
                if (Parameters["Username"] == "4"):
                    data = client.read_input_registers(
                        int(Parameters["Password"]),
                        registercount,
                        unit=int(Parameters["Address"]))
                Domoticz.Debug("MODBUS DEBUG RESPONSE: " + str(data))
            except:
                Domoticz.Log(
                    "Modbus error communicating! (RTU/ASCII/RTU over TCP), check your settings!"
                )
                Devices[1].Update(0, "0")  # Update device to OFF in Domoticz

            try:
                # How to decode the input?
                decoder = BinaryPayloadDecoder.fromRegisters(
                    data.registers, byteorder=Endian.Big, wordorder=Endian.Big)
                if (Parameters["Mode6"] == "noco"): value = data.registers[0]
                if (Parameters["Mode6"] == "int8"):
                    value = decoder.decode_8bit_int()
                if (Parameters["Mode6"] == "int16"):
                    value = decoder.decode_16bit_int()
                if (Parameters["Mode6"] == "int32"):
                    value = decoder.decode_32bit_int()
                if (Parameters["Mode6"] == "int64"):
                    value = decoder.decode_64bit_int()
                if (Parameters["Mode6"] == "uint8"):
                    value = decoder.decode_8bit_uint()
                if (Parameters["Mode6"] == "uint16"):
                    value = decoder.decode_16bit_uint()
                if (Parameters["Mode6"] == "uint32"):
                    value = decoder.decode_32bit_uint()
                if (Parameters["Mode6"] == "uint64"):
                    value = decoder.decode_64bit_uint()
                if (Parameters["Mode6"] == "float32"):
                    value = decoder.decode_32bit_float()
                if (Parameters["Mode6"] == "float64"):
                    value = decoder.decode_64bit_float()
                if (Parameters["Mode6"] == "string2"):
                    value = decoder.decode_string(2)
                if (Parameters["Mode6"] == "string4"):
                    value = decoder.decode_string(4)
                if (Parameters["Mode6"] == "string6"):
                    value = decoder.decode_string(6)
                if (Parameters["Mode6"] == "string8"):
                    value = decoder.decode_string(8)
                Domoticz.Debug("MODBUS DEBUG VALUE: " + str(value))

                # Divide the value (decimal)?
                if (Parameters["Mode5"] == "div0"): value = str(value)
                if (Parameters["Mode5"] == "div10"):
                    value = str(round(value / 10, 1))
                if (Parameters["Mode5"] == "div100"):
                    value = str(round(value / 100, 2))
                if (Parameters["Mode5"] == "div1000"):
                    value = str(round(value / 1000, 3))

                Devices[1].Update(0, value)  # Update value in Domoticz

            except:
                Domoticz.Log(
                    "Modbus error decoding or recieved no data (RTU/ASCII/RTU over TCP)!, check your settings!"
                )
                Devices[1].Update(0, "0")  # Update value in Domoticz

        ###################################
        # pymodbusTCP section
        ###################################
        if (Parameters["Mode1"] == "tcpip"):
            try:
                # Which function to execute? TCP/IP
                if (Parameters["Username"] == "1"):
                    data = client.read_coils(int(Parameters["Password"]),
                                             registercount)
                if (Parameters["Username"] == "2"):
                    data = client.read_discrete_inputs(
                        int(Parameters["Password"]), registercount)
                if (Parameters["Username"] == "3"):
                    data = client.read_holding_registers(
                        int(Parameters["Password"]), registercount)
                if (Parameters["Username"] == "4"):
                    data = client.read_input_registers(
                        int(Parameters["Password"]), registercount)
                Domoticz.Debug("MODBUS DEBUG RESPONSE: " + str(data[0]))
            except:
                Domoticz.Log(
                    "Modbus error communicating! (TCP/IP), check your settings!"
                )
                Devices[1].Update(0, "0")  # Update device to OFF in Domoticz

            try:
                # How to decode the input?
                decoder = BinaryPayloadDecoder.fromRegisters(
                    data, byteorder=Endian.Big, wordorder=Endian.Big)
                if (Parameters["Mode6"] == "noco"): value = data[0]
                if (Parameters["Mode6"] == "int8"):
                    value = decoder.decode_8bit_int()
                if (Parameters["Mode6"] == "int16"):
                    value = decoder.decode_16bit_int()
                if (Parameters["Mode6"] == "int32"):
                    value = decoder.decode_32bit_int()
                if (Parameters["Mode6"] == "int64"):
                    value = decoder.decode_64bit_int()
                if (Parameters["Mode6"] == "uint8"):
                    value = decoder.decode_8bit_uint()
                if (Parameters["Mode6"] == "uint16"):
                    value = decoder.decode_16bit_uint()
                if (Parameters["Mode6"] == "uint32"):
                    value = decoder.decode_32bit_uint()
                if (Parameters["Mode6"] == "uint64"):
                    value = decoder.decode_64bit_uint()
                if (Parameters["Mode6"] == "float32"):
                    value = decoder.decode_32bit_float()
                if (Parameters["Mode6"] == "float64"):
                    value = decoder.decode_64bit_float()
                if (Parameters["Mode6"] == "string2"):
                    value = decoder.decode_string(2)
                if (Parameters["Mode6"] == "string4"):
                    value = decoder.decode_string(4)
                if (Parameters["Mode6"] == "string6"):
                    value = decoder.decode_string(6)
                if (Parameters["Mode6"] == "string8"):
                    value = decoder.decode_string(8)
                Domoticz.Debug("MODBUS DEBUG VALUE: " + str(value))

                # Divide the value (decimal)?
                if (Parameters["Mode5"] == "div0"): value = str(value)
                if (Parameters["Mode5"] == "div10"):
                    value = str(round(value / 10, 1))
                if (Parameters["Mode5"] == "div100"):
                    value = str(round(value / 100, 2))
                if (Parameters["Mode5"] == "div1000"):
                    value = str(round(value / 1000, 3))

                Devices[1].Update(0, value)  # Update value in Domoticz

            except:
                Domoticz.Log(
                    "Modbus error decoding or recieved no data (TCP/IP)!, check your settings!"
                )
                Devices[1].Update(0, "0")  # Update value in Domoticz
Beispiel #16
0
class EPsolarTracerClient:
    ''' EPsolar Tracer client
    '''
    def __init__(self, unit=1, serialclient=None, **kwargs):
        ''' Initialize a serial client instance
        '''
        self.unit = unit
        if serialclient == None:
            port = kwargs.get('port', '/dev/ttyXRUSB0')
            baudrate = kwargs.get('baudrate', 115200)
            self.client = ModbusClient(method='rtu',
                                       port=port,
                                       baudrate=baudrate,
                                       kwargs=kwargs)
        else:
            self.client = serialclient

    def connect(self):
        ''' Connect to the serial
        :returns: True if connection succeeded, False otherwise
        '''
        return self.client.connect()

    def close(self):
        ''' Closes the underlying connection
        '''
        return self.client.close()

    def read_device_info(self):
        request = ReadDeviceInformationRequest(unit=self.unit)
        response = self.client.execute(request)
        return response

    def read_input(self, name):
        register = registerByName(name)
        if register.is_coil():
            response = self.client.read_coils(register.address,
                                              register.size,
                                              unit=self.unit)
        elif register.is_discrete_input():
            response = self.client.read_discrete_inputs(register.address,
                                                        register.size,
                                                        unit=self.unit)
        elif register.is_input_register():
            response = self.client.read_input_registers(register.address,
                                                        register.size,
                                                        unit=self.unit)
        else:
            response = self.client.read_holding_registers(register.address,
                                                          register.size,
                                                          unit=self.unit)
        return register.decode(response)

    def write_output(self, name, value):
        register = registerByName(name)
        values = register.encode(value)
        response = False
        if register.is_coil():
            self.client.write_coil(register.address, values, unit=self.unit)
            response = True
        elif register.is_discrete_input():
            _logger.error("Cannot write discrete input " + repr(name))
            pass
        elif register.is_input_register():
            _logger.error("Cannot write input register " + repr(name))
            pass
        else:
            print(name, register.address, values, self.unit)
            registers = self.client.write_registers(register.address,
                                                    values,
                                                    unit=self.unit)
            print(registers)
            response = True
        return response

    def readRTC(self):
        register = registerByName('Real time clock 1')
        sizeAddress = 3
        result = self.client.read_holding_registers(register.address,
                                                    sizeAddress,
                                                    unit=self.unit)
        return self.decodeRTC(result.registers)

    def writeRTC(self, datetime):
        register = registerByName('Real time clock 1')
        values = self.encodeRTC(datetime)
        self.client.write_registers(register.address, values, unit=self.unit)
        return True

    def decodeRTC(self, rtc):
        s = 2000
        secMin = rtc[0]
        hourDay = rtc[1]
        monthYear = rtc[2]
        secs = (secMin & 0xff)
        hour = (hourDay & 0xff)
        month = (monthYear & 0xff)
        minut = secMin >> 8
        day = hourDay >> 8
        year = monthYear >> 8
        return datetime(s + year, month, day, hour, minut, secs)

    def encodeRTC(self, datetime):
        s = 2000
        rtc1 = int((datetime.minute << 8) | datetime.second)
        rtc2 = int((datetime.day << 8) | datetime.hour)
        rtc3 = int((datetime.year - s << 8) | datetime.month)
        return [rtc1, rtc2, rtc3]
Beispiel #17
0
class Modbus_Device():
    def __init__(self,
                 method='rtu',
                 port='/dev/ttyUSB0',
                 baudrate=9600,
                 timeout=3,
                 parity='E',
                 stopbits=1,
                 bytesize=8,
                 slaveAddress=0):
        self.method = method
        self.port = port
        self.baudrate = baudrate
        self.timeout = timeout
        self.parity = parity
        self.stopbits = stopbits
        self.bytesize = bytesize
        self.slaveAddress = slaveAddress
        self.client = ModbusSerialClient(
            method=self.method,
            port=self.port,  #'/dev/ttyUSB0'or #'COM9',
            baudrate=self.baudrate,
            timeout=self.timeout,
            parity=self.parity,
            stopbits=self.stopbits,
            bytesize=self.bytesize)

    def readRegister(self, function_Code=3, register=0, count=1, Print=True):
        if self.client.connect():
            print('Client connected')
            if function_Code == 1:
                response = self.client.read_coils(address=register,
                                                  count=count,
                                                  unit=self.slaveAddress)

                if not response.isError():
                    print(decode(response.registers))
                    return decode(response.registers)
                else:
                    print(response)
            if function_Code == 2:
                response = self.client.read_discrete_inputs(
                    address=register, count=count, unit=self.slaveAddress)

                if not response.isError():
                    print(decode(response.registers))
                    return decode(response.registers)
                else:
                    print(response)
            if function_Code == 3:
                print('Reading holding regisster')
                response = self.client.read_holding_registers(
                    address=register, count=count, unit=self.slaveAddress)

                if not response.isError():
                    print(decode(response.registers))
                    return decode(response.registers)
                else:
                    print(response)
            if function_Code == 4:
                response = self.client.read_input_registers(
                    address=register, count=count, unit=self.slaveAddress)

                if not response.isError():
                    print(decode(response.registers))
                    return decode(response.registers)
                else:
                    print(response)

        else:
            print('Cannot connect to the Modbus Server/Slave')

    def writeRegister(self,
                      function_Code=6,
                      register=0,
                      count=1,
                      Print=True,
                      value=0):
        if self.client.connect():
            if function_Code == 6:
                if count > 1:
                    response = self.client.write_registers(
                        address=register, values=value, unit=self.slaveAddress)
                    if not response.isError():
                        print("Written Successfully!")
                    else:
                        print("Error Writing")
                else:
                    response = self.client.write_register(
                        address=register, value=value, unit=self.slaveAddress)
                    if not response.isError():
                        print("Written Successfully!")
                    else:
                        print("Error Writing")
            if function_Code == 5:
                response = self.client.write_coil(address=register,
                                                  values=value,
                                                  unit=self.slaveAddress)
                if not response.isError():
                    print("Written Successfully!")
                else:
                    print("Error Writing")
class reader:
    def __init__(self, xmlFile):
        """Parses the xml file and creates the reader"""
        self.xml = xmlFile
        validationInt = validateXml(self.xml)
        if validationInt == -1: raise Exception('XML File Error: devicData node missing')
        elif validationInt == -2: raise Exception('XML File Error: modbus type not set')
        elif validationInt == -3: raise Exception('XML File Error: ip address missing')
        elif validationInt == -4: raise Exception('XML File Error: comm port missing')
        elif validationInt == -5: raise Exception('XML File Error: baud rate missing')
        elif validationInt == -10: raise Exception('XML File Error: No register mappings')
        elif validationInt == -11: raise Exception('XML File Error: Duplicated Input register mapping')
        elif validationInt == -12: raise Exception('XML File Error: Duplicated Discrete input mapping')
        elif validationInt == -13: raise Exception('XML File Error: Duplicated Holding register mapping')
        elif validationInt == -14: raise Exception('XML File Error: Duplicated Coil mapping')

        self.xmlData = self._parseXml()
        if self.xmlData.get('modbusType') == 'tcp/ip':
            self.client = ModbusTcpClient(self.xmlData.get('ip'), self.xmlData.get('port'), timeout=1)
        elif self.xmlData.get('modbusType') == 'rtu':
            self.client = ModbusSerialClient(method = 'rtu', 
                                            port = self.xmlData.get('com'),
                                            baudrate = self.xmlData.get('baud'),
                                            bytesize = self.xmlData.get('bytesize'),
                                            stopbits = self.xmlData.get('stopbits'),
                                            parity = self.xmlData.get('parity'),
                                            timeout = self.xmlData.get('timeout'),
                                            )

    def update_all(self):
        #Update register values
        if self.client.connect():
            #Input registers
            for ir in self.xmlData.get('registers').get('ir'):
                self._update_reg(ir)
                self._writeToLog(ir)
                #ir['str_repr'] = f"INPUT REGISTER | REGISTER: {int(ir.get('register'))} | DESCRIPTION: {ir.get('description')} | VALUE: {ir.get('value')}"

            #Holding registers
            for hr in self.xmlData.get('registers').get('hr'):
                self._update_reg(hr)
                self._writeToLog(hr)
                #hr['str_repr'] = f"HOLDING REGISTER | REGISTER: {int(hr.get('register'))} | DESCRIPTION: {hr.get('description')} | VALUE: {hr.get('value')}"

            #Coils
            for co in self.xmlData.get('registers').get('co'):
                self._update_reg(co)
                self._writeToLog(co)
                #co['str_repr'] = f"COIL | REGISTER: {int(co.get('register'))} |DESCRIPTION: {co.get('description')} | VALUE: {co.get('value')}"

            #Discrete inputs
            for di in self.xmlData.get('registers').get('di'):
                self._update_reg(di)
                self._writeToLog(di)
                #di['str_repr'] = f"DISCRETE INPUT | REGISTER: {int(di.get('register'))} | DESCRIPTION: {di.get('description')} | VALUE: {di.get('value')}"

        else:
            print('Connection failed')

    def _writeToLog(self, reg=None):
        if not self.xmlData.get('log'):
            return

        if self.xmlData.get('log') not in ['all', 'partial']:
            return

        if type(reg)==dict:
            if self.xmlData.get('log') == 'partial' and not reg.get('log'):
                return
            logstr = f"READ;{datetime.datetime.now()};{reg.get('type')};{reg.get('register')};{reg.get('description')};{reg.get('value')};\n"
        
        elif type(reg)==tuple:
            logstr = f"WRITE;{datetime.datetime.now()};{reg[0]};{reg[1]};;{reg[2]};\n"
        else:
            #fault
            return

        #Check if the logging file exists already
        if os.path.isfile('modbusLog.csv'):
            with open('modbusLog.csv', 'a') as f:
                f.write(logstr)
        else:
            with open('modbusLog.csv', 'w') as f:
                f.write(f"Operation;Timestamp;Register Type;Register #; Description;Register Value;\n")
                f.write(logstr)

    def _parseXml(self):
        """Parses xml file and validates the registers"""
        data = {}

        tree = ET.parse(self.xml)
        root = tree.getroot()
        registers = root.find('registers')

        #Discrete inputs (booleans)
        di = []
        diNode = registers.find('di')
        if diNode != None:
            for mapping in diNode.findall('mapping'):
                mapDict = {
                    'register' : int(mapping.get('register')),
                    'type' : 'di',
                    'description' : mapping.get('description', '-'),
                    'value' : 0,
                    'log' : mapping.get('log', False)
                }
                di.append(mapDict)

        #Input registers (analogs)
        ir = []
        irNode = registers.find('ir')
        if irNode != None:
            for mapping in irNode.findall('mapping'):
                mapDict = {
                    'register' : int(mapping.get('register')),
                    'type' : 'ir',
                    'description' : mapping.get('description', '-'),
                    'bit0' : mapping.get('bit0', '-'),
                    'bit1' : mapping.get('bit1', '-'),
                    'bit2' : mapping.get('bit2', '-'),
                    'bit3' : mapping.get('bit3', '-'),
                    'bit4' : mapping.get('bit4', '-'),
                    'bit5' : mapping.get('bit5', '-'),
                    'bit6' : mapping.get('bit6', '-'),
                    'bit7' : mapping.get('bit7', '-'),
                    'bit8' : mapping.get('bit8', '-'),
                    'bit9' : mapping.get('bit9', '-'),
                    'bit10' : mapping.get('bit10', '-'),
                    'bit11' : mapping.get('bit11', '-'),
                    'bit12' : mapping.get('bit12', '-'),
                    'bit13' : mapping.get('bit13', '-'),
                    'bit14' : mapping.get('bit14', '-'),
                    'bit15' : mapping.get('bit15', '-'),
                    'value' : 0,
                    'log' : mapping.get('log', False)
                }
                ir.append(mapDict)

        #Holding registers (analogs)
        hr = []
        hrNode = registers.find('hr')
        if hrNode != None:
            for mapping in hrNode.findall('mapping'):
                mapDict = {
                    'register' : int(mapping.get('register')),
                    'type' : 'hr',
                    'description' : mapping.get('description', '-'),
                    'bit0' : mapping.get('bit0', '-'),
                    'bit1' : mapping.get('bit1', '-'),
                    'bit2' : mapping.get('bit2', '-'),
                    'bit3' : mapping.get('bit3', '-'),
                    'bit4' : mapping.get('bit4', '-'),
                    'bit5' : mapping.get('bit5', '-'),
                    'bit6' : mapping.get('bit6', '-'),
                    'bit7' : mapping.get('bit7', '-'),
                    'bit8' : mapping.get('bit8', '-'),
                    'bit9' : mapping.get('bit9', '-'),
                    'bit10' : mapping.get('bit10', '-'),
                    'bit11' : mapping.get('bit11', '-'),
                    'bit12' : mapping.get('bit12', '-'),
                    'bit13' : mapping.get('bit13', '-'),
                    'bit14' : mapping.get('bit14', '-'),
                    'bit15' : mapping.get('bit15', '-'),
                    'value' : 0,
                    'log' : mapping.get('log', False)
                }
                hr.append(mapDict)

        #Coils (booleans)
        co = []
        coNode = registers.find('co')
        if coNode != None:
            for mapping in coNode.findall('mapping'):
                mapDict = {
                    'register' : int(mapping.get('register')),
                    'type' : 'co',
                    'description' : mapping.get('description', '-'),
                    'value' : 0,
                    'log' : mapping.get('log', False)
                }
                co.append(mapDict)

        data['registers'] = {
            'di' : di,
            'ir' : ir,
            'hr' : hr,
            'co' : co
        }

        #Parse device data
        deviceData = root.find('deviceData')
        data['vendorName'] = deviceData.get("vendorName", '')
        data['productCode'] = deviceData.get("productCode", '')
        data['vendorUrl'] = deviceData.get("vendorUrl", '')
        data['productName'] = deviceData.get("productName", '')
        data['modelName'] = deviceData.get("modelName", '')
        data['version'] = deviceData.get("version", '0.0-1')
        data['modbusType'] = deviceData.get('modbusType')
        data['com'] = deviceData.get("com", None)
        data['baud'] = int(deviceData.get("baud", "9600"))
        data['stopbits'] = int(deviceData.get("stopbits", "1"))
        data['bytesize'] = int(deviceData.get("bytesize", "8"))
        data['parity'] = deviceData.get("parity", "E")
        data['ip'] = deviceData.get("ip", "localhost")
        data['port'] = int(deviceData.get("port", 502))
        data['timeout'] = int(deviceData.get('timeout', "2"))
        #Log to file can be all or partial
        #all logs all, partial only those with the flag
        data['log'] = deviceData.get('log', False)

        return data

    def connect(self):
        return self.client.connect()

    def _update_reg(self, register):
        try:
            if register.get('type') == 'di':
                data = self.client.read_discrete_inputs(address=register.get('register'), count=1)
                if not isinstance(data, ExceptionResponse):
                    register['value'] =  data.getBit(0)
                else:
                    register['value'] =   str(data)
        
            elif register.get('type') == 'co':
                data = self.client.read_coils(address=register.get('register'), count=1)
                if not isinstance(data, ExceptionResponse):
                    register['value'] =   data.getBit(0)
                else:
                    register['value'] =    str(data)

            elif register.get('type') == 'ir':
                
                data = self.client.read_input_registers(address=register.get('register'), count=1)
                if not isinstance(data, ExceptionResponse):
                    register['value'] = data.getRegister(0)
                else:
                    register['value'] =  str(data)

            elif register.get('type') == 'hr':
                
                data = self.client.read_holding_registers(address=register.get('register'), count=1)
                if not isinstance(data, ExceptionResponse):
                    register['value'] = data.getRegister(0)
                else:
                    register['value'] =  str(data)
        except Exception as e:
            register['value'] =  str(e) + ' ' + str(data)
            
    def get_ir(self, register):
        #gets the value of the register, regardless if it exists
        if self.connect():
            try:
                data = self.client.read_input_registers(address=register, count=1)
                if not isinstance(data, ExceptionResponse):
                    return data.getRegister(0)
                else:
                    return  str(data)
            except Exception as e:
                return str(e) + str(data)

    def get_hr(self, register):
        #gets the value of the register, regardless if it exists
        if self.connect():
            try:
                data = self.client.read_holding_registers(address=register, count=1)
                if not isinstance(data, ExceptionResponse):
                    return data.getRegister(0)
                else:
                    return  str(data)
            except Exception as e:
                return str(e) + str(data)

    def get_di(self, register):
        #gets the value of the register, regardless if it exists
        if self.connect():
            try:
                data = self.client.read_discrete_inputs(address=register, count=1)
                if not isinstance(data, ExceptionResponse):
                    return data.getBit(0)
                else:
                    return  str(data)
            except Exception as e:
                return str(e) + ' ' + str(data)

    def get_co(self, register):
        #gets the value of the register, regardless if it exists
        if self.connect():
            try:
                data = self.client.read_coils(address=register, count=1)
                if not isinstance(data, ExceptionResponse):
                    return data.getBit(0)
                else:
                    return  str(data)
            except Exception as e:
                return str(e) + ' ' + str(data)

    def write_coil(self, register, value):
        if self.connect():
            if value > 1:
                value = 1
            self._writeToLog(reg=('co', register, value))
            return self.client.write_coil(address=register, value=value)

    def write_register(self, register, value):
        if self.connect():
            self._writeToLog(reg=('hr', register, value))
            return self.client.write_register(address=register, value=value)
Beispiel #19
0
                      baudrate=9600)
connection = client.connect()

pinout = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

try:
    time.sleep(2)
    plc01.ready()
    while True:
        result = client.read_discrete_inputs(1024, 16, unit=1)
        for x in range(0, 16):
            if x < 8:
                plc01['x' + str(x)] = result.bits[x]
            else:
                plc01['x' + str(x + 2)] = result.bits[x]
        result = client.read_coils(1280, 16, unit=1)
        for x in range(0, 16):
            if x < 8:
                plc01['y' + str(x)] = result.bits[x]
            else:
                plc01['y' + str(x + 2)] = result.bits[x]

        result = client.read_coils(2560, 16, unit=1)
        for x in range(0, 8):
            plc01['M' + str(512 + x)] = result.bits[x]

        for x in range(0, 16):
            pinout[x] = plc01['M' + str(100 + x)]
        client.write_coils(2148, pinout, unit=1)

        time.sleep(.025)
Beispiel #20
0
class EPsolarTracerClient:
    """ EPsolar Tracer client
    """

    def __init__(self, unit: int=1, serialclient: ModbusClient=None, **kwargs):
        """ Initialize a serial client instance
        """
        self.unit = unit
        if serialclient is None:
            if not 'port' in kwargs:
                kwargs['port'] = '/dev/ttyXRUSB0'

            if not 'baudrate' in kwargs:
                kwargs['baudrate'] = 115200

            self.client = ModbusClient(method='rtu', **kwargs)
        else:
            self.client = serialclient

    def connect(self):
        """ Connect to the serial
        :returns: True if connection succeeded, False otherwise
        """
        try:
            return self.client.connect()
        except AttributeError:
            # !FIXME there is bug in pymodbus when rtu mode is used and connection is not made:
            # !FIXME AttributeError: 'NoneType' object has no attribute 'interCharTimeout' that simply means connection failed
            return False

    def close(self):
        """ Closes the underlying connection
        """
        return self.client.close()

    def read_device_info(self):
        request = ReadDeviceInformationRequest(unit=self.unit)
        response = self.client.execute(request)
        return response

    def read_input(self, register_type: Union[RegisterTypeEnum, CoilTypeEnum]):
        if type(register_type) == 'str':
            register = registerByName(register_type)
        elif type(register_type) == RegisterTypeEnum:
            register = registers.get(register_type)
        elif type(register_type) == CoilTypeEnum:
            register = coils.get(register_type)

        if not register:
            raise Exception("Unknown register {}".format(register_type.name))

        if register.is_coil():
            response = self.client.read_coils(register.address, register.size, unit=self.unit)
        elif register.is_discrete_input():
            response = self.client.read_discrete_inputs(register.address, register.size, unit=self.unit)
        elif register.is_input_register():
            response = self.client.read_input_registers(register.address, register.size, unit=self.unit)
        else:
            response = self.client.read_holding_registers(register.address, register.size, unit=self.unit)
        return register.decode(response)

    def write_output(self, register_type: Union[RegisterTypeEnum, CoilTypeEnum], value):
        if type(register_type) == 'str':
            register = registerByName(register_type)
        elif type(register_type) == RegisterTypeEnum:
            register = registers.get(register_type)
        elif type(register_type) == CoilTypeEnum:
            register = coils.get(register_type)

        if not register:
            raise Exception("Unknown register {}".format(register_type.name))

        values = register.encode(value)
        response = False
        if register.is_coil():
            self.client.write_coil(register.address, values, unit=self.unit)
            response = True
        elif register.is_discrete_input():
            _logger.error("Cannot write discrete input {}".format(register_type.name))
            pass
        elif register.is_input_register():
            _logger.error("Cannot write input register {}".format(register_type.name))
            pass
        else:
            self.client.write_registers(register.address, values, unit=self.unit)
            response = True
        return response
Beispiel #21
0
class EPsolarTracerClient:
    ''' EPsolar Tracer client
    '''
    def __init__(self, unit=1, serialclient=None, **kwargs):
        ''' Initialize a serial client instance
        '''
        self.unit = unit
        if serialclient == None:
            port = kwargs.get('port', '/dev/ttyXRUSB0')
            baudrate = kwargs.get('baudrate', 115200)
            self.client = ModbusClient(method='rtu',
                                       port=port,
                                       baudrate=baudrate,
                                       kwargs=kwargs)
        else:
            self.client = serialclient

    def connect(self):
        ''' Connect to the serial
        :returns: True if connection succeeded, False otherwise
        '''
        return self.client.connect()

    def close(self):
        ''' Closes the underlying connection
        '''
        return self.client.close()

    def read_device_info(self):
        request = ReadDeviceInformationRequest(unit=self.unit)
        response = self.client.execute(request)
        return response

    def read_input(self, name):
        register = registerByName(name)
        if register.is_coil():
            response = self.client.read_coils(register.address,
                                              register.size,
                                              unit=self.unit)
        elif register.is_discrete_input():
            response = self.client.read_discrete_inputs(register.address,
                                                        register.size,
                                                        unit=self.unit)
        elif register.is_input_register():
            response = self.client.read_input_registers(register.address,
                                                        register.size,
                                                        unit=self.unit)
        else:
            response = self.client.read_holding_registers(register.address,
                                                          register.size,
                                                          unit=self.unit)
        return register.decode(response)

    def write_output(self, name, value):
        register = registerByName(name)
        values = register.encode(value)
        response = False
        if register.is_coil():
            self.client.write_coil(register.address, values, unit=self.unit)
            response = True
        elif register.is_discrete_input():
            _logger.error("Cannot write discrete input " + repr(name))
            pass
        elif register.is_input_register():
            _logger.error("Cannot write input register " + repr(name))
            pass
        else:
            self.client.write_registers(register.address,
                                        values,
                                        unit=self.unit)
            response = True
        return response
Beispiel #22
0
from pymodbus.payload import BinaryPayloadDecoder
from pymodbus.payload import BinaryPayloadBuilder
from pymodbus.constants import Endian


import time
onOff = True


#client.write_coil(0, True)

isOk = True
count = 1
while isOk:
    # read the setable devices
    result = client.read_coils(count-1, count)

    if not result.isError():
        print(result.bits)
    else:
        print('ERROR')
        break
    count += 1

'''
for i in range(0, 8):
    # read only inputs
    result = client.read_discrete_inputs(i, 2)
    if not result.isError():
        print(result.bits)
    else:
# are not known to these tests. Furthermore, some use the same memory
# blocks for the two sets, so a change to one is a change to the other.
# Keep both of these cases in mind when testing as the following will
# _only_ pass with the supplied async modbus server (script supplied).
#---------------------------------------------------------------------------# 
#rq = client.write_coil(1, True)
var = 1
try:
    conn=psycopg2.connect("dbname='hcam' user='******' password='******'")
except:
    print "I am unable to connect to the database."

cur = conn.cursor()

while var == 1 :
	rr1 = client.read_coils(2048,10,unit=0x01)
	#print rr1.bits[0]
	#print rr1.bits[1]
	#print rr1.bits[2]
	#print rr1.bits[8]

	rr2 = client.read_coils(3099,2,unit=0x01)
	#print rr2.bits[0]
	#print rr2.bits[1]

	rr3 = client.read_holding_registers(1088,2,unit=0x01)
	#print hex(rr3.registers[0]).lstrip("0x")
	#print hex(rr3.registers[1]).lstrip("0x")

	try:
		query = "insert into presion_flujo(id,fecha,presion,flujo) values(nextval('seq_presion_flujo'), current_timestamp, %s, %s)"
Beispiel #24
0
class M98:
    def __init__(self, **kwargs):
        self.conn = ModbusSerialClient('rtu', **kwargs)
        self.conn.connect()
        model = self.conn.read_holding_registers(Reg.MODEL,
                                                 unit=1).registers[0]
        try:
            self.model = Model(model)
        except ValueError:
            raise RuntimeError('unknown device model: %d' % model)

    def _cmd(self, cmd: Cmd):
        self.conn.write_registers(Reg.CMD, [cmd], unit=1)

    class EnableContext:
        def __init__(self, main, prev_state):
            self.main = main
            self.prev_state = prev_state

        def __enter__(self):
            pass

        def __exit__(self, exc_type, exc_value, traceback):
            self.main._cmd(Cmd.ON if self.prev_state else Cmd.OFF)

    def enable(self, state: bool):
        before_state = self.enabled()
        self._cmd(Cmd.ON if state else Cmd.OFF)
        return self.EnableContext(self, before_state)

    def enabled(self):
        return self.conn.read_coils(Coil.ISTATE, unit=1).getBit(0)

    def cc_mode(self, current, risetime=None):
        self.conn.write_registers(Reg.IFIX,
                                  _float(current),
                                  skip_encode=True,
                                  unit=1)
        if risetime:
            self.conn.write_registers(Reg.TMCCS,
                                      _float(risetime * 1000),
                                      skip_encode=True,
                                      unit=1)
            self._cmd(Cmd.CC_Soft)
        else:
            self._cmd(Cmd.CC)
        return (self.voltage, self.current)

    def battery_mode(self, current, end_voltage, start_capacity=0):
        self.conn.write_registers(Reg.IFIX,
                                  _float(current),
                                  skip_encode=True,
                                  unit=1)
        # set end voltage and reset start capacity
        self.conn.write_registers(Reg.UBATTEND,
                                  _float(end_voltage, start_capacity),
                                  skip_encode=True,
                                  unit=1)
        self._cmd(Cmd.Battery_Test)
        return (self.voltage, self.current, self.capacity)

    def cw_mode(self, power):
        self.conn.write_registers(Reg.PFIX,
                                  _float(power),
                                  skip_encode=True,
                                  unit=1)
        self._cmd(Cmd.CW)
        return (self.voltage, self.current)

    def voltage(self):
        return _defloat(
            self.conn.read_holding_registers(Reg.U, 2, unit=1).registers)[0]

    def current(self):
        return _defloat(
            self.conn.read_holding_registers(Reg.I, 2, unit=1).registers)[0]

    def capacity(self):
        return _defloat(
            self.conn.read_holding_registers(Reg.BATT, 2, unit=1).registers)[0]
def run_sync_client():
    client = ModbusClient(method='rtu',
                          port=PORT,
                          timeout=1,
                          baudrate=BAUD_RATE,
                          parity=PARITY,
                          stopbits=STOP_BITS,
                          bytesize=N_DATA_BITS)
    client.connect()

    # ------------------------------------------------------------------------#
    # Specify slave to query
    # ------------------------------------------------------------------------#
    # The slave to query is specified in an optional parameter for each
    # individual request. This can be done by specifying the `unit` parameter
    # which defaults to `0x00`
    # ----------------------------------------------------------------------- #
    log.debug("Read coils")
    read_resp = client.read_coils(1, 1, unit=UNIT)
    log.debug(read_resp)

    # ----------------------------------------------------------------------- #
    # Example requests
    # ----------------------------------------------------------------------- #
    # simply call the methods that you would like to use. An example session
    # is displayed below along with some assert checks. Note that some Modbus
    # implementations differentiate holding/input discrete/coils and as such
    # you will not be able to write to these, therefore the starting values
    # are not known to these tests. Furthermore, some use the same memory
    # blocks for the two sets, so a change to one is a change to the other.
    # Keep both of these cases in mind when testing as the following will
    # _only_ pass with the supplied asynchronous Modbus server (script supplied).
    # ----------------------------------------------------------------------- #
    log.debug("Write to a coil and read back")
    write_resp = client.write_coil(0, True, unit=UNIT)
    read_resp = client.read_coils(0, 1, unit=UNIT)
    assert not write_resp.isError()  # test that we are not an error
    assert read_resp.bits[0]  # test the expected value

    log.debug("Write to multiple coils and read back- test 1")
    write_resp = client.write_coils(1, [True] * 8, unit=UNIT)
    assert not write_resp.isError()  # test that we are not an error
    read_resp = client.read_coils(1, 21, unit=UNIT)
    assert not read_resp.isError()  # test that we are not an error
    resp = [True] * 21

    # If the returned output quantity is not a multiple of eight,
    # the remaining bits in the final data byte will be padded with zeros
    # (toward the high order end of the byte)

    resp.extend([False] * 3)
    assert read_resp.bits == resp  # test the expected value

    log.debug("Write to multiple coils and read back - test 2")
    write_resp = client.write_coils(1, [False] * 8, unit=UNIT)
    read_resp = client.read_coils(1, 8, unit=UNIT)
    assert not write_resp.isError()  # test that we are not an error
    assert read_resp.bits == [False] * 8  # test the expected value

    log.debug("Read discrete inputs")
    read_resp = client.read_discrete_inputs(0, 8, unit=UNIT)
    assert not write_resp.isError()  # test that we are not an error

    log.debug("Write to a holding register and read back")
    write_resp = client.write_register(1, 10, unit=UNIT)
    read_resp = client.read_holding_registers(1, 1, unit=UNIT)
    assert not write_resp.isError()  # test that we are not an error
    assert read_resp.registers[0] == 10  # test the expected value

    log.debug("Write to multiple holding registers and read back")
    write_resp = client.write_registers(1, [10] * 8, unit=UNIT)
    read_resp = client.read_holding_registers(1, 8, unit=UNIT)
    assert not write_resp.isError()  # test that we are not an error
    assert read_resp.registers == [10] * 8  # test the expected value

    log.debug("Read input registers")
    read_resp = client.read_input_registers(1, 8, unit=UNIT)
    assert not write_resp.isError()  # test that we are not an error

    arguments = {
        'read_address': 1,
        'read_count': 8,
        'write_address': 1,
        'write_registers': [20] * 8,
    }
    log.debug("Read write registers simultaneously")
    write_resp = client.readwrite_registers(unit=UNIT, **arguments)
    read_resp = client.read_holding_registers(1, 8, unit=UNIT)
    assert not write_resp.isError()  # test that we are not an error
    assert write_resp.registers == [20] * 8  # test the expected value
    assert read_resp.registers == [20] * 8  # test the expected value

    # ----------------------------------------------------------------------- #
    # Close the client
    # ----------------------------------------------------------------------- #
    client.close()
def run_sync_client():
    # ------------------------------------------------------------------------#
    # choose the client you want
    # ------------------------------------------------------------------------#
    # make sure to start an implementation to hit against. For this
    # you can use an existing device, the reference implementation in the tools
    # directory, or start a pymodbus server.
    #
    # If you use the UDP or TCP clients, you can override the framer being used
    # to use a custom implementation (say RTU over TCP). By default they use
    # the socket framer::
    #
    #    client = ModbusClient('localhost', port=5020, framer=ModbusRtuFramer)
    #
    # It should be noted that you can supply an ipv4 or an ipv6 host address
    # for both the UDP and TCP clients.
    #
    # There are also other options that can be set on the client that controls
    # how transactions are performed. The current ones are:
    #
    # * retries - Specify how many retries to allow per transaction (default=3)
    # * retry_on_empty - Is an empty response a retry (default = False)
    # * source_address - Specifies the TCP source address to bind to
    # * strict - Applicable only for Modbus RTU clients.
    #            Adheres to modbus protocol for timing restrictions
    #            (default = True).
    #            Setting this to False would disable the inter char timeout
    #            restriction (t1.5) for Modbus RTU
    #
    #
    # Here is an example of using these options::
    #
    #    client = ModbusClient('localhost', retries=3, retry_on_empty=True)
    # ------------------------------------------------------------------------#
    #client = ModbusClient('localhost', port=5020)
    # from pymodbus.transaction import ModbusRtuFramer
    # client = ModbusClient('localhost', port=5020, framer=ModbusRtuFramer)
    # client = ModbusClient(method='binary', port='/dev/ptyp0', timeout=1)
    # client = ModbusClient(method='ascii', port='/dev/ptyp0', timeout=1)
    client = ModbusClient(method='rtu', port=sys.argv[1], timeout=1,
                           baudrate=int(sys.argv[2]))
    client.connect()

    # ------------------------------------------------------------------------#
    # specify slave to query
    # ------------------------------------------------------------------------#
    # The slave to query is specified in an optional parameter for each
    # individual request. This can be done by specifying the `unit` parameter
    # which defaults to `0x00`
    # ----------------------------------------------------------------------- #
    log.debug("Reading Coils")
    rr = client.read_coils(1, 1, unit=UNIT)
    log.debug(rr)


    # ----------------------------------------------------------------------- #
    # example requests
    # ----------------------------------------------------------------------- #
    # simply call the methods that you would like to use. An example session
    # is displayed below along with some assert checks. Note that some modbus
    # implementations differentiate holding/input discrete/coils and as such
    # you will not be able to write to these, therefore the starting values
    # are not known to these tests. Furthermore, some use the same memory
    # blocks for the two sets, so a change to one is a change to the other.
    # Keep both of these cases in mind when testing as the following will
    # _only_ pass with the supplied asynchronous modbus server (script supplied).
    # ----------------------------------------------------------------------- #
    log.debug("Write to a Coil and read back")
    rq = client.write_coil(0, True, unit=UNIT)
    rr = client.read_coils(0, 1, unit=UNIT)
    assert(not rq.isError())     # test that we are not an error
    assert(rr.bits[0] == True)          # test the expected value

    log.debug("Write to multiple coils and read back- test 1")
    rq = client.write_coils(1, [True]*8, unit=UNIT)
    assert(not rq.isError())     # test that we are not an error
    rr = client.read_coils(1, 21, unit=UNIT)
    assert(not rr.isError())     # test that we are not an error
    resp = [True]*21

    # If the returned output quantity is not a multiple of eight,
    # the remaining bits in the final data byte will be padded with zeros
    # (toward the high order end of the byte).

    resp.extend([False]*3)
    assert(rr.bits == resp)         # test the expected value

    log.debug("Write to multiple coils and read back - test 2")
    rq = client.write_coils(1, [False]*8, unit=UNIT)
    rr = client.read_coils(1, 8, unit=UNIT)
    assert(not rq.isError())     # test that we are not an error
    assert(rr.bits == [False]*8)         # test the expected value

    log.debug("Read discrete inputs")
    rr = client.read_discrete_inputs(0, 8, unit=UNIT)
    assert(not rq.isError())     # test that we are not an error

    log.debug("Write to a holding register and read back")
    rq = client.write_register(1, 10, unit=UNIT)
    rr = client.read_holding_registers(1, 1, unit=UNIT)
    assert(not rq.isError())     # test that we are not an error
    assert(rr.registers[0] == 10)       # test the expected value

    log.debug("Write to multiple holding registers and read back")
    rq = client.write_registers(1, [10]*8, unit=UNIT)
    rr = client.read_holding_registers(1, 8, unit=UNIT)
    assert(not rq.isError())     # test that we are not an error
    assert(rr.registers == [10]*8)      # test the expected value

    log.debug("Read input registers")
    rr = client.read_input_registers(1, 8, unit=UNIT)
    assert(not rq.isError())     # test that we are not an error

    arguments = {
        'read_address':    1,
        'read_count':      8,
        'write_address':   1,
        'write_registers': [20]*8,
    }
    log.debug("Read write registeres simulataneously")
    rq = client.readwrite_registers(unit=UNIT, **arguments)
    rr = client.read_holding_registers(1, 8, unit=UNIT)
    assert(not rq.isError())     # test that we are not an error
    assert(rq.registers == [20]*8)      # test the expected value
    assert(rr.registers == [20]*8)      # test the expected value

    # ----------------------------------------------------------------------- #
    # close the client
    # ----------------------------------------------------------------------- #
    client.close()
Beispiel #27
0
def run_sync_client():
    # ------------------------------------------------------------------------#
    # choose the client you want
    # ------------------------------------------------------------------------#
    # make sure to start an implementation to hit against. For this
    # you can use an existing device, the reference implementation in the tools
    # directory, or start a pymodbus server.
    #
    # If you use the UDP or TCP clients, you can override the framer being used
    # to use a custom implementation (say RTU over TCP). By default they use
    # the socket framer::
    #
    #    client = ModbusClient('localhost', port=5020, framer=ModbusRtuFramer)
    #
    # It should be noted that you can supply an ipv4 or an ipv6 host address
    # for both the UDP and TCP clients.
    #
    # There are also other options that can be set on the client that controls
    # how transactions are performed. The current ones are:
    #
    # * retries - Specify how many retries to allow per transaction (default=3)
    # * retry_on_empty - Is an empty response a retry (default = False)
    # * source_address - Specifies the TCP source address to bind to
    # * strict - Applicable only for Modbus RTU clients.
    #            Adheres to modbus protocol for timing restrictions
    #            (default = True).
    #            Setting this to False would disable the inter char timeout
    #            restriction (t1.5) for Modbus RTU
    #
    #
    # Here is an example of using these options::
    #
    #    client = ModbusClient('localhost', retries=3, retry_on_empty=True)
    # ------------------------------------------------------------------------#
    client = ModbusClient('localhost', port=5020)
    # from pymodbus.transaction import ModbusRtuFramer
    # client = ModbusClient('localhost', port=5020, framer=ModbusRtuFramer)
    # client = ModbusClient(method='binary', port='/dev/ptyp0', timeout=1)
    # client = ModbusClient(method='ascii', port='/dev/ptyp0', timeout=1)
    # client = ModbusClient(method='rtu', port='/dev/ptyp0', timeout=1,
    #                       baudrate=9600)
    client.connect()

    # ------------------------------------------------------------------------#
    # specify slave to query
    # ------------------------------------------------------------------------#
    # The slave to query is specified in an optional parameter for each
    # individual request. This can be done by specifying the `unit` parameter
    # which defaults to `0x00`
    # ----------------------------------------------------------------------- #
    log.debug("Reading Coils")
    rr = client.read_coils(1, 1, unit=UNIT)
    log.debug(rr)


    # ----------------------------------------------------------------------- #
    # example requests
    # ----------------------------------------------------------------------- #
    # simply call the methods that you would like to use. An example session
    # is displayed below along with some assert checks. Note that some modbus
    # implementations differentiate holding/input discrete/coils and as such
    # you will not be able to write to these, therefore the starting values
    # are not known to these tests. Furthermore, some use the same memory
    # blocks for the two sets, so a change to one is a change to the other.
    # Keep both of these cases in mind when testing as the following will
    # _only_ pass with the supplied asynchronous modbus server (script supplied).
    # ----------------------------------------------------------------------- #
    log.debug("Write to a Coil and read back")
    rq = client.write_coil(0, True, unit=UNIT)
    rr = client.read_coils(0, 1, unit=UNIT)
    assert(not rq.isError())     # test that we are not an error
    assert(rr.bits[0] == True)          # test the expected value

    log.debug("Write to multiple coils and read back- test 1")
    rq = client.write_coils(1, [True]*8, unit=UNIT)
    assert(not rq.isError())     # test that we are not an error
    rr = client.read_coils(1, 21, unit=UNIT)
    assert(not rr.isError())     # test that we are not an error
    resp = [True]*21

    # If the returned output quantity is not a multiple of eight,
    # the remaining bits in the final data byte will be padded with zeros
    # (toward the high order end of the byte).

    resp.extend([False]*3)
    assert(rr.bits == resp)         # test the expected value

    log.debug("Write to multiple coils and read back - test 2")
    rq = client.write_coils(1, [False]*8, unit=UNIT)
    rr = client.read_coils(1, 8, unit=UNIT)
    assert(not rq.isError())     # test that we are not an error
    assert(rr.bits == [False]*8)         # test the expected value

    log.debug("Read discrete inputs")
    rr = client.read_discrete_inputs(0, 8, unit=UNIT)
    assert(not rq.isError())     # test that we are not an error

    log.debug("Write to a holding register and read back")
    rq = client.write_register(1, 10, unit=UNIT)
    rr = client.read_holding_registers(1, 1, unit=UNIT)
    assert(not rq.isError())     # test that we are not an error
    assert(rr.registers[0] == 10)       # test the expected value

    log.debug("Write to multiple holding registers and read back")
    rq = client.write_registers(1, [10]*8, unit=UNIT)
    rr = client.read_holding_registers(1, 8, unit=UNIT)
    assert(not rq.isError())     # test that we are not an error
    assert(rr.registers == [10]*8)      # test the expected value

    log.debug("Read input registers")
    rr = client.read_input_registers(1, 8, unit=UNIT)
    assert(not rq.isError())     # test that we are not an error

    arguments = {
        'read_address':    1,
        'read_count':      8,
        'write_address':   1,
        'write_registers': [20]*8,
    }
    log.debug("Read write registeres simulataneously")
    rq = client.readwrite_registers(unit=UNIT, **arguments)
    rr = client.read_holding_registers(1, 8, unit=UNIT)
    assert(not rq.isError())     # test that we are not an error
    assert(rq.registers == [20]*8)      # test the expected value
    assert(rr.registers == [20]*8)      # test the expected value

    # ----------------------------------------------------------------------- #
    # close the client
    # ----------------------------------------------------------------------- #
    client.close()
Beispiel #28
0
class modbusport(object):
    """ this class handles the communications with all the modbus devices"""
    def __init__(self, sendmessage, adderror, addserial):
        self.sendmessage = sendmessage  # function to create an Artisan message to the user in the message line
        self.adderror = adderror  # signal an error to the user
        self.addserial = addserial  # add to serial log

        # retries
        self.readRetries = 1
        #default initial settings. They are changed by settingsload() at initiation of program acording to the device chosen
        self.comport = "COM5"  #NOTE: this string should not be translated.
        self.baudrate = 115200
        self.bytesize = 8
        self.parity = 'N'
        self.stopbits = 1
        self.timeout = 1.0
        self.PID_slave_ID = 0
        self.PID_SV_register = 0
        self.PID_p_register = 0
        self.PID_i_register = 0
        self.PID_d_register = 0
        self.PID_ON_action = ""
        self.PID_OFF_action = ""
        self.input1slave = 0
        self.input1register = 0
        self.input1float = False
        self.input1bcd = False
        self.input1code = 3
        self.input1div = 0  # 0: none, 1: 1/10, 2:1/100
        self.input1mode = "C"
        self.input2slave = 0
        self.input2register = 0
        self.input2float = False
        self.input2bcd = False
        self.input2code = 3
        self.input2div = 0
        self.input2mode = "C"
        self.input3slave = 0
        self.input3register = 0
        self.input3float = False
        self.input3bcd = False
        self.input3code = 3
        self.input3div = 0
        self.input3mode = "C"
        self.input4slave = 0
        self.input4register = 0
        self.input4float = False
        self.input4bcd = False
        self.input4code = 3
        self.input4div = 0
        self.input4mode = "C"
        self.input5slave = 0
        self.input5register = 0
        self.input5float = False
        self.input5bcd = False
        self.input5code = 3
        self.input5div = 0
        self.input5mode = "C"
        self.input6slave = 0
        self.input6register = 0
        self.input6float = False
        self.input6bcd = False
        self.input6code = 3
        self.input6div = 0
        self.input6mode = "C"
        self.SVmultiplier = 0
        self.PIDmultiplier = 0
        self.byteorderLittle = False
        self.wordorderLittle = True
        self.master = None
        self.COMsemaphore = QSemaphore(1)
        self.host = '127.0.0.1'  # the TCP/UDP host
        self.port = 502  # the TCP/UDP port
        self.type = 0
        # type =
        #    0: Serial RTU
        #    1: Serial ASCII
        #    2: Serial Binary
        #    3: TCP
        #    4: UDP
        self.lastReadResult = 0  # this is set by eventaction following some custom button/slider Modbus actions with "read" command

        self.commError = False  # True after a communication error was detected and not yet cleared by receiving proper data

    # this garantees a minimum of 30 miliseconds between readings and 80ms between writes (according to the Modbus spec) on serial connections
    # this sleep delays between requests seems to be beneficial on slow RTU serial connections like those of the FZ-94
    def sleepBetween(self, write=False):
        if write:
            #            if self.type in [3,4]: # TCP or UDP
            #                time.sleep(0.040)
            pass  # handled in MODBUS lib
            #            else:
            time.sleep(0.035)
        else:
            if self.type in [
                    3, 4
            ]:  # delay between writes only on serial connections
                pass
            else:
                time.sleep(0.035)

    def address2register(self, addr, code=3):
        if code == 3 or code == 6:
            return addr - 40001
        else:
            return addr - 30001

    def isConnected(self):
        return not (self.master is None) and self.master.socket

    def disconnect(self):
        try:
            self.master.close()
        except Exception:
            pass
        self.master = None

    def connect(self):
        #        if self.master and not self.master.socket:
        #            self.master = None
        if self.master is None:
            self.commError = False
            try:
                # as in the following the port is None, no port is opened on creation of the (py)serial object
                if self.type == 1:  # Serial ASCII
                    from pymodbus.client.sync import ModbusSerialClient
                    self.master = ModbusSerialClient(method='ascii',
                                                     port=self.comport,
                                                     baudrate=self.baudrate,
                                                     bytesize=self.bytesize,
                                                     parity=self.parity,
                                                     stopbits=self.stopbits,
                                                     retry_on_empty=True,
                                                     timeout=self.timeout)
                elif self.type == 2:  # Serial Binary
                    from pymodbus.client.sync import ModbusSerialClient
                    self.master = ModbusSerialClient(method='binary',
                                                     port=self.comport,
                                                     baudrate=self.baudrate,
                                                     bytesize=self.bytesize,
                                                     parity=self.parity,
                                                     stopbits=self.stopbits,
                                                     retry_on_empty=True,
                                                     timeout=self.timeout)
                elif self.type == 3:  # TCP
                    from pymodbus.client.sync import ModbusTcpClient
                    try:
                        self.master = ModbusTcpClient(
                            host=self.host,
                            port=self.port,
                            retry_on_empty=True,
                            retries=1,
                            timeout=0.9,  #self.timeout
                        )
                        self.readRetries = 0
                    except:
                        self.master = ModbusTcpClient(
                            host=self.host,
                            port=self.port,
                        )
                elif self.type == 4:  # UDP
                    from pymodbus.client.sync import ModbusUdpClient
                    try:
                        self.master = ModbusUdpClient(
                            host=self.host,
                            port=self.port,
                            retry_on_empty=True,
                            retries=3,
                            timeout=0.7,  #self.timeout
                        )
                    except:  # older versions of pymodbus don't support the retries, timeout nor the retry_on_empty arguments
                        self.master = ModbusUdpClient(
                            host=self.host,
                            port=self.port,
                        )
                else:  # Serial RTU
                    from pymodbus.client.sync import ModbusSerialClient
                    self.master = ModbusSerialClient(method='rtu',
                                                     port=self.comport,
                                                     baudrate=self.baudrate,
                                                     bytesize=self.bytesize,
                                                     parity=self.parity,
                                                     stopbits=self.stopbits,
                                                     retry_on_empty=False,
                                                     timeout=self.timeout)
                    self.readRetries = 1
                self.master.connect()
                self.adderror(
                    QApplication.translate("Error Message",
                                           "Connected via MODBUS", None))
                time.sleep(.5)  # avoid possible hickups on startup
            except Exception as ex:
                _, _, exc_tb = sys.exc_info()
                self.adderror(
                    (QApplication.translate("Error Message", "Modbus Error:",
                                            None) + " connect() {0}").format(
                                                str(ex)), exc_tb.tb_lineno)

    # function 15 (Write Multiple Coils)
    def writeCoils(self, slave, register, values):
        try:
            #### lock shared resources #####
            self.COMsemaphore.acquire(1)
            self.connect()
            self.master.write_coils(int(register),
                                    list(values),
                                    unit=int(slave))
            time.sleep(.3)  # avoid possible hickups on startup
        except Exception as ex:
            #            self.disconnect()
            #            import traceback
            #            traceback.print_exc(file=sys.stdout)
            _, _, exc_tb = sys.exc_info()
            self.adderror(
                (QApplication.translate("Error Message", "Modbus Error:", None)
                 + " writeCoils() {0}").format(str(ex)), exc_tb.tb_lineno)
        finally:
            if self.COMsemaphore.available() < 1:
                self.COMsemaphore.release(1)

    # function 5 (Write Single Coil)
    def writeCoil(self, slave, register, value):
        try:
            #### lock shared resources #####
            self.COMsemaphore.acquire(1)
            self.connect()
            self.master.write_coil(int(register), value, unit=int(slave))
            time.sleep(.3)  # avoid possible hickups on startup
        except Exception as ex:
            #            self.disconnect()
            _, _, exc_tb = sys.exc_info()
            self.adderror(
                (QApplication.translate("Error Message", "Modbus Error:", None)
                 + " writeCoil() {0}").format(str(ex)), exc_tb.tb_lineno)
        finally:
            if self.COMsemaphore.available() < 1:
                self.COMsemaphore.release(1)

    # write value to register on slave (function 6 for int or function 16 for float)
    # value can be one of string (containing an int or float), an int or a float
    def writeRegister(self, slave, register, value):
        #        print("writeRegister",slave,register,value)
        if stringp(value):
            if "." in value:
                self.writeWord(slave, register, value)
            else:
                self.writeSingleRegister(slave, register, value)
        elif isinstance(value, int):
            self.writeSingleRegister(slave, register, value)
        elif isinstance(value, float):
            self.writeWord(slave, register, value)

    # function 6 (Write Single Holding Register)
    def writeSingleRegister(self, slave, register, value):
        #        _logger.debug("writeSingleRegister(%d,%d,%d)" % (slave,register,value))
        try:
            #### lock shared resources #####
            self.COMsemaphore.acquire(1)
            self.connect()
            self.master.write_register(int(register),
                                       int(value),
                                       unit=int(slave))
            time.sleep(.03)  # avoid possible hickups on startup
        except Exception as ex:
            #            _logger.debug("writeSingleRegister exception: %s" % str(ex))
            #            import traceback
            #            traceback.print_exc(file=sys.stdout)
            #            self.disconnect()
            _, _, exc_tb = sys.exc_info()
            self.adderror(
                (QApplication.translate("Error Message", "Modbus Error:", None)
                 + " writeSingleRegister() {0}").format(str(ex)),
                exc_tb.tb_lineno)
        finally:
            if self.COMsemaphore.available() < 1:
                self.COMsemaphore.release(1)

    # function 22 (Mask Write Register)
    def maskWriteRegister(self, slave, register, and_mask, or_mask):
        try:
            #### lock shared resources #####
            self.COMsemaphore.acquire(1)
            self.connect()
            self.master.mask_write_register(int(register),
                                            int(and_mask),
                                            int(or_mask),
                                            unit=int(slave))
            time.sleep(.03)
        except Exception as ex:
            #            import traceback
            #            traceback.print_exc(file=sys.stdout)
            #            self.disconnect()
            _, _, exc_tb = sys.exc_info()
            self.adderror(
                (QApplication.translate("Error Message", "Modbus Error:", None)
                 + " writeMask() {0}").format(str(ex)), exc_tb.tb_lineno)
        finally:
            if self.COMsemaphore.available() < 1:
                self.COMsemaphore.release(1)

    # function 16 (Write Multiple Holding Registers)
    # values is a list of integers or one integer
    def writeRegisters(self, slave, register, values):
        try:
            #### lock shared resources #####
            self.COMsemaphore.acquire(1)
            self.connect()
            self.master.write_registers(int(register), values, unit=int(slave))
            time.sleep(.03)
        except Exception as ex:
            #            self.disconnect()
            _, _, exc_tb = sys.exc_info()
            self.adderror(
                (QApplication.translate("Error Message", "Modbus Error:", None)
                 + " writeRegisters() {0}").format(str(ex)), exc_tb.tb_lineno)
        finally:
            if self.COMsemaphore.available() < 1:
                self.COMsemaphore.release(1)

    # function 16 (Write Multiple Holding Registers)
    # value=int or float
    # writes a single precision 32bit float (2-registers)
    def writeWord(self, slave, register, value):
        try:
            #### lock shared resources #####
            self.COMsemaphore.acquire(1)
            self.connect()
            builder = getBinaryPayloadBuilder(self.byteorderLittle,
                                              self.wordorderLittle)
            builder.add_32bit_float(float(value))
            payload = builder.build()  # .tolist()
            self.master.write_registers(int(register),
                                        payload,
                                        unit=int(slave),
                                        skip_encode=True)
            time.sleep(.03)
        except Exception as ex:
            #            self.disconnect()
            _, _, exc_tb = sys.exc_info()
            self.adderror(
                (QApplication.translate("Error Message", "Modbus Error:", None)
                 + " writeWord() {0}").format(str(ex)), exc_tb.tb_lineno)
        finally:
            if self.COMsemaphore.available() < 1:
                self.COMsemaphore.release(1)

    # translates given int value int a 16bit BCD and writes it into one register
    def writeBCD(self, slave, register, value):
        try:
            #### lock shared resources #####
            self.COMsemaphore.acquire(1)
            self.connect()
            builder = getBinaryPayloadBuilder(self.byteorderLittle,
                                              self.wordorderLittle)
            r = convert_to_bcd(int(value))
            builder.add_16bit_uint(r)
            payload = builder.build()  # .tolist()
            self.master.write_registers(int(register),
                                        payload,
                                        unit=int(slave),
                                        skip_encode=True)
            time.sleep(.03)
        except Exception as ex:
            #            self.disconnect()
            _, _, exc_tb = sys.exc_info()
            self.adderror(
                (QApplication.translate("Error Message", "Modbus Error:", None)
                 + " writeWord() {0}").format(str(ex)), exc_tb.tb_lineno)
        finally:
            if self.COMsemaphore.available() < 1:
                self.COMsemaphore.release(1)

    # function 3 (Read Multiple Holding Registers) and 4 (Read Input Registers)
    def readFloat(self, slave, register, code=3):
        r = None
        try:
            #### lock shared resources #####
            self.COMsemaphore.acquire(1)
            self.connect()
            retry = self.readRetries
            while True:
                if code == 3:
                    res = self.master.read_holding_registers(int(register),
                                                             2,
                                                             unit=int(slave))
                else:
                    res = self.master.read_input_registers(int(register),
                                                           2,
                                                           unit=int(slave))
                if res is None or res.isError():  # requires pymodbus v1.5.1
                    if retry > 0:
                        retry = retry - 1
                        #time.sleep(0.020)
                    else:
                        raise Exception("Exception response")
                else:
                    break
            decoder = getBinaryPayloadDecoderFromRegisters(
                res.registers, self.byteorderLittle, self.wordorderLittle)
            r = decoder.decode_32bit_float()
            if self.commError:  # we clear the previous error and send a message
                self.commError = False
                self.adderror(
                    QApplication.translate("Error Message",
                                           "Modbus Communication Resumed",
                                           None))
            return r
        except Exception:  # as ex:
            #            import traceback
            #            traceback.print_exc(file=sys.stdout)
            #            self.disconnect()
            #            _, _, exc_tb = sys.exc_info()
            #            self.adderror((QApplication.translate("Error Message","Modbus Error:",None) + " readFloat() {0}").format(str(ex)),exc_tb.tb_lineno)
            self.adderror(
                QApplication.translate("Error Message",
                                       "Modbus Communication Error", None))
        finally:
            if self.COMsemaphore.available() < 1:
                self.COMsemaphore.release(1)
            #note: logged chars should be unicode not binary
            settings = str(self.comport) + "," + str(
                self.baudrate) + "," + str(self.bytesize) + "," + str(
                    self.parity) + "," + str(self.stopbits) + "," + str(
                        self.timeout)
            ser_str = "MODBUS readFloat :" + settings + " || Slave = " + str(
                slave) + " || Register = " + str(
                    register) + " || Code = " + str(code)
            if r is not None:
                ser_str = ser_str + " || Rx = " + str(r)
            self.addserial(ser_str)

    # function 3 (Read Multiple Holding Registers) and 4 (Read Input Registers)
    def readBCD(self, slave, register, code=3):
        r = None
        try:
            #### lock shared resources #####
            self.COMsemaphore.acquire(1)
            self.connect()
            retry = self.readRetries
            while True:
                if code == 3:
                    res = self.master.read_holding_registers(int(register),
                                                             1,
                                                             unit=int(slave))
                else:
                    res = self.master.read_input_registers(int(register),
                                                           1,
                                                           unit=int(slave))
                if res is None or res.isError():  # requires pymodbus v1.5.1
                    if retry > 0:
                        retry = retry - 1
                        #time.sleep(0.020)
                    else:
                        raise Exception("Exception response")
                else:
                    break
            decoder = getBinaryPayloadDecoderFromRegisters(
                res.registers, self.byteorderLittle, self.wordorderLittle)
            r = decoder.decode_16bit_uint()
            if self.commError:  # we clear the previous error and send a message
                self.commError = False
                self.adderror(
                    QApplication.translate("Error Message",
                                           "Modbus Communication Resumed",
                                           None))
            time.sleep(
                0.020
            )  # we add a small sleep between requests to help out the slow Loring electronic
            return convert_from_bcd(r)
        except Exception:  # as ex:
            #            import traceback
            #            traceback.print_exc(file=sys.stdout)
            #            self.disconnect()
            #            _, _, exc_tb = sys.exc_info()
            #            self.adderror((QApplication.translate("Error Message","Modbus Error:",None) + " readBCD() {0}").format(str(ex)),exc_tb.tb_lineno)
            self.adderror(
                QApplication.translate("Error Message",
                                       "Modbus Communication Error", None))
        finally:
            if self.COMsemaphore.available() < 1:
                self.COMsemaphore.release(1)
            #note: logged chars should be unicode not binary
            settings = str(self.comport) + "," + str(
                self.baudrate) + "," + str(self.bytesize) + "," + str(
                    self.parity) + "," + str(self.stopbits) + "," + str(
                        self.timeout)
            ser_str = "MODBUS readBCD :" + settings + " || Slave = " + str(
                slave) + " || Register = " + str(
                    register) + " || Code = " + str(code)
            if r is not None:
                ser_str = ser_str + " || Rx = " + str(r)
            self.addserial(ser_str)

    # as readSingleRegister, but does not retry nor raise and error and returns a None instead
    # also does not reserve the port via a semaphore!
    def peekSingleRegister(self, slave, register, code=3):
        try:
            if code == 1:
                res = self.master.read_coils(int(register), 1, unit=int(slave))
            elif code == 2:
                res = self.master.read_discrete_inputs(int(register),
                                                       1,
                                                       unit=int(slave))
            elif code == 4:
                res = self.master.read_input_registers(int(register),
                                                       1,
                                                       unit=int(slave))
            else:  # code==3
                res = self.master.read_holding_registers(int(register),
                                                         1,
                                                         unit=int(slave))
        except Exception:
            res = None
        if res is not None and not res.isError():  # requires pymodbus v1.5.1
            if code in [1, 2]:
                if res is not None and res.bits[0]:
                    return 1
                else:
                    return 0
            else:
                decoder = getBinaryPayloadDecoderFromRegisters(
                    res.registers, self.byteorderLittle, self.wordorderLittle)
                r = decoder.decode_16bit_uint()
                return r
        else:
            return None

    # function 1 (Read Coil)
    # function 2 (Read Discrete Input)
    # function 3 (Read Multiple Holding Registers) and
    # function 4 (Read Input Registers)
    def readSingleRegister(self, slave, register, code=3):
        #        import logging
        #        logging.basicConfig()
        #        log = logging.getLogger()
        #        log.setLevel(logging.DEBUG)
        r = None
        try:
            #### lock shared resources #####
            self.COMsemaphore.acquire(1)
            self.connect()
            retry = self.readRetries
            while True:
                try:
                    if code == 1:
                        res = self.master.read_coils(int(register),
                                                     1,
                                                     unit=int(slave))
                    elif code == 2:
                        res = self.master.read_discrete_inputs(int(register),
                                                               1,
                                                               unit=int(slave))
                    elif code == 4:
                        res = self.master.read_input_registers(int(register),
                                                               1,
                                                               unit=int(slave))
                    else:  # code==3
                        res = self.master.read_holding_registers(
                            int(register), 1, unit=int(slave))
                except Exception:
                    res = None
                if res is None or res.isError():  # requires pymodbus v1.5.1
                    if retry > 0:
                        retry = retry - 1
                        time.sleep(0.020)
                    else:
                        raise Exception("Exception response")
                else:
                    break
            if code in [1, 2]:
                if res is not None and res.bits[0]:
                    r = 1
                else:
                    r = 0
                return r
            else:
                decoder = getBinaryPayloadDecoderFromRegisters(
                    res.registers, self.byteorderLittle, self.wordorderLittle)
                r = decoder.decode_16bit_uint()
                if self.commError:  # we clear the previous error and send a message
                    self.commError = False
                    self.adderror(
                        QApplication.translate("Error Message",
                                               "Modbus Communication Resumed",
                                               None))
                return r
        except Exception:  # as ex:
            #            self.disconnect()
            #            import traceback
            #            traceback.print_exc(file=sys.stdout)
            #            _, _, exc_tb = sys.exc_info()
            #            self.adderror((QApplication.translate("Error Message","Modbus Error:",None) + " readSingleRegister() {0}").format(str(ex)),exc_tb.tb_lineno)
            self.adderror(
                QApplication.translate("Error Message",
                                       "Modbus Communication Error", None))
            self.commError = True
        finally:
            if self.COMsemaphore.available() < 1:
                self.COMsemaphore.release(1)
            #note: logged chars should be unicode not binary
            settings = str(self.comport) + "," + str(
                self.baudrate) + "," + str(self.bytesize) + "," + str(
                    self.parity) + "," + str(self.stopbits) + "," + str(
                        self.timeout)
            ser_str = "MODBUS readSingleRegister :" + settings + " || Slave = " + str(
                slave) + " || Register = " + str(
                    register) + " || Code = " + str(code)
            if r is not None:
                ser_str = ser_str + " || Rx = " + str(r)
            self.addserial(ser_str)

    def setTarget(self, sv):
        if self.PID_slave_ID:
            multiplier = 1.
            if self.SVmultiplier == 1:
                multiplier = 10.
            elif self.SVmultiplier == 2:
                multiplier = 100.
            self.writeSingleRegister(self.PID_slave_ID, self.PID_SV_register,
                                     int(round(sv * multiplier)))

    def setPID(self, p, i, d):
        if self.PID_slave_ID and not (self.PID_p_register ==
                                      self.PID_i_register ==
                                      self.PID_d_register == 0):
            multiplier = 1.
            if self.PIDmultiplier == 1:
                multiplier = 10.
            elif self.PIDmultiplier == 2:
                multiplier = 100.
            self.writeSingleRegister(self.PID_slave_ID, self.PID_p_register,
                                     p * multiplier)
            self.writeSingleRegister(self.PID_slave_ID, self.PID_i_register,
                                     i * multiplier)
            self.writeSingleRegister(self.PID_slave_ID, self.PID_d_register,
                                     d * multiplier)
Beispiel #29
0
# Can write registers
# registers = builder.to_registers()
# client.write_registers(address, registers, unit=1)

# Or can write encoded binary string

#client.write_register()
#request = ModbusSerialClient.(address, values, **kwargs)
#client.execute(request)

#client.write_register(1, value=payload, skip_encode=True)

import time
onOff = True
while True:
    if onOff:
        payload = on()
    else:
        payload = off()
    onOff = not onOff

    print(payload)

    #client.write_registers(register_address, payload, skip_encode=True, unit=5)
    client.write_registers(0, values=payload, skip_encode=True)
    time.sleep(1)

result = client.read_coils(1, 1)
print(result)
client.close()
class modbusClient:
    """Class to carry out MODBUS read/write requests
    
    Usage:  Ensure all params are setup in the 'modbusSettings' file
            Call 'openConnection' to connect to the assigned server
            Use 'dataHandler' to read or write data to the server
            Call 'closeConnection' to safely close the connection
    """

    def __init__(self):
        """Load settings and connect to the designated slave"""
        
        self.modbusCfg = yamlImport.importYAML("./cfg/modbusSettings.yaml")
        if self.modbusCfg['logging'] == "enable":
            self.log = self.__logging()
        if self.__setupClient() == 0:
            return 0
        if self.openConnection() == 0:
            return 0
            
            
    def __logging(self):
        """Setup and enable logging on the client
        
        :return: enabled log instance
        """
        import logging
        logging.basicConfig()
        log = logging.getLogger()
        log.setLevel(logging.INFO)
        return log
        
        
    def __setupClient(self):
        """Setup MODBUS client object"""
        if self.modbusCfg['method'] == "tcp":
            try:
                self.client = ModbusTcpClient(self.modbusCfg['ip'],\
                                              self.modbusCfg['tcpPort'])
            except:
                raise
                return 0
        elif self.modbusCfg['method'] == "rtu":
            try:
                self.client = ModbusSerialClient(self.modbusCfg['method'],\
                                                 self.modbusCfg['rtuPort'],\
                                                 self.modbusCfg['stopbits'],\
                                                 self.modbusCfg['bytesize'],\
                                                 self.modbusCfg['parity'],\
                                                 self.modbusCfg['baudrate'],\
                                                 self.modbusCfg['timeout'])
            except:
                raise
                return 0
            else:
                raise NameError("Unsupported method")
                return 0
            
            
    def openConnection(self):
        """Attempt connection with the MODBUS server"""
        for i in range(3):
            if self.client.connect() == True:
                return 1
            else:
                print "Attempt " + str(i) + " failed"
            if i == 2:
                raise IOError("Failed to connect to specified server")
                return 0
            time.sleep(0.5)
   

    def closeConnection(self):
        """Close connection with the MODBUS server"""
        try:
            self.client.close()
        except:
            print("Error - See log for details")
            return 0
        return 1
        
    
    def dataHandler(self, op, reg, addr, length=None, data=None, encoding=1):
        """Handle the MODBUS read/write requests and pass to the appropriate function
        
        Arguments:
        :param op: Operation to perform (R/W)
        :param reg: Modbus register to access (1-4)
        :param addr: Address to start operation at
        :type op:  string
        :type reg: int
        :type addr: int
        
        Keyword Arguments:
        :param length: Length of registers to read (default None)
        :param data: Data to write to the slave
        :type length: int
        :type data: list
        
        :return: List containing the requested data or confimation of send.
        """
        if op == 'r':
            for i in range(3):
                r = self.__readData(reg, addr, length, encoding)
                if (r == ConnectionException) or (r == ModbusIOException):
                    print("Read attempt " + str(i) + " failed")
                    if i == 2:
                        #TODO: remove sys exit and handle properly
                        raise SystemExit('Modbus Error: Failed 3 Attemps')
                elif r == ValueError:
                    #TODO: remove sys exit and handle properly
                    raise SystemExit('Invalid Register - Use 15 or 16')
                else:
                    return r
        if op == 'w':
            for i in range(3):
                w = self.__writeData(reg, addr, data, encoding)
                if (w == ConnectionException) or (w == ModbusIOException):
                    print("Write attempt " + str(i) + " failed")
                    if i == 2:
                        #TODO: remove sys exit and handle properly
                        raise SystemExit('Modbus Error: Failed 3 Attemps')
                elif w == ValueError:
                    #TODO: remove sys exit and handle properly
                    raise SystemExit('Invalid Register - Use 15 or 16')
                else:
                    return w
        return ValueError('Invalid Operation')
            
    
    def __readData(self, reg, addr, length, encoding):
        """Read data from the MODBUS Slave
        
        Called by 'dataHandler' in modbusClient.py
        
        Arguments:
        :param reg:      Modbus register to access (1-4)
        :param addr:     Address to start reading from
        :param length:   Quantity of registers to read
        :param encoding: States whether data should be decoded
        :type reg:       int
        :type addr:      int
        :type length:    int
        :type encoding: int
        
        :return:         List containing the requested data or failure exception.
        """
        data = []
        
        if 1 <= reg <= 2:
            try:
                if reg == 1:
                    co = self.client.read_coils(addr,length,unit=0x01)
                else:
                    co = self.client.read_discrete_inputs(addr,length,unit=0x01)
            except ConnectionException:
                return ConnectionException
            
            if co.function_code != reg:
                return ModbusIOException
                
            for i in range(length):
                data.append(co.getBit(i))
            return data
        
        
        elif 3 <= reg <= 4:
            try:
                if reg == 3:
                    hr = self.client.read_holding_registers(addr,length,unit=0x01)
                else:
                    hr = self.client.read_input_registers(addr,length,unit=0x01)
            except ConnectionException:
                return ConnectionException
            
            if hr.function_code != reg:
                return ModbusIOException
                
            for i in range(length):
                data.append(hr.getRegister(i))
            
            if encoding == 1:
                return self.__decodeData(data)
            return data
        
        else:
            return ValueError
            
    
    def __writeData(self, reg, addr, data, encoding):
        """Write data to the MODBUS slave
        
        Called by 'dataHandler' in modbusClient.py
        
        Arguments:
        :param reg:      Modbus register to access (15 or 16)
        :param addr:     Address to start writing to
        :param data:     List of data to write to the device
        :param encoding: States whether data should be encoded first
        :type reg:       int
        :type addr:      int
        :type length:    int
        :type encoding: int
        
        :return:         success or failure exception
        """
        if reg == 15:
            try:
                co = self.client.write_coils(addr,data,unit=0x01)
            except ConnectionException:
                return ConnectionException
            
            if co.function_code != reg:
                return ModbusIOException
        
        elif reg == 16:
            if encoding == 1:
                data = self.__encodeData(data)
            
            try:
                hr = self.client.write_registers(addr,data,unit=0x01)
            except ConnectionException:
                return ConnectionException
            
            if hr.function_code != reg:
                return ModbusIOException
            
        else:
            return ValueError
        
    
    def __encodeData(self, data):
        """Encode data to 32bit float
        
        Function encodes a list of data passed to it into a 32 bit float
        packet that can be written directly to the MODBUS server table.
        
        Arguments:
        :param data: Float to be encoded
        :type data: list
        """
        builder = BinaryPayloadBuilder(endian=Endian.Little)
        try:
            for i in range(0,len(data)):
                builder.add_32bit_float(data[i])
        except TypeError:
            builder.add_32bit_float(data)
        return builder.to_registers()

    def __decodeData(self, data):
        """Decode MODBUS data to float
        
        Function decodes a list of MODBUS 32bit float data passed to it
        into its respective list of floats.
        
        Arguments:
        :param data: Data to be decoded
        :type data: list
        """
        returnData = [0]*(len(data)/2)
        decoder = BinaryPayloadDecoder.fromRegisters(data, endian=Endian.Little)
        for i in range(0,len(data)/2):
            returnData[i] = round(decoder.decode_32bit_float(),2)
        return returnData
Beispiel #31
0
def run_sync_client():
    # ------------------------------------------------------------------------# 
    # choose the client you want
    # ------------------------------------------------------------------------# 
    # make sure to start an implementation to hit against. For this
    # you can use an existing device, the reference implementation in the tools
    # directory, or start a pymodbus server.
    #
    # If you use the UDP or TCP clients, you can override the framer being used
    # to use a custom implementation (say RTU over TCP). By default they use
    # the socket framer::
    #
    #    client = ModbusClient('localhost', port=5020, framer=ModbusRtuFramer)
    #
    # It should be noted that you can supply an ipv4 or an ipv6 host address
    # for both the UDP and TCP clients.
    #
    # There are also other options that can be set on the client that controls
    # how transactions are performed. The current ones are:
    #
    # * retries - Specify how many retries to allow per transaction (default=3)
    # * retry_on_empty - Is an empty response a retry (default = False)
    # * source_address - Specifies the TCP source address to bind to
    #
    # Here is an example of using these options::
    #
    #    client = ModbusClient('localhost', retries=3, retry_on_empty=True)
    # ------------------------------------------------------------------------# 
    # client = ModbusClient('localhost', port=5020)
    # client = ModbusClient(method='ascii', port='/dev/pts/2', timeout=1)
    client = ModbusClient(method='rtu', port='/dev/ttyS3', baudrate=9600, timeout=1)
    client.connect()
    
    # ----------------------------------------------------------------------- #
    # example requests
    # ----------------------------------------------------------------------- #
    # simply call the methods that you would like to use. An example session
    # is displayed below along with some assert checks. Note that some modbus
    # implementations differentiate holding/input discrete/coils and as such
    # you will not be able to write to these, therefore the starting values
    # are not known to these tests. Furthermore, some use the same memory
    # blocks for the two sets, so a change to one is a change to the other.
    # Keep both of these cases in mind when testing as the following will
    # _only_ pass with the supplied async modbus server (script supplied).
    # ----------------------------------------------------------------------- #

    # 读模块型号
    rr = client.read_holding_registers(40001, 1, unit=UNIT)
    print(rr.registers[0])
    
    # 读两路输入(寄存器地址200,共2个)
    log.debug("Read discrete inputs")
    rr = client.read_discrete_inputs(200, 2, unit=UNIT)
    print(rr.bits)  # bit0表示DI1的状态,bit1表示DI2

    # 写单个输出DO1(寄存器地址100)
    log.debug("Write to a Coil and read back")
    rq = client.write_coil(100, True, unit=UNIT)
    rr = client.read_coils(100, 1, unit=UNIT)
    assert(rq.function_code < 0x80)     # test that we are not an error
    assert(rr.bits[0] == True)          # test the expected value
    
    # ----------------------------------------------------------------------- #
    # close the client
    # ----------------------------------------------------------------------- #
    client.close()
#!/usr/bin/env python
# test script to write to coils on enervent ventilation unit

from pymodbus.client.sync import ModbusSerialClient as ModbusClient
import logging
logging.basicConfig()
log = logging.getLogger()
log.setLevel(logging.DEBUG)

client = ModbusClient(method='rtu', port='/dev/ttyUSB0', timeout=1)
client.connect()

log.debug("Reading Coils")
# starting register, number of registers, slave unit id
rr = client.read_coils(12, 1, unit=0x01)

#hh = client.read_holding_registers(1,45,unit=0x01)

#print "holding registers:"
#print hh.registers

#print "coild register:"
#print rr.bits
#print("{}: {}".format("summernight cooling status:", rr.bits[0]))

#rq = client.write_register(53, 70, unit=0x01)
#rqq = client.write_register(53, 71, unit=0x01)

#print rqq
kk =  client.read_holding_registers(53,1,unit=0x01)
print "ventilation:"
Beispiel #33
0
 def poll(self):
     types = {
         'b': 1,
         'B': 1,
         'h': 1,
         'H': 1,
         'i': 2,
         'I': 2,
         'q': 4,
         'Q': 4,
         'f': 2,
         'd': 4,
         's': 0,
         'c': 1
     }
     measures = {}
     self.__lacquire()
     client = ModbusClient(method=self.method,
                           port=self.port,
                           stopbits=self.stopbits,
                           bytesize=self.bytesize,
                           partity=self.parity,
                           baudrate=self.baudrate,
                           timeout=self.timeout,
                           retry_on_empty=True,
                           retry_on_invalid=True)
     if not client.connect():
         logger.error("Cannot connect to device %s" % (self.port))
         self.__lrelease()
         return None
     ut = time.time()
     for row in self.mapping:
         (name, descr, unit, datatype, rw, scale, offset, register) = row
         register = int(register)
         scale = float(scale)
         offset = float(offset)
         length = types.get(datatype)
         string = re.match(r'^s(\d*)$', datatype)
         if string:
             length = int(string.group(1)) >> 1
         try:
             if register > 40000:
                 addr = register - 40001
                 result = client.read_holding_registers(addr,
                                                        length,
                                                        unit=self.slaveid)
             elif register > 30000:
                 addr = register - 30001
                 result = client.read_input_registers(addr,
                                                      length,
                                                      unit=self.slaveid)
             elif register > 10000:
                 addr = register - 10001
                 result = client.read_discrete_inputs(addr,
                                                      length,
                                                      unit=self.slaveid)
             else:
                 addr = register - 1
                 result = client.read_coils(addr, length, unit=self.slaveid)
         except ConnectionException as e:
             logger.error(
                 "Error reading modbus device %s slave %d register %d: %s" %
                 (self.host, self.slaveid, register, str(e)))
             client.close()
             self.__lrelease()
             return None
         if type(result) == ExceptionResponse:
             logger.error(
                 "Error reading modbus device %s slave %d register %d: %s" %
                 (self.port, self.slaveid, register, result))
             client.close()
             self.__lrelease()
             return None
         if result.isError():
             logger.error(
                 "Error reading modbus device %s slave %d register %d" %
                 (self.port, self.slaveid, register))
             client.close()
             self.__lrelease()
             return None
         if hasattr(result, 'bits'):
             measures[name] = result.bits[0]
             logger.debug(
                 'Modbus device: %s slave: %s register: %s (%s) value: %s' %
                 (self.port, self.slaveid, register, name, result.bits[0]))
             continue
         try:
             decoder = BinaryPayloadDecoder.fromRegisters(
                 result.registers,
                 byteorder=Endian.Big,
                 wordorder=self.endian)
             if string:
                 value = decoder.decode_string(255).decode()
                 measures[name] = value
                 logger.debug(
                     'Modbus device: %s slave: %s register: %s (%s) value: %s'
                     % (self.port, self.slaveid, register, name, value))
                 continue
             if datatype == 'b':
                 value = decoder.decode_8bit_int()
             if datatype == 'B':
                 value = decoder.decode_8bit_uint()
             if datatype == 'h':
                 value = decoder.decode_16bit_int()
             if datatype == 'H':
                 value = decoder.decode_16bit_uint()
             if datatype == 'i':
                 value = decoder.decode_32bit_int()
             if datatype == 'I':
                 value = decoder.decode_32bit_uint()
             if datatype == 'q':
                 value = decoder.decode_64bit_int()
             if datatype == 'Q':
                 value = decoder.decode_64bit_uint()
             if datatype == 'f':
                 value = decoder.decode_32bit_float()
             if datatype == 'd':
                 value = decoder.decode_64bit_float()
         except (AttributeError, ValueError, struct.error):
             logger.error(
                 "Error reading modbus device %s slave %d register %d" %
                 (self.port, self.slaveid, register))
             client.close()
             self.__lrelease()
             return None
         if math.isnan(value) or type(value) == bool:
             logger.error(
                 "Error reading modbus device %s slave %d register %d" %
                 (self.port, self.slaveid, register))
             client.close()
             self.__lrelease()
             return None
         measures[name] = round(value * scale, 14) + offset
         logger.debug(
             'Modbus device: %s slave: %s register: %s (%s) value: %s %s' %
             (self.port, self.slaveid, register, name, value, unit))
     client.close()
     self.__lrelease()
     data = {
         'ts': ut,
         'client_id': self.clientid,
         'device_id': self.deviceid,
         'measures': measures
     }
     return data
Beispiel #34
0
print "[01] version ................................... : ",convert_bit_to_string(result.bits[1],"STANDARD+ABSENCE","ALLEMAGNE+STANDBY")
print "[02] free contact .............................. : ",convert_bit_to_string(result.bits[2],"NO","NC")
print "[03] ** UNDOCUMENTED / UNSED ** ................ : ",convert_bit_to_string(result.bits[3],"False","True")
print "[04] ** UNDOCUMENTED / UNSED ** ................ : ",convert_bit_to_string(result.bits[4],"False","True")
print "[05] defroost mode ............................. : ",convert_bit_to_string(result.bits[5],"desactivated","actived")
print "[06] extract motor state ....................... : ",convert_bit_to_string(result.bits[6],"ok","error")
print "[07] input motor state ......................... : ",convert_bit_to_string(result.bits[7],"ok","error")
print "[08] ** UNDOCUMENTED / UNSED ** ................ : ",convert_bit_to_string(result.bits[8],"False","True")
print "[09] ** UNDOCUMENTED / UNSED ** ................ : ",convert_bit_to_string(result.bits[9],"False","True")
print "[10] inside temperature sensor state (tint) .... : ",convert_bit_to_string(result.bits[10],"ok","error")
print "[11] outside temperature sensor state (tout) ... : ",convert_bit_to_string(result.bits[11],"ok","error")
print "[12] extract temperature sensor state (text) ... : ",convert_bit_to_string(result.bits[12],"ok","error")
print "[13] input temperature sensor state (tinp) ..... : ",convert_bit_to_string(result.bits[13],"ok","error")
print "[14] alarm filters state ....................... : ",convert_bit_to_string(result.bits[14],"off","on")

result = client.read_coils(address=0x00, count=14, unit=0x01)
print "===================================================="
print "COILS"
print "===================================================="
print "[00] ** UNDOCUMENTED / UNSED ** ................ : ",convert_bit_to_string(result.bits[0],"False","True")
print "[01] ** UNDOCUMENTED / UNSED ** ................ : ",convert_bit_to_string(result.bits[1],"False","True")
print "[02] pre heating battery ....................... : ",convert_bit_to_string(result.bits[2],"not installed","installed")
print "[03] post heating battery ...................... : ",convert_bit_to_string(result.bits[3],"not installed","installed")
print "[04] sense of switch ........................... : ",convert_bit_to_string(result.bits[4],"no","nc")
print "[05] ** UNDOCUMENTED / UNSED ** ................ : ",convert_bit_to_string(result.bits[5],"False","True")
print "[06] selection of version ...................... : ",convert_bit_to_string(result.bits[6],"STANDBY+ABSENCE","ALLEMAGNE+STANDBY")
print "[07] activation mode stanby absence ............ : ",convert_bit_to_string(result.bits[7],"STANBY/ABSENCE ON","STANDBY/ABSENCE OFF")
print "[08] bypass auto control ....................... : ",convert_bit_to_string(result.bits[8],"actived","desactivated")
print "[09] manual bypass ............................. : ",convert_bit_to_string(result.bits[9],"desactivated","activated")
print "[10] ** UNDOCUMENTED / UNSED ** ................ : ",convert_bit_to_string(result.bits[10],"False","True")
print "[11] ** UNDOCUMENTED / UNSED ** ................ : ",convert_bit_to_string(result.bits[11],"False","True")
Beispiel #35
0
class modbusport(object):
    """ this class handles the communications with all the modbus devices"""
    def __init__(self, sendmessage, adderror, addserial, aw):
        self.sendmessage = sendmessage  # function to create an Artisan message to the user in the message line
        self.adderror = adderror  # signal an error to the user
        self.addserial = addserial  # add to serial log
        self.aw = aw

        # retries
        self.readRetries = 1
        #default initial settings. They are changed by settingsload() at initiation of program acording to the device chosen
        self.comport = "COM5"  #NOTE: this string should not be translated.
        self.baudrate = 115200
        self.bytesize = 8
        self.parity = 'N'
        self.stopbits = 1
        self.timeout = 1.0
        self.PID_slave_ID = 0
        self.PID_SV_register = 0
        self.PID_p_register = 0
        self.PID_i_register = 0
        self.PID_d_register = 0
        self.PID_ON_action = ""
        self.PID_OFF_action = ""

        self.channels = 8
        self.inputSlaves = [0] * self.channels
        self.inputRegisters = [0] * self.channels
        self.inputFloats = [False] * self.channels
        self.inputBCDs = [False] * self.channels
        self.inputCodes = [3] * self.channels
        self.inputDivs = [0] * self.channels  # 0: none, 1: 1/10, 2:1/100
        self.inputModes = ["C"] * self.channels

        self.optimizer = True  # if set, values of consecutive register addresses are requested in single requests
        # MODBUS functions associated to dicts associating MODBUS slave ids to registers in use
        # for optimized read of full register segments with single requests
        # this dict is re-computed on each connect() by a call to updateActiveRegisters()
        # NOTE: for registers of type float and BCD (32bit = 2x16bit) also the succeeding register is registered here
        self.activeRegisters = {}
        # the readings cache that is filled by requesting sequences of values in blocks
        self.readingsCache = {}

        self.SVmultiplier = 0
        self.PIDmultiplier = 0
        self.byteorderLittle = False
        self.wordorderLittle = True
        self.master = None
        self.COMsemaphore = QSemaphore(1)
        self.host = '127.0.0.1'  # the TCP/UDP host
        self.port = 502  # the TCP/UDP port
        self.type = 0
        # type =
        #    0: Serial RTU
        #    1: Serial ASCII
        #    2: Serial Binary
        #    3: TCP
        #    4: UDP
        self.lastReadResult = 0  # this is set by eventaction following some custom button/slider Modbus actions with "read" command

        self.commError = False  # True after a communication error was detected and not yet cleared by receiving proper data

    # this garantees a minimum of 30 miliseconds between readings and 80ms between writes (according to the Modbus spec) on serial connections
    # this sleep delays between requests seems to be beneficial on slow RTU serial connections like those of the FZ-94
    def sleepBetween(self, write=False):
        if write:
            #            if self.type in [3,4]: # TCP or UDP
            #                time.sleep(0.040)
            pass  # handled in MODBUS lib
            #            else:
            time.sleep(0.035)
        else:
            if self.type in [
                    3, 4
            ]:  # delay between writes only on serial connections
                pass
            else:
                time.sleep(0.035)

    def address2register(self, addr, code=3):
        if code == 3 or code == 6:
            return addr - 40001
        else:
            return addr - 30001

    def isConnected(self):
        return not (self.master is None) and self.master.socket

    def disconnect(self):
        try:
            self.master.close()
        except Exception:
            pass
        self.master = None

    def connect(self):
        #        if self.master and not self.master.socket:
        #            self.master = None
        if self.master is None:
            self.commError = False
            try:
                # as in the following the port is None, no port is opened on creation of the (py)serial object
                if self.type == 1:  # Serial ASCII
                    from pymodbus.client.sync import ModbusSerialClient
                    self.master = ModbusSerialClient(method='ascii',
                                                     port=self.comport,
                                                     baudrate=self.baudrate,
                                                     bytesize=self.bytesize,
                                                     parity=self.parity,
                                                     stopbits=self.stopbits,
                                                     retry_on_empty=True,
                                                     timeout=self.timeout)
                elif self.type == 2:  # Serial Binary
                    from pymodbus.client.sync import ModbusSerialClient  # @Reimport
                    self.master = ModbusSerialClient(method='binary',
                                                     port=self.comport,
                                                     baudrate=self.baudrate,
                                                     bytesize=self.bytesize,
                                                     parity=self.parity,
                                                     stopbits=self.stopbits,
                                                     retry_on_empty=True,
                                                     timeout=self.timeout)
                elif self.type == 3:  # TCP
                    from pymodbus.client.sync import ModbusTcpClient
                    try:
                        self.master = ModbusTcpClient(
                            host=self.host,
                            port=self.port,
                            retry_on_empty=True,
                            retries=1,
                            timeout=0.9,  #self.timeout
                        )
                        self.readRetries = 0
                    except:
                        self.master = ModbusTcpClient(
                            host=self.host,
                            port=self.port,
                        )
                elif self.type == 4:  # UDP
                    from pymodbus.client.sync import ModbusUdpClient
                    try:
                        self.master = ModbusUdpClient(
                            host=self.host,
                            port=self.port,
                            retry_on_empty=True,
                            retries=3,
                            timeout=0.7,  #self.timeout
                        )
                    except:  # older versions of pymodbus don't support the retries, timeout nor the retry_on_empty arguments
                        self.master = ModbusUdpClient(
                            host=self.host,
                            port=self.port,
                        )
                else:  # Serial RTU
                    from pymodbus.client.sync import ModbusSerialClient  # @Reimport
                    self.master = ModbusSerialClient(
                        method='rtu',
                        port=self.comport,
                        baudrate=self.baudrate,
                        bytesize=self.bytesize,
                        parity=self.parity,
                        stopbits=self.stopbits,
                        retry_on_empty=False,
                        strict=
                        False,  # settings this to False disables the inter char timeout restriction
                        timeout=self.timeout)
                    #                    self.master.inter_char_timeout = 0.05
                    self.readRetries = 1
                self.master.connect()
                self.updateActiveRegisters()
                time.sleep(.5)  # avoid possible hickups on startup
                if self.isConnected() != None:
                    self.sendmessage(
                        QApplication.translate("Message",
                                               "Connected via MODBUS", None))
            except Exception as ex:
                _, _, exc_tb = sys.exc_info()
                self.adderror(
                    (QApplication.translate("Error Message", "Modbus Error:",
                                            None) + " connect() {0}").format(
                                                str(ex)), exc_tb.tb_lineno)

########## MODBUS optimizer for fetching register data in batches

# MODBUS code => slave => [registers]

    def updateActiveRegisters(self):
        self.activeRegisters = {}
        for c in range(self.channels):
            slave = self.inputSlaves[c]
            if slave != 0:
                register = self.inputRegisters[c]
                code = self.inputCodes[c]
                registers = [register]
                if self.inputFloats[c] or self.inputBCDs[c]:
                    registers.append(register + 1)
                if not (code in self.activeRegisters):
                    self.activeRegisters[code] = {}
                if slave in self.activeRegisters[code]:
                    self.activeRegisters[code][slave].extend(registers)
                else:
                    self.activeRegisters[code][slave] = registers

    def clearReadingsCache(self):
        self.readingsCache = {}

    def cacheReadings(self, code, slave, register, results):
        if not (code in self.readingsCache):
            self.readingsCache[code] = {}
        if not slave in self.readingsCache[code]:
            self.readingsCache[code][slave] = {}
        for i, v in enumerate(results):
            self.readingsCache[code][slave][register + i] = v

    def readActiveRegisters(self):
        if not self.optimizer:
            return
        try:
            #### lock shared resources #####
            self.COMsemaphore.acquire(1)
            self.connect()
            self.clearReadingsCache()
            for code in self.activeRegisters:
                for slave in self.activeRegisters[code]:
                    registers = sorted(self.activeRegisters[code][slave])
                    # split in successive sequences
                    gaps = [[s, e] for s, e in zip(registers, registers[1:])
                            if s + 1 < e]
                    edges = iter(registers[:1] + sum(gaps, []) +
                                 registers[-1:])
                    sequences = list(
                        zip(edges, edges)
                    )  # list of pairs of the form (start-register,end-register)
                    just_send = False
                    for seq in sequences:
                        retry = self.readRetries
                        register = seq[0]
                        count = seq[1] - seq[0] + 1
                        res = None
                        if just_send:
                            self.sleepBetween(
                            )  # we start with a sleep, as it could be that just a send command happend before the semaphore was catched
                        just_send = True
                        while True:
                            try:
                                # we cache only MODBUS function 3 and 4 (not 1 and 2!)
                                if code == 3:
                                    res = self.master.read_holding_registers(
                                        register, count, unit=slave)
                                elif code == 4:
                                    res = self.master.read_input_registers(
                                        register, count, unit=slave)
                            except Exception:
                                res = None
                            if res is None or res.isError(
                            ):  # requires pymodbus v1.5.1
                                if retry > 0:
                                    retry = retry - 1
                                    time.sleep(0.020)
                                else:
                                    raise Exception("Exception response")
                            else:
                                break
                        if res is not None:
                            if self.commError:  # we clear the previous error and send a message
                                self.commError = False
                                self.adderror(
                                    QApplication.translate(
                                        "Error Message",
                                        "Modbus Communication Resumed", None))
                            self.cacheReadings(code, slave, register,
                                               res.registers)

                        #note: logged chars should be unicode not binary
                        if self.aw.seriallogflag:
                            ser_str = "MODBUS readSingleRegister : {},{},{},{},{},{} || Slave = {} || Register = {} || Code = {} || Rx = {}".format(
                                self.comport, self.baudrate, self.bytesize,
                                self.parity, self.stopbits, self.timeout,
                                slave, register, code, res)
                            self.addserial(ser_str)

        except Exception:  # as ex:
            #            self.disconnect()
            #            import traceback
            #            traceback.print_exc(file=sys.stdout)
            #            _, _, exc_tb = sys.exc_info()
            #            self.adderror((QApplication.translate("Error Message","Modbus Error:",None) + " readSingleRegister() {0}").format(str(ex)),exc_tb.tb_lineno)
            self.adderror(
                QApplication.translate("Error Message",
                                       "Modbus Communication Error", None))
            self.commError = True
        finally:
            if self.COMsemaphore.available() < 1:
                self.COMsemaphore.release(1)

##########

# function 15 (Write Multiple Coils)

    def writeCoils(self, slave, register, values):
        try:
            #### lock shared resources #####
            self.COMsemaphore.acquire(1)
            self.connect()
            self.master.write_coils(int(register),
                                    list(values),
                                    unit=int(slave))
            time.sleep(.3)  # avoid possible hickups on startup
        except Exception as ex:
            #            self.disconnect()
            #            import traceback
            #            traceback.print_exc(file=sys.stdout)
            _, _, exc_tb = sys.exc_info()
            self.adderror(
                (QApplication.translate("Error Message", "Modbus Error:", None)
                 + " writeCoils() {0}").format(str(ex)), exc_tb.tb_lineno)
        finally:
            if self.COMsemaphore.available() < 1:
                self.COMsemaphore.release(1)

    # function 5 (Write Single Coil)
    def writeCoil(self, slave, register, value):
        try:
            #### lock shared resources #####
            self.COMsemaphore.acquire(1)
            self.connect()
            self.master.write_coil(int(register), value, unit=int(slave))
            time.sleep(.3)  # avoid possible hickups on startup
        except Exception as ex:
            #            self.disconnect()
            _, _, exc_tb = sys.exc_info()
            self.adderror(
                (QApplication.translate("Error Message", "Modbus Error:", None)
                 + " writeCoil() {0}").format(str(ex)), exc_tb.tb_lineno)
        finally:
            if self.COMsemaphore.available() < 1:
                self.COMsemaphore.release(1)

    # write value to register on slave (function 6 for int or function 16 for float)
    # value can be one of string (containing an int or float), an int or a float
    def writeRegister(self, slave, register, value):
        if stringp(value):
            if "." in value:
                self.writeWord(slave, register, value)
            else:
                self.writeSingleRegister(slave, register, value)
        elif isinstance(value, int):
            self.writeSingleRegister(slave, register, value)
        elif isinstance(value, float):
            self.writeWord(slave, register, value)

    # function 6 (Write Single Holding Register)
    def writeSingleRegister(self, slave, register, value):
        #        _logger.debug("writeSingleRegister(%d,%d,%d)" % (slave,register,value))
        try:
            #### lock shared resources #####
            self.COMsemaphore.acquire(1)
            self.connect()
            self.master.write_register(int(register),
                                       int(value),
                                       unit=int(slave))
            time.sleep(.03)  # avoid possible hickups on startup
        except Exception as ex:
            #            _logger.debug("writeSingleRegister exception: %s" % str(ex))
            #            import traceback
            #            traceback.print_exc(file=sys.stdout)
            #            self.disconnect()
            _, _, exc_tb = sys.exc_info()
            self.adderror(
                (QApplication.translate("Error Message", "Modbus Error:", None)
                 + " writeSingleRegister() {0}").format(str(ex)),
                exc_tb.tb_lineno)
        finally:
            if self.COMsemaphore.available() < 1:
                self.COMsemaphore.release(1)

    # function 22 (Mask Write Register)
    # bits to be modified are "masked" with a 0 in the and_mask (not and_mask)
    # new bit values to be written are taken from the or_mask
    def maskWriteRegister(self, slave, register, and_mask, or_mask):
        try:
            #### lock shared resources #####
            self.COMsemaphore.acquire(1)
            self.connect()
            self.master.mask_write_register(int(register),
                                            int(and_mask),
                                            int(or_mask),
                                            unit=int(slave))
            time.sleep(.03)
        except Exception as ex:
            #            import traceback
            #            traceback.print_exc(file=sys.stdout)
            #            self.disconnect()
            _, _, exc_tb = sys.exc_info()
            self.adderror(
                (QApplication.translate("Error Message", "Modbus Error:", None)
                 + " writeMask() {0}").format(str(ex)), exc_tb.tb_lineno)
        finally:
            if self.COMsemaphore.available() < 1:
                self.COMsemaphore.release(1)

    # a local variant of function 22 (Mask Write Register)
    # the masks are evaluated locally on the given integer value and the result is send via
    # using function 6
    def localMaskWriteRegister(self, slave, register, and_mask, or_mask,
                               value):
        new_val = (int(round(value)) & and_mask) | (or_mask &
                                                    (and_mask ^ 0xFFFF))
        self.writeSingleRegister(slave, register, int(new_val))

    # function 16 (Write Multiple Holding Registers)
    # values is a list of integers or one integer
    def writeRegisters(self, slave, register, values):
        try:
            #### lock shared resources #####
            self.COMsemaphore.acquire(1)
            self.connect()
            self.master.write_registers(int(register), values, unit=int(slave))
            time.sleep(.03)
        except Exception as ex:
            #            self.disconnect()
            _, _, exc_tb = sys.exc_info()
            self.adderror(
                (QApplication.translate("Error Message", "Modbus Error:", None)
                 + " writeRegisters() {0}").format(str(ex)), exc_tb.tb_lineno)
        finally:
            if self.COMsemaphore.available() < 1:
                self.COMsemaphore.release(1)

    # function 16 (Write Multiple Holding Registers)
    # value=int or float
    # writes a single precision 32bit float (2-registers)
    def writeWord(self, slave, register, value):
        try:
            #### lock shared resources #####
            self.COMsemaphore.acquire(1)
            self.connect()
            builder = getBinaryPayloadBuilder(self.byteorderLittle,
                                              self.wordorderLittle)
            builder.add_32bit_float(float(value))
            payload = builder.build()  # .tolist()
            self.master.write_registers(int(register),
                                        payload,
                                        unit=int(slave),
                                        skip_encode=True)
            time.sleep(.03)
        except Exception as ex:
            #            self.disconnect()
            _, _, exc_tb = sys.exc_info()
            self.adderror(
                (QApplication.translate("Error Message", "Modbus Error:", None)
                 + " writeWord() {0}").format(str(ex)), exc_tb.tb_lineno)
        finally:
            if self.COMsemaphore.available() < 1:
                self.COMsemaphore.release(1)

    # translates given int value int a 16bit BCD and writes it into one register
    def writeBCD(self, slave, register, value):
        try:
            #### lock shared resources #####
            self.COMsemaphore.acquire(1)
            self.connect()
            builder = getBinaryPayloadBuilder(self.byteorderLittle,
                                              self.wordorderLittle)
            r = convert_to_bcd(int(value))
            builder.add_16bit_uint(r)
            payload = builder.build()  # .tolist()
            self.master.write_registers(int(register),
                                        payload,
                                        unit=int(slave),
                                        skip_encode=True)
            time.sleep(.03)
        except Exception as ex:
            #            self.disconnect()
            _, _, exc_tb = sys.exc_info()
            self.adderror(
                (QApplication.translate("Error Message", "Modbus Error:", None)
                 + " writeWord() {0}").format(str(ex)), exc_tb.tb_lineno)
        finally:
            if self.COMsemaphore.available() < 1:
                self.COMsemaphore.release(1)

    # function 3 (Read Multiple Holding Registers) and 4 (Read Input Registers)
    def readFloat(self, slave, register, code=3):
        r = None
        try:
            #### lock shared resources #####
            self.COMsemaphore.acquire(1)
            self.connect()
            if code in self.readingsCache and slave in self.readingsCache[code] and register in self.readingsCache[code][slave] \
                and register+1 in self.readingsCache[code][slave]:
                # cache hit
                res = [
                    self.readingsCache[code][slave][register],
                    self.readingsCache[code][slave][register + 1]
                ]
                decoder = getBinaryPayloadDecoderFromRegisters(
                    res, self.byteorderLittle, self.wordorderLittle)
                return decoder.decode_32bit_float()
            else:
                retry = self.readRetries
                while True:
                    if code == 3:
                        res = self.master.read_holding_registers(
                            int(register), 2, unit=int(slave))
                    else:
                        res = self.master.read_input_registers(int(register),
                                                               2,
                                                               unit=int(slave))
                    if res is None or res.isError(
                    ):  # requires pymodbus v1.5.1
                        if retry > 0:
                            retry = retry - 1
                            #time.sleep(0.020)
                        else:
                            raise Exception("Exception response")
                    else:
                        break
                decoder = getBinaryPayloadDecoderFromRegisters(
                    res.registers, self.byteorderLittle, self.wordorderLittle)
                r = decoder.decode_32bit_float()
                if self.commError:  # we clear the previous error and send a message
                    self.commError = False
                    self.adderror(
                        QApplication.translate("Error Message",
                                               "Modbus Communication Resumed",
                                               None))
                return r
        except Exception:  # as ex:
            #            import traceback
            #            traceback.print_exc(file=sys.stdout)
            #            self.disconnect()
            #            _, _, exc_tb = sys.exc_info()
            #            self.adderror((QApplication.translate("Error Message","Modbus Error:",None) + " readFloat() {0}").format(str(ex)),exc_tb.tb_lineno)
            self.adderror(
                QApplication.translate("Error Message",
                                       "Modbus Communication Error", None))
        finally:
            if self.COMsemaphore.available() < 1:
                self.COMsemaphore.release(1)
            #note: logged chars should be unicode not binary
            if self.aw.seriallogflag:
                ser_str = "MODBUS readFloat :{},{},{},{},{},{} || Slave = {} || Register = {} || Code = {} || Rx = {}".format(
                    self.comport, self.baudrate, self.bytesize, self.parity,
                    self.stopbits, self.timeout, slave, register, code, r)
                self.addserial(ser_str)

    # function 3 (Read Multiple Holding Registers) and 4 (Read Input Registers)
    def readBCD(self, slave, register, code=3):
        r = None
        try:
            #### lock shared resources #####
            self.COMsemaphore.acquire(1)
            self.connect()
            if code in self.readingsCache and slave in self.readingsCache[code] and register in self.readingsCache[code][slave] \
                and register+1 in self.readingsCache[code][slave]:
                # cache hit
                res = [
                    self.readingsCache[code][slave][register],
                    self.readingsCache[code][slave][register + 1]
                ]
                decoder = getBinaryPayloadDecoderFromRegisters(
                    [res], self.byteorderLittle, self.wordorderLittle)
                r = decoder.decode_32bit_uint()
                return convert_from_bcd(r)
            else:
                retry = self.readRetries
                while True:
                    if code == 3:
                        res = self.master.read_holding_registers(
                            int(register), 2, unit=int(slave))
                    else:
                        res = self.master.read_input_registers(int(register),
                                                               2,
                                                               unit=int(slave))
                    if res is None or res.isError(
                    ):  # requires pymodbus v1.5.1
                        if retry > 0:
                            retry = retry - 1
                            #time.sleep(0.020)
                        else:
                            raise Exception("Exception response")
                    else:
                        break
                decoder = getBinaryPayloadDecoderFromRegisters(
                    res.registers, self.byteorderLittle, self.wordorderLittle)
                r = decoder.decode_32bit_uint()
                if self.commError:  # we clear the previous error and send a message
                    self.commError = False
                    self.adderror(
                        QApplication.translate("Error Message",
                                               "Modbus Communication Resumed",
                                               None))
                time.sleep(
                    0.020
                )  # we add a small sleep between requests to help out the slow Loring electronic
                return convert_from_bcd(r)
        except Exception:  # as ex:
            #            import traceback
            #            traceback.print_exc(file=sys.stdout)
            #            self.disconnect()
            #            _, _, exc_tb = sys.exc_info()
            #            self.adderror((QApplication.translate("Error Message","Modbus Error:",None) + " readBCD() {0}").format(str(ex)),exc_tb.tb_lineno)
            self.adderror(
                QApplication.translate("Error Message",
                                       "Modbus Communication Error", None))
        finally:
            if self.COMsemaphore.available() < 1:
                self.COMsemaphore.release(1)
            #note: logged chars should be unicode not binary
            if self.aw.seriallogflag:
                ser_str = "MODBUS readBCD : {},{},{},{},{},{} || Slave = {} || Register = {} || Code = {} || Rx = {}".format(
                    self.comport, self.baudrate, self.bytesize, self.parity,
                    self.stopbits, self.timeout, slave, register, code, r)
                self.addserial(ser_str)

    # as readSingleRegister, but does not retry nor raise and error and returns a None instead
    # also does not reserve the port via a semaphore!
    def peekSingleRegister(self, slave, register, code=3):
        try:
            if code == 1:
                res = self.master.read_coils(int(register), 1, unit=int(slave))
            elif code == 2:
                res = self.master.read_discrete_inputs(int(register),
                                                       1,
                                                       unit=int(slave))
            elif code == 4:
                res = self.master.read_input_registers(int(register),
                                                       1,
                                                       unit=int(slave))
            else:  # code==3
                res = self.master.read_holding_registers(int(register),
                                                         1,
                                                         unit=int(slave))
        except Exception:
            res = None
        if res is not None and not res.isError():  # requires pymodbus v1.5.1
            if code in [1, 2]:
                if res is not None and res.bits[0]:
                    return 1
                else:
                    return 0
            else:
                decoder = getBinaryPayloadDecoderFromRegisters(
                    res.registers, self.byteorderLittle, self.wordorderLittle)
                r = decoder.decode_16bit_uint()
                return r
        else:
            return None

    # function 1 (Read Coil)
    # function 2 (Read Discrete Input)
    # function 3 (Read Multiple Holding Registers) and
    # function 4 (Read Input Registers)
    def readSingleRegister(self, slave, register, code=3):
        #        import logging
        #        logging.basicConfig()
        #        log = logging.getLogger()
        #        log.setLevel(logging.DEBUG)
        r = None
        try:
            #### lock shared resources #####
            self.COMsemaphore.acquire(1)
            self.connect()
            if code in self.readingsCache and slave in self.readingsCache[
                    code] and register in self.readingsCache[code][slave]:
                # cache hit
                res = self.readingsCache[code][slave][register]
                decoder = getBinaryPayloadDecoderFromRegisters(
                    [res], self.byteorderLittle, self.wordorderLittle)
                return decoder.decode_16bit_uint()
            else:
                retry = self.readRetries
                while True:
                    try:
                        if code == 1:
                            res = self.master.read_coils(int(register),
                                                         1,
                                                         unit=int(slave))
                        elif code == 2:
                            res = self.master.read_discrete_inputs(
                                int(register), 1, unit=int(slave))
                        elif code == 4:
                            res = self.master.read_input_registers(
                                int(register), 1, unit=int(slave))
                        else:  # code==3
                            res = self.master.read_holding_registers(
                                int(register), 1, unit=int(slave))
                    except Exception:
                        res = None
                    if res is None or res.isError(
                    ):  # requires pymodbus v1.5.1
                        if retry > 0:
                            retry = retry - 1
                            time.sleep(0.020)
                        else:
                            raise Exception("Exception response")
                    else:
                        break
                if code in [1, 2]:
                    if res is not None and res.bits[0]:
                        r = 1
                    else:
                        r = 0
                    if self.commError:  # we clear the previous error and send a message
                        self.commError = False
                        self.adderror(
                            QApplication.translate(
                                "Error Message",
                                "Modbus Communication Resumed", None))
                    return r
                else:
                    decoder = getBinaryPayloadDecoderFromRegisters(
                        res.registers, self.byteorderLittle,
                        self.wordorderLittle)
                    r = decoder.decode_16bit_uint()
                    if self.commError:  # we clear the previous error and send a message
                        self.commError = False
                        self.adderror(
                            QApplication.translate(
                                "Error Message",
                                "Modbus Communication Resumed", None))
                    return r
        except Exception:  # as ex:
            #            self.disconnect()
            #            import traceback
            #            traceback.print_exc(file=sys.stdout)
            #            _, _, exc_tb = sys.exc_info()
            #            self.adderror((QApplication.translate("Error Message","Modbus Error:",None) + " readSingleRegister() {0}").format(str(ex)),exc_tb.tb_lineno)
            self.adderror(
                QApplication.translate("Error Message",
                                       "Modbus Communication Error", None))
            self.commError = True
        finally:
            if self.COMsemaphore.available() < 1:
                self.COMsemaphore.release(1)
            #note: logged chars should be unicode not binary
            if self.aw.seriallogflag:
                ser_str = "MODBUS readSingleRegister : {},{},{},{},{},{} || Slave = {} || Register = {} || Code = {} || Rx = {}".format(
                    self.comport, self.baudrate, self.bytesize, self.parity,
                    self.stopbits, self.timeout, slave, register, code, r)
                self.addserial(ser_str)

    def setTarget(self, sv):
        if self.PID_slave_ID:
            multiplier = 1.
            if self.SVmultiplier == 1:
                multiplier = 10.
            elif self.SVmultiplier == 2:
                multiplier = 100.
            self.writeSingleRegister(self.PID_slave_ID, self.PID_SV_register,
                                     int(round(sv * multiplier)))

    def setPID(self, p, i, d):
        if self.PID_slave_ID and not (self.PID_p_register ==
                                      self.PID_i_register ==
                                      self.PID_d_register == 0):
            multiplier = 1.
            if self.PIDmultiplier == 1:
                multiplier = 10.
            elif self.PIDmultiplier == 2:
                multiplier = 100.
            self.writeSingleRegister(self.PID_slave_ID, self.PID_p_register,
                                     p * multiplier)
            self.writeSingleRegister(self.PID_slave_ID, self.PID_i_register,
                                     i * multiplier)
            self.writeSingleRegister(self.PID_slave_ID, self.PID_d_register,
                                     d * multiplier)
Beispiel #36
0
class DemeterClient(object):
    def __init__(self, unit, modbus_config):
        self.client = ModbusSerialClient(**modbus_config)
        self.unit = unit
        self.valid_commands = {
            'read_holding_registers': self.read_holding_registers,
            'write_registers': self.write_holding_registers,
            'read_input_registers': self.read_input_registers,
            'read_coils': self.read_coils,
            'write_coils': self.write_coils,
            'get_datetime': self.get_datetime,
            'set_datetime': self.set_datetime,
            'get_loginterval': self.get_loginterval,
            'set_loginterval': self.set_loginterval,
            'read_event': self.read_event,
            'write_event': self.write_event,
            'enable_event': self.enable_event,
            'disable_event': self.disable_event,
            'read_events': self.read_events,
            'disable_event': self.disable_event,
            'enable_event': self.enable_event,
            'disable_relay': self.disable_relay,
            'enable_relay': self.enable_relay,
            'temperatura': self.get_temperature,
            'humedad': self.get_humidity,
            'luz': self.get_light,
        }

    def is_valid(self, command):
        return command in self.valid_commands

    def read_holding_registers(self, arguments):
        if len(arguments) != 2:
            return "Modo de uso: read_holding_registers <start-address> <registers>"

        for i in range(0, len(arguments)):
            if not self.__is_number(arguments[i]):
                return "%s: se esperaba un entero" % arguments[i]

        values = [int(x) for x in arguments]

        return self.client.read_holding_registers(address=values[0], count=values[1], unit=self.unit)

    def write_holding_registers(self, arguments):
        if len(arguments) < 2:
            return "Modo de uso: write_holding_registers <start-address> <register-1> <register-2> ... <register-n>"

        for i in range(0, len(arguments)):
            if not self.__is_number(arguments[i]):
                return "%s: se esperaba un entero" % arguments[i]

        values = [int(x) for x in arguments]
        
        return self.client.write_registers(values[0], values[1:], unit=self.unit)

    def get_temperature(self, arguments):
        value = self.client.read_input_registers(address=0, count=1, unit=self.unit)
        if isinstance(value, ReadRegistersResponseBase):
            value = "%d,%d °C" % (value.registers[0]/10, value.registers[0]%10)
        return value

    def get_humidity(self, arguments):
        value = self.client.read_input_registers(address=1, count=1, unit=self.unit)
        if isinstance(value, ReadRegistersResponseBase):
            value = "%d,%d %%" % (value.registers[0]/10, value.registers[0]%10)
        return value

    def get_light(self, arguments):
        value = self.client.read_input_registers(address=2, count=1, unit=self.unit)
        if isinstance(value, ReadRegistersResponseBase):
            value = value.registers[0]
        return value

    def read_input_registers(self, arguments):
        if len(arguments) != 2:
            return "Modo de uso: read_input_registers <start-address> <registers>"

        for i in range(0, len(arguments)):
            if not self.__is_number(arguments[i]):
                return "%s: se esperaba un entero" % arguments[i]

        values = [int(x) for x in arguments]
        
        return self.client.read_input_registers(address=values[0], count=values[1], unit=self.unit)

    def read_coils(self, arguments):
        if len(arguments) != 2:
            return "Modo de uso: read_coils <start-address> <coils>"

        for i in range(0, len(arguments)):
            if not self.__is_number(arguments[i]):
                return "%s: se esperaba un entero" % arguments[i]

        values = [int(x) for x in arguments]
        
        return self.client.read_coils(address=values[0], count=values[1], unit=self.unit)

    def write_coils(self, arguments):
        if len(arguments) < 2:
            return "Modo de uso: write_coils <start-address> <bit-1> <bit-2> ... <bit-n>"

        for i in range(0, len(arguments)):
            if not self.__is_number(arguments[i]):
                return "%s: se esperaba un entero" % arguments[i]

        values = [int(x) for x in arguments]
        
        return self.client.write_coils(address=values[0], values=values[1:], unit=self.unit)

    def get_datetime(self, arguments):
        response = self.client.read_holding_registers(address=1, count=6, unit=self.unit)
        if isinstance(response, ReadRegistersResponseBase):
            r = response.registers
            return "%s/%02d/%02d %02d:%02d:%02d" % (r[0], r[1], r[2], r[3], r[4], r[5])
        return response

    def set_datetime(self, arguments):
        # yyy:mm:dd hh:mm:ss
        if len(arguments) != 6:
            return "Modo de uso: set_datetime <yyyy> <mm> <dd> <hh> <mm> <ss>"

        for i in range(0, 6):
            if not self.__is_number(arguments[i]):
                return "%s: se esperaba un entero" % arguments[i]

        values = [int(x) for x in arguments]

        return self.client.write_registers(address=1, values=values, unit=self.unit)

    def get_loginterval(self, arguments):
        response = self.client.read_holding_registers(address=0, count=1, unit=self.unit)
        if isinstance(response, ReadRegistersResponseBase):
            return response.registers[0]
        return response

    def set_loginterval(self, arguments):
        if len(arguments) != 1:
            return "Modo de uso: set_loginterval <segunos>"

        if not self.__is_number(arguments[0]):
            return "%s: se esperaba un entero" % arguments[0]

        return self.client.write_registers(address=0, values=[int(arguments[0])], unit=self.unit)

    def read_event(self, arguments):
        if len(arguments) != 1:
            return "Modo de uso: read_event <numero de evento>"

        if not self.__is_number(arguments[0]):
            return "%s: se esperaba un entero" % arguments[0]

        number = int(arguments[0])
        response = self.client.read_holding_registers(address=number * 6 + 7, count=6, unit=self.unit)
        if isinstance(response, ReadRegistersResponseBase):
            return self.__print_event(number, response.registers)
        return response

    def write_event(self, arguments):
        # nro de evento + 6 campos
        if len(arguments) != (1 + 6):
            return "Modo de uso: write_event <numero de evento> <hh>:<mm>:<ss> <duracion> <relay> <1|0>"

        for i in range(0, 7):
            if not self.__is_number(arguments[i]):
                return "%s: se esperaba un entero" % arguments[i]

        number = int(arguments[0])

        values = [int(x) for x in arguments[1:]]
        if values[5] not in [0,1]:
            return "%s: el valor debe ser cero o uno" % values[5]

        return self.client.write_registers(address=number * 6 + 7, values=values, unit=self.unit)

    def disable_event(self, arguments):
        # nro de evento
        if len(arguments) != 1:
            return "Modo de uso: disable_event <numero de evento>"

        if not self.__is_number(arguments[0]):
            return "%s: se esperaba un entero" % arguments[i]

        number = int(arguments[0])

        return self.client.write_registers(address=number * 6 + 5, values=[0], unit=self.unit)

    def enable_event(self, arguments):
        # nro de evento
        if len(arguments) != 1:
            return "Modo de uso: disable_event <numero de evento>"

        if not self.__is_number(arguments[0]):
            return "%s: se esperaba un entero" % arguments[i]

        number = int(arguments[0])

        return self.client.write_registers(address=number * 6 + 5, values=[0], unit=self.unit)

    def read_events(self, arguments):
        response = self.client.read_holding_registers(address=7, count=6 * 10, unit=self.unit)
        if isinstance(response, ReadRegistersResponseBase):
            str = ""
            for i in range(0, 10):
                str += self.__print_event(i, response.registers[i * 6:(i + 1) * 6])
                str += "\n"
            return str
        return response

    def disable_event(self, arguments):
        if len(arguments) != 1:
            return "Modo de uso: disable_event <numero de evento>"

        if not self.__is_number(arguments[0]):
            return "%s: se esperaba un entero" % arguments[0]

        number = int(arguments[0])

        return self.client.write_registers(address=number * 6 + 7 + 5, values=[0], unit=self.unit)

    def enable_event(self, arguments):
        if len(arguments) != 1:
            return "Modo de uso: enable_event <numero de evento>"

        if not self.__is_number(arguments[0]):
            return "%s: se esperaba un entero" % arguments[0]

        number = int(arguments[0])

        return self.client.write_registers(address=number * 6 + 7 + 5, values=[1], unit=self.unit)

    def disable_relay(self, arguments):
        if len(arguments) != 1:
            return "Modo de uso: disable_relay <numero de relay>"

        if not self.__is_number(arguments[0]):
            return "%s: se esperaba un entero" % arguments[0]

        number = int(arguments[0])
        if number not in [0, 1]:
            return "%d: solo hay dos relays" % number
        
        return self.client.write_coils(address=number, values=[0], unit=self.unit)

    def enable_relay(self, arguments):
        if len(arguments) != 1:
            return "Modo de uso: disable_relay <numero de relay>"

        if not self.__is_number(arguments[0]):
            return "%s: se esperaba un entero" % arguments[0]

        number = int(arguments[0])
        if number not in [0, 1]:
            return "%d: solo hay dos relays" % number

        return self.client.write_coils(address=number, values=[1], unit=self.unit)

    def dummy(self, arguments):
        return None

    def execute(self, command, arguments):
        return self.valid_commands.get(command, self.dummy)(arguments)

    def __print_event(self, number, data):
        return "Evento #%d (%s) => Inicia a las %02d:%02d:%02d hs., dura: %d segs. y ejecuta en relay #%d" % (
                                    number, ("habilitado" if data[5] != 0 else "deshabilitado"), data[0],
                                    data[1], data[2], data[3], data[4])
    def __is_number(self, str):
        try:
            int(str)
        except ValueError:
            return False
        return True