class TestClientServer(unittest.TestCase):
    def setUp(self):
        # modbus server
        self.server = ModbusServer(port=5020, no_block=True)
        self.server.start()
        # modbus client
        self.client = ModbusClient(port=5020)
        self.client.open()

    def tearDown(self):
        self.client.close()

    def test_read_and_write(self):
        # word space
        self.assertEqual(self.client.read_holding_registers(0), [0],
                         'Default value is 0 when server start')
        self.assertEqual(self.client.read_input_registers(0), [0],
                         'Default value is 0 when server start')
        # single read/write
        self.assertEqual(self.client.write_single_register(0, 0xffff), True)
        self.assertEqual(self.client.read_input_registers(0), [0xffff])
        # multi-write at max size
        words_l = [randint(0, 0xffff)] * 0x7b
        self.assertEqual(self.client.write_multiple_registers(0, words_l),
                         True)
        self.assertEqual(self.client.read_holding_registers(0, len(words_l)),
                         words_l)
        self.assertEqual(self.client.read_input_registers(0, len(words_l)),
                         words_l)
        # write over sized
        words_l = [randint(0, 0xffff)] * 0x7c
        self.assertEqual(self.client.write_multiple_registers(0, words_l),
                         None)
        # bit space
        self.assertEqual(self.client.read_coils(0), [False],
                         'Default value is False when server start')
        self.assertEqual(self.client.read_discrete_inputs(0), [False],
                         'Default value is False when server start')
        # single read/write
        self.assertEqual(self.client.write_single_coil(0, True), True)
        self.assertEqual(self.client.read_coils(0), [True])
        self.assertEqual(self.client.read_discrete_inputs(0), [True])
        # multi-write at min size
        bits_l = [getrandbits(1)] * 0x1
        self.assertEqual(self.client.write_multiple_coils(0, bits_l), True)
        self.assertEqual(self.client.read_coils(0, len(bits_l)), bits_l)
        self.assertEqual(self.client.read_discrete_inputs(0, len(bits_l)),
                         bits_l)
        # multi-write at max size
        bits_l = [getrandbits(1)] * 0x7b0
        self.assertEqual(self.client.write_multiple_coils(0, bits_l), True)
        self.assertEqual(self.client.read_coils(0, len(bits_l)), bits_l)
        self.assertEqual(self.client.read_discrete_inputs(0, len(bits_l)),
                         bits_l)
        # multi-write over sized
        bits_l = [getrandbits(1)] * 0x7b1
        self.assertEqual(self.client.write_multiple_coils(0, bits_l), None)
Example #2
0
class TestClientServer(unittest.TestCase):

    def setUp(self):
        # modbus server
        self.server = ModbusServer(port=5020, no_block=True)
        self.server.start()
        # modbus client
        self.client = ModbusClient(port=5020)
        self.client.open()

    def tearDown(self):
        self.client.close()

    def test_read_and_write(self):
        # word space
        self.assertEqual(self.client.read_holding_registers(0), [0], 'Default value is 0 when server start')
        self.assertEqual(self.client.read_input_registers(0), [0], 'Default value is 0 when server start')
        # single read/write
        self.assertEqual(self.client.write_single_register(0, 0xffff), True)
        self.assertEqual(self.client.read_input_registers(0), [0xffff])
        # multi-write at max size
        words_l = [randint(0, 0xffff)] * 0x7b
        self.assertEqual(self.client.write_multiple_registers(0, words_l), True)
        self.assertEqual(self.client.read_holding_registers(0, len(words_l)), words_l)
        self.assertEqual(self.client.read_input_registers(0, len(words_l)), words_l)
        # write over sized
        words_l = [randint(0, 0xffff)] * 0x7c
        self.assertEqual(self.client.write_multiple_registers(0, words_l), None)
        # bit space
        self.assertEqual(self.client.read_coils(0), [False], 'Default value is False when server start')
        self.assertEqual(self.client.read_discrete_inputs(0), [False], 'Default value is False when server start')
        # single read/write
        self.assertEqual(self.client.write_single_coil(0, True), True)
        self.assertEqual(self.client.read_coils(0), [True])
        self.assertEqual(self.client.read_discrete_inputs(0), [True])
        # multi-write at min size
        bits_l = [getrandbits(1)] * 0x1
        self.assertEqual(self.client.write_multiple_coils(0, bits_l), True)
        self.assertEqual(self.client.read_coils(0, len(bits_l)), bits_l)
        self.assertEqual(self.client.read_discrete_inputs(0, len(bits_l)), bits_l)
        # multi-write at max size
        bits_l = [getrandbits(1)] * 0x7b0
        self.assertEqual(self.client.write_multiple_coils(0, bits_l), True)
        self.assertEqual(self.client.read_coils(0, len(bits_l)), bits_l)
        self.assertEqual(self.client.read_discrete_inputs(0, len(bits_l)), bits_l)
        # multi-write over sized
        bits_l = [getrandbits(1)] * 0x7b1
        self.assertEqual(self.client.write_multiple_coils(0, bits_l), None)
Example #3
0
 def read_all_tags(self):
     try:
         c = ModbusClient(host="192.168.2.11", port=502, debug=False)
         c.open()
         
         for name, tag in self.tag_db.items():
             mb0 = tag['modbus_start'] -1
             mb1 = tag['modbus_stop'] -1
             size = 1+mb1-mb0
             #print(name, mb0, mb1, size)
             #print(tag)
             if 0 <= mb0 < 100000:
                 val = c.read_coils(mb0)[0]
             elif 100000 <= mb0 < 200000:
                 val = c.read_discrete_inputs(mb0-100000)[0]
             elif 300000 <= mb0 < 400000:
                 val = c.read_input_registers(mb0-300000,  size)
                 if size == 1: val = val[0]
                 elif size == 2:
                     val = utils.word_list_to_long(val, big_endian=False)[0]
             elif 400000 <= mb0 < 500000:
                 val = c.read_holding_registers(mb0-400000,  size )
                 if size == 1: val = val[0]
                 elif size == 2:
                     val = utils.word_list_to_long(val, big_endian=False)[0]
             
             if tag['dtype'] == 'float32':
                 val = utils.decode_ieee(val)
             
             #print(name, val)
             self.settings[name] = val
                 
     except Exception as err:
         print("Error in read_all_tags", err)
         c.close()        
Example #4
0
def read_valid_registers(target_ip, port, reg):
    result = False
    print(f'\n=====Polling remote server for {reg}:=====')
    for i in range(start_reg, end_reg):
        client = ModbusClient(host=target_ip,
                              port=port,
                              auto_open=True,
                              auto_close=True,
                              timeout=10)
        if reg == "hold":
            data = client.read_holding_registers(i, 1)
        if reg == "input":
            data = client.read_input_registers(i, 1)
        if reg == "discrete":
            data = client.read_discrete_inputs(i, 1)
        if reg == "coil":
            data = client.read_coils(i, 1)
        if data:
            result = True
            print(f'\nValid Registers {reg} detected at {i} with value {data}')
        client.close()
        print('/', end='')
        sleep(0.1)


#	return valid_list,data_list,permission_list
    if result != True:
        print(f'\n No Valid Registers detected in specified range')
Example #5
0
def callback(marker_array, inputs):
    output_address = inputs[0]
    input_address = inputs[1]
    zone_distance = inputs[2]
    grid_x = inputs[3]
    #Create a connection with the ADAM-6052
    adam = ModbusClient(host="192.168.1.3",
                        port=502,
                        auto_open=True,
                        auto_close=False)

    #Calculate distance to nearest object
    distance = 100
    for marker in marker_array.markers:
        xpos = marker.pose.position.x
        xsize = marker.scale.x
        #Set distance if new distance is smaller
        if xpos - float(xsize) / 2 - grid_x < distance:
            distance = xpos - float(xsize) / 2 - grid_x

    a = adam.read_discrete_inputs(int(input_address))
    #If it is a valid read
    if type(a) == type([]):
        #If HIGH
        if a[0] == 1:
            rospy.loginfo("System is in reduced distance mode")
            #If there is an obstruction less than xm detected write pin False
            if distance <= int(zone_distance):
                rospy.logwarn("Obstruction has been detected")
                adam.write_single_coil(int(output_address), False)
            #If there is an no obstruction less than xm detected write pin False
            else:
                rospy.loginfo("No Obsturction has been detected")
                adam.write_single_coil(int(output_address), True)
        #If LOW
        elif a[0] == 0:
            #If there is an obstruction detected write pin False
            if len(marker_array.markers) > 0:
                rospy.logwarn("Obstruction has been detected")
                adam.write_single_coil(int(output_address), False)
            #If there is no obstruction detected write pin True
            else:
                rospy.loginfo("No Obsturction has been detected")
                adam.write_single_coil(int(output_address), True)
    else:
        rospy.logwarn("Connection to adam failed")
Example #6
0
def read_valid_registers(ip_addr,port,reg):
	valid_list=[]
	data_list=[]
	permission_list=[]
	client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10)
	for i in tqdm(range(1,500)):
		if reg == "hold":
			data=client.read_holding_registers(i,1)
		if reg == "input":
			data=client.read_input_registers(i,1)
		if reg == "discrete":
			data=client.read_discrete_inputs(i,1)
		if reg == "coil":
			data=client.read_coils(i,1)
		if data:
				valid_list.append(i)
				data_list.append(data[0])
				permission_list.append("Read")
	client.close()
	return valid_list,data_list,permission_list
Example #7
0
def monitor_register(target_ip, port, address, delay, reg):
    while True:
        client = ModbusClient(host=target_ip,
                              port=port,
                              auto_open=True,
                              auto_close=True,
                              timeout=1)
        if reg == "Holding":
            data = client.read_holding_registers(address, 1)
        if reg == "Input":
            data = client.read_input_registers(address, 1)
        if reg == "Discrete":
            data = client.read_discrete_inputs(address, 1)
        if reg == "Coil":
            data = client.read_coils(address, 1)
        if data:
            print(f'{reg} register at address {address} has value {data}')
        #print ('.', end='')
        client.close()
        sleep(delay)
Example #8
0
# TCP auto connect on first modbus request
#c = ModbusClient(host="localhost", port=502, auto_open=True)

# TCP auto connect on modbus request, close after it
#c = ModbusClient(host="127.0.0.1", auto_open=True, auto_close=True)

c = ModbusClient()
c.host("192.168.58.10")
c.port(502)
# managing TCP sessions with call to c.open()/c.close()
c.open()

# to debug the communication
#c.debug(True)
inputRegD = c.read_discrete_inputs(0, 16)
coil = c.read_coils(0, 16)
read_holding = c.read_holding_registers(0, 2)
inputReg = c.read_input_registers(0, 2)

while True:
    if inputRegD:
        #print(regs)
        #print(type(regs))
        #print(type(coil))
        x = inputRegD[5]
        print("Read Input: " + str(inputRegD))
        print("Read Coils: " + str(coil))
        print("Holding Register: " + str(read_holding))
        print("Read Input Register: " + str(inputReg))
Example #9
0
class ThermiaGenesis:  # pylint:disable=too-many-instance-attributes
    """Main class to perform modbus requests to heat pump."""

    def __init__(self, host, port=502, kind='inverter', delay=0.1, max_registers=16):
        """Initialize."""

        self.data = {}
        self._client = ModbusClient(host, port=port, unit_id=1, auto_open=True)
        self.firmware = None
        if(kind == MODEL_MEGA): self.model = "Mega"
        else: self.model = "Diplomat Inverter"
        self._host = host
        self._port = port
        self._kind = kind
        self._delay = delay
        self.MAX_REGISTERS = max_registers

        _LOGGER.debug("Using host: %s:%d", host, port)

    async def async_set(self, register, value):  # pylint:disable=too-many-branches
        """Write data to heat pump."""
        ret_value = await self._set_data(register, value)
        self._client.close()

    async def async_update(self, register_types=REG_TYPES, only_registers = None):  # pylint:disable=too-many-branches
        """Update data from heat pump."""
        use_registers = []
        if(only_registers != None):
            #Make sure to sort registers by type and address
            use_registers = sorted(only_registers, key=(lambda x: f"{REGISTERS[x][KEY_REG_TYPE]}-{REGISTERS[x][KEY_ADDRESS]:03}"))
        else:
            use_registers = dict(filter(lambda x: x[1][self._kind], REGISTERS.items())).keys()

        raw_data = await self._get_data(use_registers)
        self._client.close()

        if not raw_data:
            self.data = {}
            return {}

        #_LOGGER.debug("RAW data: %s", raw_data)
        data = {}
        try:
            for i, (name, val) in enumerate(raw_data.items()):
                data[name] = val

            self.firmware = f"{self.data[ATTR_INPUT_SOFTWARE_VERSION_MAJOR]}.{self.data[ATTR_INPUT_SOFTWARE_VERSION_MINOR]}.{self.data[ATTR_INPUT_SOFTWARE_VERSION_MICRO]}"

            _LOGGER.debug("------------- REGISTERS ----------------------")
            for i, (name, val) in enumerate(self.data.items()):
                _LOGGER.debug(f"{REGISTERS[name][KEY_ADDRESS]}\t{val}\t{name}")


        except AttributeError as err:
            _LOGGER.debug("Incomplete data from modbus.")
            _LOGGER.debug(err)
        except KeyError as err: 
            _LOGGER.debug("Incomplete data from modbus.")
            _LOGGER.debug(err)
        except TypeError as err:
            _LOGGER.debug("Incomplete data from modbus.")
            _LOGGER.debug(err)
        self.data = data
        return data

    @property
    def available(self):
        """Return True is data is available."""
        return bool(self.data)


    async def _set_data(self, register, value):
        meta = REGISTERS[register]
        regtype = meta[KEY_REG_TYPE]
        address = meta[KEY_ADDRESS]
        scale = meta[KEY_SCALE]
        await asyncio.sleep(self._delay)
        try:
            if(regtype == REG_COIL):
                _LOGGER.debug(f"Set {regtype} register at {address} value {value} ({value})")
                self._client.write_single_coil(address, value)
            elif(regtype == REG_HOLDING):
                converted_value = int(value * scale)
                if(meta[KEY_DATATYPE] == TYPE_INT):
                    converted_value = num_to_bin(converted_value)
                _LOGGER.debug(f"Set {regtype} register at {address} value {converted_value} ({value}) {scale}")
                self._client.write_single_register(address, converted_value)
            else: 
                raise "This register can not be changed"
        except Exception as e:
            _LOGGER.error(f'exception: {e}')
            print(traceback.format_exc())
        return value


    async def _get_data(self, registers):
        """Retreive data from heat pump."""
        raw_data = {}
        #Split into requests that reads up to self.MAX_REGISTERS within REGISTER_RANGES (register blocks) for the requested registers
        first_chunk_address = 0
        current_type = None
        chunks = []
        chunk = None
        for name in registers:
            meta = REGISTERS[name]

            if(name == ATTR_HOLDING_FIXED_SYSTEM_SUPPLY_SET_POINT):
                #This will give an errror unless coil 42 is True, so skip if we don't know this or if it's false
                enableAttr = ATTR_COIL_ENABLE_FIXED_SYSTEM_SUPPLY_SET_POINT
                if(enableAttr not in raw_data and enableAttr not in self.data): 
                    _LOGGER.debug(f"Will not read {name} since we don't know if {ATTR_COIL_ENABLE_FIXED_SYSTEM_SUPPLY_SET_POINT} is set, include this register in the request to read this")
                    continue
                if(not raw_data[ATTR_COIL_ENABLE_FIXED_SYSTEM_SUPPLY_SET_POINT] and not self.data[ATTR_COIL_ENABLE_FIXED_SYSTEM_SUPPLY_SET_POINT]):
                    _LOGGER.debug(f"Will not read {name} since {ATTR_COIL_ENABLE_FIXED_SYSTEM_SUPPLY_SET_POINT} is False which disables this register")
                    continue

            reg_address = meta[KEY_ADDRESS]
            if(chunk == None #First iteration
                    or chunk[KEY_REG_TYPE] != meta[KEY_REG_TYPE] #New register type
                    or (reg_address - chunk['start']) >= self.MAX_REGISTERS #Exceeds max number of registers per request
                    or reg_address > chunk['range_end']): #Address belongs to another register block
                if(chunk != None):
                    chunks.append(chunk)
                start = meta[KEY_ADDRESS]
                chunk = { KEY_REG_TYPE: meta[KEY_REG_TYPE], 'start': start, 'slots': { name: 0 } }

                if(meta[KEY_DATATYPE] == TYPE_LONG): 
                    chunk['end'] = start + 1
                else: 
                    chunk['end'] = start

                in_range = list(filter(lambda x: x[0] <= start and x[1] >= start, REGISTER_RANGES[self._kind][meta[KEY_REG_TYPE]]))
                chunk['range_end'] = in_range[0][1]

            else:
                chunk['slots'][name] = reg_address - start
                if(meta[KEY_DATATYPE] == TYPE_LONG):
                    chunk['end'] = reg_address + 1
                else:
                    chunk['end'] = reg_address
        if(chunk != None): chunks.append(chunk)
        _LOGGER.info(f"Will make {len(chunks)} requests to read {len(registers)} registers")
        #print(f"Will make {len(chunks)} requests to read {len(registers)} registers")

        try:
            for chunk in chunks:
                await asyncio.sleep(self._delay)
                start_address = chunk['start']
                length = chunk['end'] - chunk['start'] + 1
                regtype = chunk[KEY_REG_TYPE]
                _LOGGER.debug(f"Reading {regtype} {start_address} length {length}")
                read_data = None
                if(regtype == REG_COIL):
                    read_data = self._client.read_coils(start_address, length)
                elif(regtype == REG_DISCRETE_INPUT):
                    read_data = self._client.read_discrete_inputs(start_address, length)
                elif(regtype == REG_INPUT):
                    read_data = self._client.read_input_registers(start_address, length)
                elif(regtype == REG_HOLDING):
                    read_data = self._client.read_holding_registers(start_address, length)
                if read_data:
                    for i, (name, address) in enumerate(chunk['slots'].items()):
                        info = REGISTERS[name]
                        datatype = info[KEY_DATATYPE]
                        scale = info[KEY_SCALE]
                        val = read_data[address]
                        if(datatype == TYPE_LONG):
                            regs = read_data[address:(address+2)]
                            val = word_list_to_long(regs)[0]
                        elif(datatype == TYPE_INT):
                            if(val == 32767): val = 0
                            if(val > 32767): val = val - 65536
                        elif(datatype == TYPE_STATUS):
                            status_str = "OFF"
                            if val == 1:
                                status_str = "Manual Operation"
                            elif val == 2:
                                status_str = "Defrost"
                            elif val == 3:
                                status_str = "Hot water"
                            elif val == 4:
                                status_str = "Heat"
                            elif val == 5:
                                status_str = "Cool"
                            elif val == 6:
                                status_str = "Pool"
                            elif val == 7:
                                status_str = "Anti legionella"
                            elif val == 98:
                                status_str = "Standby"
                            elif val == 99:
                                status_str = "No demand"
                            val = status_str

                        if(scale != 1): val = val / scale
                        raw_data[name] = val
                else:
                    if self._client.last_error() > 0:
                        _LOGGER.error(f'error {self._client.last_error()}')
                    raise Exception(f"Failed to read {regtype} {start_address} length {length}", self._client.last_error())
            #for regtype in register_types:
            #    last_chunk_address = 0
            #    values = []
            #    for chunk in REGISTER_RANGES[self._kind][regtype]:
            #        await asyncio.sleep(self._delay)
            #        start_address = chunk[0]
            #        length = chunk[1] - start_address
            #        #Insert 0 if there is a gap
            #        values.extend([0] * (start_address - last_chunk_address))
            #        _LOGGER.debug(f"Reading {regtype} {start_address} length {length}")
            #        read_data = None
            #        if(regtype == REG_COIL):
            #            read_data = self._client.read_coils(start_address, length)
            #        elif(regtype == REG_DISCRETE_INPUT):
            #            read_data = self._client.read_discrete_inputs(start_address, length)
            #        elif(regtype == REG_INPUT):
            #            read_data = self._client.read_input_registers(start_address, length)
            #        elif(regtype == REG_HOLDING):
            #            read_data = self._client.read_holding_registers(start_address, length)
            #        if read_data:
            #            values.extend(read_data)
            #        else:
            #            if self._client.last_error() > 0:
            #                print(f'error {self._client.last_error()}')
            #                _LOGGER.error(f'error {self._client.last_error()}')
            #            raise Exception(f"Failed to read {regtype} {start_address} length {length}", self._client.last_error())
            #        last_chunk_address = chunk[1]
            #    raw_data[regtype] = values
        except Exception as e:
            _LOGGER.error(f'exception: {e}')
            print(traceback.format_exc())

        return raw_data
def get_points(conn, devices):
    for device in devices:
        try:
            cur = conn.cursor()
            #Get IP Address and port from database
            cur.execute("SELECT ip, port FROM device WHERE devID = ?",
                        (device, ))
            request = cur.fetchone()
            ip = request[0]
            port = request[1]

            client = ModbusClient()
            client.host(ip)
            client.port(port)

            client_connected = True
            if (client.is_open() == False):
                if (client.open() == False):
                    print("Unable to connect to " + ip + ":" + str(port))
                    client_connected = False

            if (client_connected == True):
                cur.execute(
                    "SELECT name, address, type, pointID, mult_factor FROM device_points WHERE devID = ? AND deleted = 0",
                    (device, ))
                rows = cur.fetchall()

                for row in rows:
                    if (row[2] == "dig_in"):
                        req = client.read_discrete_inputs(int(row[1]), 1)

                        datetime_str = datetime.now().strftime(
                            "%Y-%m-%d %H:%M:%S.%f")
                        point_ID = row[3]
                        value = req[0] * row[4]
                        print(datetime_str + " | " + str(point_ID) + " | " +
                              str(value))
                        cur.execute("INSERT INTO point_data VALUES (?, ?, ?)",
                                    (datetime_str, point_ID, value))
                        #print("Value for point " + row[0] + ": " + str(req) + datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f"))

                    if (row[2] == "dig_out"):
                        req = client.read_coils(int(row[1]), 1)

                        datetime_str = datetime.now().strftime(
                            "%Y-%m-%d %H:%M:%S.%f")
                        point_ID = row[3]
                        value = req[0] * row[4]
                        error_code = 0
                        print(datetime_str + " | " + str(point_ID) + " | " +
                              str(value))
                        cur.execute("INSERT INTO point_data VALUES (?, ?, ?)",
                                    (datetime_str, point_ID, value))
                        #print("Value for point " + row[0] + ": " + str(req) + datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f"))

                    if (row[2] == "an_in"):
                        req = client.read_input_registers(int(row[1]), 1)

                        datetime_str = datetime.now().strftime(
                            "%Y-%m-%d %H:%M:%S.%f")
                        point_ID = row[3]
                        value = req[0] * row[4]
                        error_code = 0
                        print(datetime_str + " | " + str(point_ID) + " | " +
                              str(value))
                        cur.execute("INSERT INTO point_data VALUES (?, ?, ?)",
                                    (datetime_str, point_ID, value))
                        #print("Value for point " + row[0] + ": " + str(req) + datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f"))

                    if (row[2] == "an_out"):
                        req = client.read_holding_registers(int(row[1]), 1)

                        datetime_str = datetime.now().strftime(
                            "%Y-%m-%d %H:%M:%S.%f")
                        point_ID = row[3]
                        value = req[0] * row[4]
                        error_code = 0
                        print(datetime_str + " | " + str(point_ID) + " | " +
                              str(value))
                        cur.execute("INSERT INTO point_data VALUES (?, ?, ?)",
                                    (datetime_str, point_ID, value))
                        #print("Value for point " + row[0] + ": " + str(req) + datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f"))

                print("\n")
                conn.commit()
                cur.close()
                client.close()

        except Error as e:
            print(e)
            conn.close()
            database = "./database/SCADADB.db"
            conn = create_connection(database)
Example #11
0
class ET7000:
    ranges = {
        0x00: {
            'min': -0.015,
            'max': 0.015,
            'min_code': 0x8000,
            'max_code': 0x7fff,
            'units': 'V'
        },
        0x01: {
            'min': -0.05,
            'max': 0.05,
            'min_code': 0x8000,
            'max_code': 0x7fff,
            'units': 'V'
        },
        0x02: {
            'min': -0.1,
            'max': 0.1,
            'min_code': 0x8000,
            'max_code': 0x7fff,
            'units': 'V'
        },
        0x03: {
            'min': -0.5,
            'max': 0.5,
            'min_code': 0x8000,
            'max_code': 0x7fff,
            'units': 'V'
        },
        0x04: {
            'min': -1.,
            'max': 1.,
            'min_code': 0x8000,
            'max_code': 0x7fff,
            'units': 'V'
        },
        0x05: {
            'min': -2.5,
            'max': 2.5,
            'min_code': 0x8000,
            'max_code': 0x7fff,
            'units': 'V'
        },
        0x06: {
            'min': -20.0e-3,
            'max': 20.0e-3,
            'min_code': 0x8000,
            'max_code': 0x7fff,
            'units': 'A'
        },
        0x07: {
            'units': 'A',
            'min': 4.0e-3,
            'min_code': 0x0000,
            'max_code': 0xffff,
            'max': 20.0e-3
        },
        0x08: {
            'units': 'V',
            'min': -10.,
            'max': 10.,
            'min_code': 0x8000,
            'max_code': 0x7fff,
        },
        0x09: {
            'units': 'V',
            'min_code': 0x8000,
            'max_code': 0x7fff,
            'min': -5.,
            'max': 5.
        },
        0x0A: {
            'units': 'V',
            'min_code': 0x8000,
            'max_code': 0x7fff,
            'min': -1.,
            'max': 1.
        },
        0x0B: {
            'units': 'V',
            'min_code': 0x8000,
            'max_code': 0x7fff,
            'min': -.5,
            'max': .5
        },
        0x0C: {
            'units': 'V',
            'min_code': 0x8000,
            'max_code': 0x7fff,
            'min': -.15,
            'max': .15
        },
        0x0D: {
            'min': -20.0e-3,
            'max': 20.0e-3,
            'min_code': 0x8000,
            'max_code': 0x7fff,
            'units': 'A'
        },
        0x0E: {
            'units': 'degC',
            'min_code': 0xdca2,
            'max_code': 0x7fff,
            'min': -210.0,
            'max': 760.0
        },
        0x0F: {
            'units': 'degC',
            'min_code': 0xe6d0,
            'max_code': 0x7fff,
            'min': -270.0,
            'max': 1372.0
        },
        0x10: {
            'units': 'degC',
            'min_code': 0xa99a,
            'max_code': 0x7fff,
            'min': -270.0,
            'max': 400.0
        },
        0x11: {
            'units': 'degC',
            'min_code': 0xdd71,
            'max_code': 0x7fff,
            'min': -270.0,
            'max': 1000.0
        },
        0x12: {
            'units': 'degC',
            'min_code': 0x0000,
            'max_code': 0x7fff,
            'min': 0.0,
            'max': 1768.0
        },
        0x13: {
            'units': 'degC',
            'min_code': 0x0000,
            'max_code': 0x7fff,
            'min': 0.0,
            'max': 1768.0
        },
        0x14: {
            'units': 'degC',
            'min_code': 0x0000,
            'max_code': 0x7fff,
            'min': 0.0,
            'max': 1820.0
        },
        0x15: {
            'units': 'degC',
            'min_code': 0xe56b,
            'max_code': 0x7fff,
            'min': -270.0,
            'max': 1300.0
        },
        0x16: {
            'units': 'degC',
            'min_code': 0x0000,
            'max_code': 0x7fff,
            'min': 0.0,
            'max': 2320.0
        },
        0x17: {
            'units': 'degC',
            'min_code': 0xe000,
            'max_code': 0x7fff,
            'min': -200.0,
            'max': 800.0
        },
        0x18: {
            'units': 'degC',
            'min_code': 0x8000,
            'max_code': 0x4000,
            'min': -200.0,
            'max': 100.0
        },
        0x19: {
            'units': 'degC',
            'min_code': 0xe38e,
            'max_code': 0xffff,
            'min': -200.0,
            'max': 900.0
        },
        0x1A: {
            'min': 0.0,
            'max': 20.0e-3,
            'min_code': 0x0000,
            'max_code': 0xffff,
            'units': 'A'
        },
        0x20: {
            'units': 'degC',
            'min_code': 0x8000,
            'max_code': 0x7fff,
            'min': -100.0,
            'max': 100.0
        },
        0x21: {
            'units': 'degC',
            'min_code': 0x0000,
            'max_code': 0x7fff,
            'min': 0.0,
            'max': 100.0
        },
        0x22: {
            'units': 'degC',
            'min_code': 0x0000,
            'max_code': 0x7fff,
            'min': 0.0,
            'max': 200.0
        },
        0x23: {
            'units': 'degC',
            'min_code': 0x0000,
            'max_code': 0x7fff,
            'min': 0.0,
            'max': 600.0
        },
        0x24: {
            'units': 'degC',
            'min_code': 0x8000,
            'max_code': 0x7fff,
            'min': -100.0,
            'max': 100.0
        },
        0x25: {
            'units': 'degC',
            'min_code': 0x0000,
            'max_code': 0x7fff,
            'min': 0.0,
            'max': 100.0
        },
        0x26: {
            'units': 'degC',
            'min_code': 0x0000,
            'max_code': 0x7fff,
            'min': 0.0,
            'max': 200.0
        },
        0x27: {
            'units': 'degC',
            'min_code': 0x0000,
            'max_code': 0x7fff,
            'min': 0.0,
            'max': 600.0
        },
        0x28: {
            'units': 'degC',
            'min_code': 0x999a,
            'max_code': 0x7fff,
            'min': -80.0,
            'max': 100.0
        },
        0x29: {
            'units': 'degC',
            'min_code': 0x0000,
            'max_code': 0x7fff,
            'min': 0.0,
            'max': 100.0
        },
        0x2A: {
            'units': 'degC',
            'min_code': 0xd556,
            'max_code': 0x7fff,
            'min': -200.0,
            'max': 600.0
        },
        0x2B: {
            'units': 'degC',
            'min_code': 0xeeef,
            'max_code': 0x7fff,
            'min': -20.0,
            'max': 150.0
        },
        0x2C: {
            'units': 'degC',
            'min_code': 0x0000,
            'max_code': 0x7fff,
            'min': 0.0,
            'max': 200.0
        },
        0x2D: {
            'units': 'degC',
            'min_code': 0xeeef,
            'max_code': 0x7fff,
            'min': -20.0,
            'max': 150.0
        },
        0x2E: {
            'units': 'degC',
            'min_code': 0x8000,
            'max_code': 0x7fff,
            'min': -200.0,
            'max': 200.0
        },
        0x2F: {
            'units': 'degC',
            'min_code': 0x8000,
            'max_code': 0x7fff,
            'min': -200.0,
            'max': 200.0
        },
        0x80: {
            'units': 'degC',
            'min_code': 0xd556,
            'max_code': 0x7fff,
            'min': -200.0,
            'max': 600.0
        },
        0x81: {
            'units': 'degC',
            'min_code': 0xd556,
            'max_code': 0x7fff,
            'min': -200.0,
            'max': 600.0
        },
        0x82: {
            'units': 'degC',
            'min_code': 0xd556,
            'max_code': 0x7fff,
            'min': -50.0,
            'max': 150.0
        },
        0x83: {
            'min_code': 0xd556,
            'max_code': 0x7fff,
            'units': 'degC',
            'min': -60.0,
            'max': 180.0
        },
        0x30: {
            'min_code': 0x0000,
            'max_code': 0xffff,
            'min': 0.0,
            'max': 20.0e-3,
            'units': 'A'
        },
        0x31: {
            'min_code': 0x0000,
            'max_code': 0xffff,
            'min': 4.0e-3,
            'max': 20.0e-3,
            'units': 'A'
        },
        0x32: {
            'min_code': 0x0000,
            'max_code': 0x7fff,
            'min': 0.0,
            'max': 10.0,
            'units': 'V'
        },
        0x33: {
            'min': -10.0,
            'max': 10.0,
            'min_code': 0x8000,
            'max_code': 0x7fff,
            'units': 'V'
        },
        0x34: {
            'min': 0.0,
            'max': 5.0,
            'min_code': 0x0000,
            'max_code': 0x7fff,
            'units': 'V'
        },
        0x35: {
            'min': -5.0,
            'max': 5.0,
            'min_code': 0x8000,
            'max_code': 0x7fff,
            'units': 'V'
        },
        0xff: {
            'min': 0,
            'max': 0xffff,
            'min_code': 0x0000,
            'max_code': 0xffff,
            'units': '?'
        }
    }
    devices = {0x7015: {}, 0x7016: {}, 0x7018: {}, 0x7060: {}, 0x7026: {}}

    @staticmethod
    def range(r):
        if r in ET7000.ranges:
            return (ET7000.ranges[r])
        return ET7000.ranges[0xff]

    # default conversion from quanta to real units
    @staticmethod
    def convert(b, amin, amax):
        b = float(b)
        # обрабатывается 2 случая - минимум нулевой или больше 0
        if amin >= 0 and amax > 0:
            return amin + (amax - amin) * b / 0xffff
        # и минимум  и максимум разного знака
        if amin < 0 and amax > 0:
            range = max(-amin, amax)
            if b <= 0x7fff:
                return range * b / 0x7fff
            else:
                return range * (0x8000 - b) / 0x8000
        # в других случаях ошибка
        return float('nan')

    @staticmethod
    def ai_convert_function(r):
        v_min = 0
        v_max = 0xffff
        c_min = 0
        c_max = 0xffff
        try:
            v_min = ET7000.ranges[r]['min']
            v_max = ET7000.ranges[r]['max']
            c_min = ET7000.ranges[r]['min_code']
            c_max = ET7000.ranges[r]['max_code']
        except:
            pass
        if c_min < c_max:
            k = (v_max - v_min) / (c_max - c_min)
            b = v_min - k * c_min
            return lambda x: k * x + b
        k_max = v_max / c_max
        k_min = v_min / (0x10000 - c_min)
        #return lambda x: (x < 0x8000) * k_max * x + (x >= 0x8000) *  k_min * (0x10000 - x)
        return lambda x: k_max * x if x < 0x8000 else k_min * (0x10000 - x)

    @staticmethod
    def ao_convert_function(r):
        v_min = 0
        v_max = 0xffff
        c_min = 0
        c_max = 0xffff
        try:
            v_min = ET7000.ranges[r]['min']
            v_max = ET7000.ranges[r]['max']
            c_min = ET7000.ranges[r]['min_code']
            c_max = ET7000.ranges[r]['max_code']
        except:
            pass
        #print(hex(r), v_min, v_max, c_min, c_max)
        if c_min < c_max:
            k = (c_max - c_min) / (v_max - v_min)
            b = c_min - k * v_min
            return lambda x: int(k * x + b)
        k_max = c_max / v_max
        k_min = (0xffff - c_min) / v_min
        #return lambda x: int((x >= 0) * k_max * x + (x < 0) * (0xffff - k_min * x))
        return lambda x: int(k_max * x) if (x >= 0) else int(0xffff - k_min * x
                                                             )

    @staticmethod
    def convert_to_raw(v, amin, amax):
        v = float(v)
        # обрабатывается 2 случая - минимум нулевой или больше 0
        if amin >= 0 and amax > 0:
            return int((v - amin) / (amax - amin) * 0xffff)
        # и минимум  и максимум разного знака
        if amin < 0 and amax > 0:
            if v >= 0.0:
                return int(v * 0x7fff / amax)
            else:
                return int(0x8000 - v / amax * 0x7fff)
        # в других случаях ошибка
        return 0

    def __init__(self, host, port=502, timeout=0.15, logger=None):
        self.host = host
        self.port = port
        # logger confid
        if logger is None:
            logger = logging.getLogger(__name__)
        self.logger = logger
        # default device type
        self._name = 0
        self.type = '0000'
        # default ai
        self.AI_n = 0
        self.AI_masks = []
        self.AI_ranges = []
        self.AI_min = []
        self.AI_max = []
        self.AI_units = []
        self.AI_raw = []
        self.AI_values = []
        # default ao
        self.AO_n = 0
        self.AO_masks = []
        self.AO_ranges = []
        self.AO_min = []
        self.AO_max = []
        self.AO_units = []
        self.AO_raw = []
        self.AO_values = []
        self.AO_write_raw = []
        self.AO_write_values = []
        self.AO_write_result = False
        # default di
        self.DI_n = 0
        self.DI_values = []
        # default do
        self.DO_n = 0
        self.DO_values = []
        # modbus client
        self._client = ModbusClient(host,
                                    port,
                                    auto_open=True,
                                    auto_close=True,
                                    timeout=timeout)
        status = self._client.open()
        if not status:
            self.logger.error('ET7000 device at %s is offline' % host)
            return
        # read module name
        self._name = self.read_module_name()
        self.type = hex(self._name).replace('0x', '')
        if self._name not in ET7000.devices:
            self.logger.warning(
                'ET7000 device type %s probably not supported' %
                hex(self._name))
        # ai
        self.AI_n = self.read_AI_n()
        self.AI_masks = [False] * self.AI_n
        self.AI_ranges = [0xff] * self.AI_n
        self.AI_raw = [0] * self.AI_n
        self.AI_values = [float('nan')] * self.AI_n
        self.AI_units = [''] * self.AI_n
        self.read_AI_masks()
        self.read_AI_ranges()
        self.AI_convert = [lambda x: x] * self.AI_n
        for n in range(self.AI_n):
            r = self.AI_ranges[n]
            self.AI_units[n] = ET7000.ranges[r]['units']
            self.AI_convert[n] = ET7000.ai_convert_function(r)
        # ao
        self.AO_n = self.read_AO_n()
        self.AO_masks = [True] * self.AO_n
        self.read_AO_masks()
        self.AO_ranges = [0xff] * self.AO_n
        self.AO_raw = [0] * self.AO_n
        self.AO_values = [float('nan')] * self.AO_n
        self.AO_write_values = [float('nan')] * self.AO_n
        self.AO_units = [''] * self.AO_n
        self.AO_write = [0] * self.AO_n
        self.AO_write_raw = [0] * self.AO_n
        self.read_AO_ranges()
        self.AO_convert = [lambda x: x] * self.AI_n
        self.AO_convert_write = [lambda x: 0] * self.AI_n
        for n in range(self.AO_n):
            r = self.AO_ranges[n]
            self.AO_units[n] = ET7000.ranges[r]['units']
            self.AO_convert[n] = ET7000.ai_convert_function(
                r)  # !!! ai_convert for reading
            self.AO_convert_write[n] = ET7000.ao_convert_function(
                r)  # !!! ao_convert for writing
        # di
        self.DI_n = self.read_DI_n()
        self.DI_values = [False] * self.DI_n
        # do
        self.DO_n = self.read_DO_n()
        self.DO_values = [False] * self.DO_n
        self.DO_write = [False] * self.DO_n

    def read_module_name(self):
        regs = self._client.read_holding_registers(559, 1)
        if regs and regs[0] != 0:
            return regs[0]
        regs = self._client.read_holding_registers(260, 1)
        if regs:
            return regs[0]
        return 0

    # AI functions
    def read_AI_n(self):
        regs = self._client.read_input_registers(320, 1)
        if regs and regs[0] != 0:
            return regs[0]
        regs = self._client.read_input_registers(120, 1)
        if regs:
            return regs[0]
        return 0

    def read_AI_masks(self):
        coils = self._client.read_coils(595, self.AI_n)
        if coils and len(coils) == self.AI_n:
            self.AI_masks = coils
        return coils

    def read_AI_ranges(self):
        regs = self._client.read_holding_registers(427, self.AI_n)
        if regs and len(regs) == self.AI_n:
            self.AI_ranges = regs
        return regs

    def read_AI_raw(self, channel=None):
        if channel is None:
            n = self.AI_n
            channel = 0
        else:
            n = 1
        regs = self._client.read_input_registers(0 + channel, n)
        if regs and len(regs) == n:
            self.AI_raw[channel:channel + n] = regs
        if n == 1:
            return regs[0]
        return regs

    def convert_AI(self):
        for k in range(self.AI_n):
            if self.AI_masks[k]:
                self.AI_values[k] = self.AI_convert[k](self.AI_raw[k])
            else:
                self.AI_values[k] = float('nan')
        return self.AI_values

    def read_AI(self, channel=None):
        if channel is None:
            self.read_AI_raw()
            self.convert_AI()
            return self.AI_values
        return self.read_AI_channel(channel)

    def read_AI_channel(self, k: int):
        v = float('nan')
        if self.AI_masks[k]:
            regs = self._client.read_input_registers(0 + k, 1)
            if regs:
                self.AI_raw[k] = regs[0]
                v = self.AI_convert[k](regs[0])
        self.AI_values[k] = v
        return v

    # AO functions
    def read_AO_n(self):
        regs = self._client.read_input_registers(330, 1)
        if regs and regs[0] != 0:
            return regs[0]
        regs = self._client.read_input_registers(130, 1)
        if regs:
            return regs[0]
        return 0

    def read_AO_masks(self):
        return self.AO_masks

    def read_AO_ranges(self):
        regs = self._client.read_holding_registers(459, self.AO_n)
        if regs and len(regs) == self.AO_n:
            self.AO_ranges = regs
        return regs

    def read_AO_raw(self, channel=None):
        if channel is None:
            n = self.AO_n
            channel = 0
        else:
            n = 1
        regs = self._client.read_holding_registers(0 + channel, n)
        if regs and len(regs) == n:
            self.AO_raw[channel:channel + n] = regs
        if n == 1:
            return regs[0]
        return regs

    def write_AO_raw(self, regs):
        result = self._client.write_multiple_registers(0, regs)
        self.AO_write_result = result
        if len(regs) == self.AO_n:
            self.AO_write_raw = regs
        return result

    def convert_AO(self):
        raw = self.AO_raw
        for k in range(self.AO_n):
            self.AO_values[k] = self.AO_convert[k](raw[k])
        return self.AO_values

    def convert_to_raw_AO(self, values=None):
        if values is None:
            values = self.AO_write_values
        answer = []
        for k in range(len(values)):
            answer.append(self.AO_convert_write[k](values[k]))
        return answer

    def read_AO(self):
        self.AO_raw = self.read_AO_raw()
        self.convert_AO()
        return self.AO_values

    def read_AO_channel(self, k: int):
        v = float('nan')
        if self.AO_masks[k]:
            regs = self._client.read_holding_registers(0 + k, 1)
            if regs:
                v = self.AO_convert[k](regs[0])
                self.AO_values[k] = v
        return v

    def write_AO(self, values):
        self.AO_write_values = values
        regs = ET7000.convert_to_raw_AO(values)
        result = self.write_AO_raw(regs)
        return result

    def write_AO_channel(self, k: int, value):
        raw = self.AO_convert_write[k](value)
        result = self._client.write_single_register(0 + k, raw)
        self.AO_write_result = result
        if result:
            self.AO_write_values[k] = value
            self.AO_write_raw[k] = raw
            pass
        return result

    # DI functions
    def read_DI_n(self):
        regs = self._client.read_input_registers(300, 1)
        if regs and regs[0] != 0:
            return regs[0]
        regs = self._client.read_input_registers(100, 1)
        if regs:
            return regs[0]
        return 0

    def read_DI(self):
        regs = self._client.read_discrete_inputs(0, self.DI_n)
        if regs:
            self.DI_values = regs
        return self.DI_values

    def read_DI_channel(self, k: int):
        reg = self._client.read_discrete_inputs(0 + k, 1)
        if reg:
            self.DI_values[k] = reg[0]
            return reg[0]
        return None

    # DO functions
    def read_DO_n(self):
        self.DO_time = time.time()
        regs = self._client.read_input_registers(310, 1)
        if regs and regs[0] != 0:
            return regs[0]
        regs = self._client.read_input_registers(110, 1)
        if regs:
            return regs[0]
        return 0

    def read_DO(self):
        regs = self._client.read_coils(0, self.DI_n)
        if regs:
            self.DI_values = regs
        return self.DI_values

    def read_DO_channel(self, k: int):
        reg = self._client.read_coils(0 + k, 1)
        if reg:
            self.DO_values[k] = reg[0]
            return reg[0]
        return None

    def write_DO(self, values):
        self.DO_write = values
        self.DO_write_result = self._client.write_multiple_coils(0, values)
        return self.DO_write_result

    def write_DO_channel(self, k: int, value: bool):
        result = self._client.write_single_coil(0 + k, value)
        self.DO_write_result = result
        if result:
            self.DO_write[k] = value
        return result
class TestClientServer(unittest.TestCase):
    port = 5020

    def setUp(self):
        # modbus server
        self.server = ModbusServer(port=TestClientServer.port, no_block=True)
        self.server.start()
        # modbus client
        self.client = ModbusClient(port=TestClientServer.port)
        self.client.open()
        # to prevent address taken errors
        TestClientServer.port += 1

    def tearDown(self):
        self.client.close()

    @repeat
    def test_word_init(self):
        # word space
        self.assertEqual(self.client.read_holding_registers(0), [0],
                         'Default value is 0 when server start')
        self.assertEqual(self.client.read_input_registers(0), [0],
                         'Default value is 0 when server start')

    @repeat
    def test_word_single(self):
        # single read/write
        self.assertEqual(self.client.write_single_register(0, 0xffff), True)
        self.assertEqual(self.client.read_input_registers(0), [0xffff])

    @repeat
    def test_word_multi(self):
        # multi-write at max size
        words_l = [randint(0, 0xffff)] * 0x7b
        self.assertEqual(self.client.write_multiple_registers(0, words_l),
                         True)
        self.assertEqual(self.client.read_holding_registers(0, len(words_l)),
                         words_l)
        self.assertEqual(self.client.read_input_registers(0, len(words_l)),
                         words_l)

    @repeat
    def test_word_oversize(self):
        # write over sized
        words_l = [randint(0, 0xffff)] * 0x7c
        self.assertEqual(self.client.write_multiple_registers(0, words_l),
                         None)

    @repeat
    def test_bit_init(self):
        # bit space
        self.assertEqual(self.client.read_coils(0), [False],
                         'Default value is False when server start')
        self.assertEqual(self.client.read_discrete_inputs(0), [False],
                         'Default value is False when server start')

    @repeat
    def test_bit_single(self):
        # single read/write
        self.assertEqual(self.client.write_single_coil(0, True), True)
        self.assertEqual(self.client.read_coils(0), [True])
        self.assertEqual(self.client.read_discrete_inputs(0), [True])

    @repeat
    def test_bit_multi_min(self):
        # multi-write at min size
        bits_l = [getrandbits(1)] * 0x1
        self.assertEqual(self.client.write_multiple_coils(0, bits_l), True)
        self.assertEqual(self.client.read_coils(0, len(bits_l)), bits_l)
        self.assertEqual(self.client.read_discrete_inputs(0, len(bits_l)),
                         bits_l)

    @repeat
    def test_bit_multi_max(self):
        # multi-write at max size
        bits_l = [getrandbits(1)] * 0x7b0
        self.assertEqual(self.client.write_multiple_coils(0, bits_l), True)
        self.assertEqual(self.client.read_coils(0, len(bits_l)), bits_l)
        self.assertEqual(self.client.read_discrete_inputs(0, len(bits_l)),
                         bits_l)

    @repeat
    def test_bit_multi_oversize(self):
        # multi-write over sized
        bits_l = [getrandbits(1)] * 0x7b1
        self.assertEqual(self.client.write_multiple_coils(0, bits_l), None)
    while True:
        if not c.is_open():
            logger.error("not open")
            time.sleep(2)
            continue

        # 写 coils
        c.write_single_coil(1, coil_value)
        logger.debug(f"写 coil,值为 {coil_value}")
        coil_value = not coil_value

        time.sleep(1)

        # 读 discrete_inputs
        inputs = c.read_discrete_inputs(1)
        if inputs is None:
            logger.error("读 discrete_inputs 失败")
            time.sleep(2)
            continue
        logger.debug(f"读 discrete_input,值为 {inputs[0]}")

        # 写 holding_registers
        c.write_single_register(1, holding_reg_value)
        logger.debug(f"写 holding_register,值为 {holding_reg_value}")
        holding_reg_value = (holding_reg_value + 1) % range_value

        time.sleep(1)

        # 读 input_register
        regs = c.read_input_registers(1)
Example #14
0
class LightController():
    """Class to control lights of a single controller"""

    toggle_time = config.toggle_time

    def __init__(self, host):
        self.client = ModbusClient(host=host, auto_open=True, auto_close=False)
        #self.client.debug(True)
        logger.info("Connecting to %s", self.client.host())

        status = self.check_status()
        if status & 1<<15:
            # Watchdog ellapsed, try to reset
            logger.info("Resetting watchdog")
            self.client.write_single_register(0x1121, 0xbecf)
            self.client.write_single_register(0x1121, 0xaffe)

        # Disable the watchdog, if enabled
        watchdog_timeout = self.client.read_holding_registers(0x1120)[0]
        if watchdog_timeout > 0:
            logger.debug("Watchdog timeout: %d", watchdog_timeout)
            logger.info("Disabling watchdog")
            self.client.write_single_register(0x1120, 0)

        (self.num_outputs, self.num_inputs) = self.client.read_holding_registers(0x1012, 2)
        logger.info("Number of outputs: %d", self.num_outputs)
        logger.info("Number of inputs: %d", self.num_inputs)
        self.client.close()
        # We use auto close for all subsequent calls after initialization
        self.client.auto_close(True)

    def check_status(self):
        """Read buscoupler status from the module"""
        buscoupler_status = self.client.read_holding_registers(0x100c)[0]
        if buscoupler_status & 1<<0:
            logger.error("Bus terminal error")
        if buscoupler_status & 1<<1:
            logger.error("Bus coupler configuration error")
        if buscoupler_status & 1<<15:
            logger.error("Fieldbus error, watchdog timer elapsed")
        return buscoupler_status

    def inputs(self):
        """Read input status from module"""
        inputs = self.client.read_discrete_inputs(0, self.num_inputs)
        logger.debug("Inputs: %s", "".join(map(lambda c: '1' if c else '0', inputs)))
        return inputs

    def outputs(self):
        """Read output status from module"""
        coils = self.client.read_coils(0, self.num_outputs)
        logger.debug("Outputs: %s", "".join(map(lambda c: '1' if c else '0', coils)))
        return coils

    def toggle(self, bit_addr):
        """Toggle a impulse relay connected to a single output"""
        logger.info("Toggling %d on %s", bit_addr, self.client.host())
        self.client.auto_close(False)
        self.client.write_single_coil(bit_addr, True)
        logger.debug("On %d", bit_addr)
        time.sleep(self.toggle_time)
        self.client.write_single_coil(bit_addr, False)
        logger.debug("Off %d", bit_addr)
        self.client.close()
        self.client.auto_close(True)
Example #15
0
    #print(regs)
    #print(regs2)

    try:
        for j in range(0, 10):
            print(i * 10 + j, ",cois status,", regs2[j])
    except:
        print(i * 10, ",")

print("")
print("")

print("")
print("")
for i in range(0, 1000):
    regs2 = _modbusClient.read_discrete_inputs(i * 10, 10)
    #print(i*10,"")
    #print(regs)
    #print(regs2)

    try:
        for j in range(0, 10):
            print(i * 10 + j, ",input status,", regs2[j])
    except:
        print(i * 10, ",")

print("")
print("")

for i in range(0, 1000):
    regs = _modbusClient.read_holding_registers(i * 10, 10)
Example #16
0
class Beckhoff(Adapter):
    """Beckhoff Modbus/TCP bus coupler (e.g. BK9000)"""
    def __init__(self, ip_address):
        super(Beckhoff, self).__init__(ip_address)
        self.mb_client = ModbusClient(host=ip_address, timeout=5)

    def start(self):
        while True:
            self.mb_client.open()
            if self.mb_client.is_open():
                break

            print 'Unable to connect to Beckhoff rack at {}; retrying...'.format(
                self.ip_address)
            sleep(1)

    def stop(self):
        self.mb_client.close()

    def read_all(self):
        # print 'Read inputs'
        if self.d_ins:
            data = self.mb_client.read_discrete_inputs(
                self.d_in_range[0],
                self.d_in_range[1] - self.d_in_range[0] + 1)
            if not data:
                raise ConnectionError('No data received for DIns')

            i0 = self.d_in_range[
                0]  # Starting index for looking up values from the data list
            for d in self.d_ins.values():
                d.val = data[d.address - i0]

        if self.a_ins:
            # print '\tRead input registers', self.a_in_range[0], self.a_in_range[1] - self.a_in_range[0] + 1
            data = self.mb_client.read_input_registers(
                self.a_in_range[0],
                self.a_in_range[1] - self.a_in_range[0] + 1)
            if not data:
                raise ConnectionError('No data received from AIns')

            i0 = self.a_in_range[
                0]  # Starting index for looking up values from the data list
            for d in self.a_ins.values():
                d.status = data[d.address - i0]
                d.val = data[d.address - i0 + 1]

    def write_all(self):
        # print 'Write outputs'
        if self.d_outs:
            data = []
            for i in xrange(self.d_out_range[0], self.d_out_range[1] + 1):
                try:
                    data.append(self.d_outs[i].raw)
                except KeyError:
                    data.append(0)  # Default value

            self.mb_client.write_multiple_coils(self.d_out_range[0], data)

        if self.a_outs:
            data = []
            for d in self.a_outs.values():
                data.append(0)
                data.append(d.raw)  # Only write to low words

            self.mb_client.write_multiple_registers(self.a_out_range[0], data)
Example #17
0
if not c.is_open():
    if not c.open():
        print("unable to connect to " + client_host + ":" + str(client_port))


def int32_to_int8(n):
    mask = (1 << 16) - 1
    return [(n >> k) & mask for k in range(0, 32, 16)]


var_int = utils.encode_ieee(7.5)
print(var_int)
sonuc=int32_to_int8(var_int)
print(sonuc)
if c.is_open():
    # read 10 registers at address 0, store result in regs list
    print(var_int)
    c.write_single_register(0,5)
    c.write_multiple_registers(1,sonuc)

    regs = c.read_holding_registers(0,100)
    # if success display registers
    if regs:
        print("reg ad #0 to 9: " , regs)

    bits = c.read_discrete_inputs(0, 16)
    # if success display registers
    if bits:
        print("bit ad #0 to 9: " + str(bits))
Example #18
0
    if c.is_open():
        is_ok = c.write_multiple_coils(addr, coil_bits_write)
        if not is_ok:
            print('Dummy')
            print("bit #" + str(addr) + ": unable to write " + str(toggle))
            print('numCoilsTest = ' + str(numCoilsTest), end='\r')
            break

    #time.sleep(1)
    # if open() is ok, read coils (modbus function 0x01)
    addr = 72
    if c.is_open():
        # read 10 bits at address 0, store result in regs list
        coil_bits_read.clear()
        #coil_bits_read = c.read_coils(addr, numCoilsTest)
        coil_bits_read = c.read_discrete_inputs(addr, numCoilsTest)
        # if success display registers
        if not coil_bits_read:
            print('Dummy')
            print("bit ad #0 to : " + str(numCoilsTest) + str(coil_bits_read))
            break

    # compare written with read bits info
    #print(coil_bits_read)

    for i in range(0, numCoilsTest):
        if i == 23:
            continue
        if coil_bits_read[i] != coil_bits_write[i]:
            print('Error in comparision at Coil ' + str(i))
            print("Written = " + str(coil_bits_write[i]) + " :: Read :" +
class ConveyorNode(object):
    __reg_A_servo_on = 0
    __reg_A_command = 1
    __reg_A_velocity = 2
    __reg_B_servo_on = 3
    __reg_B_command = 4
    __reg_B_velocity = 5

    def __init__(self):
        rospy.init_node("conveyor_node")
        rospy.loginfo("Starting ConveyorNode as conveyor_node.")
        host = rospy.get_param("~host", default="10.42.0.21")
        port = rospy.get_param("~port", default=502)
        publish_rate = rospy.get_param("~rate", default=20)
        self.ratio_vel_A = rospy.get_param("~ratio_vel_A", default="1")
        self.ratio_vel_B = rospy.get_param("~ratio_vel_B", default="1")
        self.ratio_cmd_A = rospy.get_param("~ratio_cmd_A", default="1")
        self.ratio_cmd_B = rospy.get_param("~ratio_cmd_B", default="1")
        self.min_vel = rospy.get_param("~min_vel", default="-0.2")
        self.max_vel = rospy.get_param("~max_vel", default="0.2")

        self.rate = rospy.Rate(publish_rate)

        rospy.Subscriber("conveyorA/command", Float32,
                         self.set_velocityA)  # unit [m/s]
        self.stateA_pub = rospy.Publisher("conveyorA/state",
                                          conveyor,
                                          queue_size=1)  # state of conveyor
        rospy.Subscriber("conveyorB/command", Float32,
                         self.set_velocityB)  # unit [m/s]
        self.stateB_pub = rospy.Publisher("conveyorB/state",
                                          conveyor,
                                          queue_size=1)  # state of conveyor

        self.stateA_msg = conveyor()
        self.stateA_msg.target_vel = 0.0
        self.stateA_msg.current_vel = 0.0
        self.stateB_msg = conveyor()
        self.stateB_msg.target_vel = 0.0
        self.stateB_msg.current_vel = 0.0

        self.__timeout_timeA = time.time()
        self.__timeout_timeB = time.time()

        try:
            self.client = ModbusClient(host, port, auto_open=True)
            rospy.loginfo("Setup complete")
        except ValueError:
            rospy.logerr("Error with conveyor Host or Port params")

        self.__register_data = None
        self.__input_data = None

    @staticmethod
    def clamp(n, minn, maxn):
        return max(min(maxn, n), minn)

    @staticmethod
    def map_velocity_to_value(velocity):
        # value = (velocity/0.05*100*2*math.pi*60)/500
        velocity = (velocity * 60) / (0.052 * 2 * math.pi * 4)
        value = int(velocity / 10.0 * 27648.0)
        return utils.get_2comp(value) & 0xFFFF

    @staticmethod
    def map_value_to_velocity(value):
        voltage = float(utils.get_2comp(value)) / 27648.0 * 10.0
        velocity = voltage * 4.0 * 2.0 * math.pi * 0.052 / 60.0
        return velocity

    def set_velocityA(self, msg):

        self.stateA_msg.target_vel = self.clamp(msg.data, self.min_vel,
                                                self.max_vel)  # [m/s]
        self.__timeout_timeA = time.time()

    def set_velocityB(self, msg):
        self.stateB_msg.target_vel = self.clamp(msg.data, self.min_vel,
                                                self.max_vel)  # [m/s]
        self.__timeout_timeB = time.time()

    def run(self):
        while not rospy.is_shutdown():
            try:
                self.__input_data = self.client.read_discrete_inputs(0, 6)
                self.stateA_msg.sensor_1 = self.__input_data[0]
                self.stateA_msg.sensor_2 = self.__input_data[1]
                self.stateA_msg.sensor_3 = self.__input_data[2]

                self.stateB_msg.sensor_1 = self.__input_data[3]
                self.stateB_msg.sensor_2 = self.__input_data[4]
                self.stateB_msg.sensor_3 = self.__input_data[5]

                self.__register_data = self.client.read_holding_registers(0, 6)

                if time.time() - self.__timeout_timeA > 1.0:
                    self.stateA_msg.target_vel = 0
                    self.client.write_single_register(self.__reg_A_servo_on, 0)
                else:
                    value = self.map_velocity_to_value(
                        self.stateA_msg.target_vel) * self.ratio_cmd_A
                    self.client.write_single_register(self.__reg_A_servo_on, 1)
                    self.client.write_single_register(self.__reg_A_command,
                                                      value)

                if time.time() - self.__timeout_timeB > 1.0:
                    self.stateB_msg.target_vel = 0
                    self.client.write_single_register(self.__reg_B_servo_on, 0)
                else:
                    value = self.map_velocity_to_value(
                        self.stateB_msg.target_vel) * self.ratio_cmd_B
                    self.client.write_single_register(self.__reg_B_servo_on, 1)
                    self.client.write_single_register(self.__reg_B_command,
                                                      value)

                velocity = self.map_value_to_velocity(
                    self.__register_data[self.__reg_A_velocity])
                self.stateA_msg.current_vel = velocity * self.ratio_vel_A
                velocity = self.map_value_to_velocity(
                    self.__register_data[self.__reg_B_velocity])
                self.stateB_msg.current_vel = velocity * self.ratio_vel_B
                self.stateA_pub.publish(self.stateA_msg)
                self.stateB_pub.publish(self.stateB_msg)

            except Exception as e:
                rospy.logerr(e)

            self.rate.sleep()
Example #20
0
    def onHeartbeat(self):
        Domoticz.Debug("onHeartbeat called")

        try:
            client = ModbusClient(host=self.TCP_IP,
                                  port=int(self.TCP_PORT),
                                  unit_id=int(1),
                                  auto_open=True,
                                  auto_close=True,
                                  timeout=2)
        except:
            Domoticz.Error("Can not connect to Modbus TCP/IP: " + self.TCP_IP +
                           ":" + self.TCP_PORT)

        try:
            c207 = BinaryPayloadDecoder.fromRegisters(
                client.read_coils(207, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            c211 = BinaryPayloadDecoder.fromRegisters(
                client.read_coils(211, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            c902 = BinaryPayloadDecoder.fromRegisters(
                client.read_coils(902, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            c1200 = BinaryPayloadDecoder.fromRegisters(
                client.read_coils(1200, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            #Domoticz.Debug("Modbus response: v='" + str(i201) + "'")
        except:
            Domoticz.Error(
                "Modbus TCP/IP communication error (input registers). Check it out!"
            )

        try:
            i200 = BinaryPayloadDecoder.fromRegisters(
                client.read_input_registers(200, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            i201 = BinaryPayloadDecoder.fromRegisters(
                client.read_input_registers(201, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            i203 = BinaryPayloadDecoder.fromRegisters(
                client.read_input_registers(203, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            i204 = BinaryPayloadDecoder.fromRegisters(
                client.read_input_registers(204, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            i205 = BinaryPayloadDecoder.fromRegisters(
                client.read_input_registers(205, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            i206 = BinaryPayloadDecoder.fromRegisters(
                client.read_input_registers(206, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            #Domoticz.Debug("Modbus response: v='" + str(i201) + "'")
        except:
            Domoticz.Error(
                "Modbus TCP/IP communication error (input registers). Check it out!"
            )

        try:
            d200 = BinaryPayloadDecoder.fromRegisters(
                client.read_discrete_inputs(200, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            d201 = BinaryPayloadDecoder.fromRegisters(
                client.read_discrete_inputs(201, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            d202 = BinaryPayloadDecoder.fromRegisters(
                client.read_discrete_inputs(202, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            d203 = BinaryPayloadDecoder.fromRegisters(
                client.read_discrete_inputs(203, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            #Domoticz.Debug("Modbus response: v='" + str(i201) + "'")
        except:
            Domoticz.Error(
                "Modbus TCP/IP communication error (discrete inputs). Check it out!"
            )

        try:
            v1000 = BinaryPayloadDecoder.fromRegisters(
                client.read_holding_registers(1000, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            v1001 = BinaryPayloadDecoder.fromRegisters(
                client.read_holding_registers(1001, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            #v1008 = BinaryPayloadDecoder.fromRegisters(client.read_holding_registers(1008, 1), byteorder=Endian.Big, wordorder=Endian.Big).decode_16bit_int()
            #v1009 = BinaryPayloadDecoder.fromRegisters(client.read_holding_registers(1009, 1), byteorder=Endian.Big, wordorder=Endian.Big).decode_16bit_int()
            #v1012 = BinaryPayloadDecoder.fromRegisters(client.read_holding_registers(1012, 1), byteorder=Endian.Big, wordorder=Endian.Big).decode_16bit_int()
            #v1013 = BinaryPayloadDecoder.fromRegisters(client.read_holding_registers(1013, 1), byteorder=Endian.Big, wordorder=Endian.Big).decode_16bit_int()
            v1015 = BinaryPayloadDecoder.fromRegisters(
                client.read_holding_registers(1015, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            v1016 = BinaryPayloadDecoder.fromRegisters(
                client.read_holding_registers(1016, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            #Domoticz.Debug("Modbus response: v='" + str(v1015) + "'")
        except:
            Domoticz.Error(
                "Modbus TCP/IP communication error (holding registers). Check it out!"
            )

        # == Temperatures
        Devices[self.uTU1].Update(0, str(i200 / 10))
        Devices[self.uTU2].Update(0, str(i201 / 10))
        Devices[self.uTEa].Update(0, str(i203 / 10))
        Devices[self.uTEb].Update(0, str(i204 / 10))

        # == IN1 & IN2
        # I00205 Stav vstupu IN1 (0-10V): Analogový vstup: U= DATA/1000, Kontaktní vstup: rozepnuto ~ 3350 až 3450, sepnuto ~ do 20
        # I00206 Stav vstupu IN2 (0-10V): Analogový vstup: U= DATA/1000, Kontaktní vstup: rozepnuto ~ 3350 až 3450, sepnuto ~ do 20
        # kontakt: Statuses: Open: nValue = 1, Closed: nValue = 0
        if self.uIN1 in Devices:
            if self.atreaIN1type == "Contact":
                Devices[self.uIN1].Update(int(not (i205 <= 50)), "")
            elif Devices[self.uIN1].Type == 81:
                # Humidity_status can be one of:
                # 0=Normal      45~50, 55~60
                # 1=Comfortable 50~55
                # 2=Dry         <45
                # 3=Wet         >60
                if i205 < 4500: humstat = 2
                elif i205 > 6000: humstat = 3
                elif i205 >= 5000 and i205 <= 5500: humstat = 1
                else: humstat = 0
                Devices[self.uIN1].Update(int(i205 / 100), str(humstat))
            else:
                Devices[self.uIN1].Update(int(i205 / 100), str(i205 / 100))
        if self.uIN2 in Devices:
            if self.atreaIN2type == "Contact":
                Devices[self.uIN2].Update(int(not (i206 <= 50)), "")
            elif Devices[self.uIN2].Type == 81:
                if i206 < 4500: humstat = 2
                elif i206 > 6000: humstat = 3
                elif i206 >= 5000 and i206 <= 5500: humstat = 1
                else: humstat = 0
                Devices[self.uIN2].Update(int(i206 / 100), str(humstat))
            else:
                Devices[self.uIN2].Update(int(i206 / 100), str(i206 / 100))

        # == D1 & D2 & D3 & D4
        # D00200 Stav vstupu D1 : 0/1 : Vypnuto/Zapnuto
        # D00201 Stav vstupu D2 : 0/1 : Vypnuto/Zapnuto
        # D00202 Stav vstupu D3 : 0/1 : Vypnuto/Zapnuto
        # D00203 Stav vstupu D4 : 0/1 : Vypnuto/Zapnuto
        if self.uD1 in Devices: Devices[self.uD1].Update(int(d200 == 1), "")
        if self.uD2 in Devices: Devices[self.uD2].Update(int(d201 == 1), "")
        if self.uD3 in Devices: Devices[self.uD3].Update(int(d202 == 1), "")
        if self.uD4 in Devices: Devices[self.uD4].Update(int(d203 == 1), "")

        # == ZVT
        # C00207 0 = ZVT
        if self.uZVT in Devices: Devices[self.uZVT].Update(int(c207 == 0), "")

        # == Bypass
        # C00211 1 = Bypass flap
        if self.uBypass in Devices:
            Devices[self.uBypass].Update(int(c211 == 1), "")

        # == Heating season
        # C01200 1 = heating, 0 = non-heating
        if self.uHeatingSeason in Devices:
            Devices[self.uHeatingSeason].Update(int(c1200 == 1), "")

        # == Nightly Cooling
        # C00902 0 = recuperation, 1 = cooling
        if self.uNightlyCooling in Devices:
            Devices[self.uNightlyCooling].Update(int(c902 == 1), "")

        # == ControlMode
        if v1015 == 2 or v1016 == 2:
            Devices[self.uControlMode].Update(1, str(30))
        elif v1015 == 1 or v1016 == 1:
            Devices[self.uControlMode].Update(0, str(10))
        else:
            Devices[self.uControlMode].Update(0, str(20))

        # == PowerReq
        # H01009 Nastavení požadovaného výkonu, pokud H01016=1,   0 = Vyp, 12=12%,..., 100 = 100%
        # H01013 Nastavení požadovaného výkonu, pokud H01016=0/2, 0 = Vyp, 12=12%,..., 100 = 100%
        #if (v1016 == 1):   Devices[self.uPowerReq].Update(int(int(v1009) >= 10), str(self._powerPercentToDomoticzValue(v1009)))
        #elif (v1016 == 2): Devices[self.uPowerReq].Update(int(int(v1013) >= 10), str(self._powerPercentToDomoticzValue(v1013)))
        #elif (v1016 == 0): Devices[self.uPowerReq].Update(int(int(v1001) >= 10), str(self._powerPercentToDomoticzValue(v1001)))

        # == PowerCur
        # "0|60|90|120|150|180|240|300"
        Devices[self.uPowerCur].Update(
            int(int(v1001) >= 10),
            str(self._powerPercentToDomoticzValue(v1001)))

        # == ModeReq                                                  "Vypnuto |    Periodické větrání |    Větrání"
        # H01008 Nastavení požadovaného režimu, pokud H01015=1,                 0 = Periodické větrání, 1 = Větrání
        # H01012 Nastavení požadovaného režimu, pokud H01015= 0/2, 0 = Vypnuto, 1 = Periodické větrání, 2 = Větrání
        #if (v1015 == 1):
        #    if v1008 == 0:   Devices[self.uModeReq].Update(1, str(10))
        #    elif v1008 == 1: Devices[self.uModeReq].Update(1, str(20))
        #elif (v1015 == 2):
        #    if v1012 == 0:   Devices[self.uModeReq].Update(1, str(10))
        #    elif v1012 == 1: Devices[self.uModeReq].Update(1, str(20))
        #elif (v1015 == 0):
        #    if v1000 == 0:   Devices[self.uModeReq].Update(1, str(10))
        #    elif v1000 == 1: Devices[self.uModeReq].Update(1, str(20))

        # == ModeCur
        # "|Periodické větrání|Větrání|Čidlo vlhkosti|IN2|D1|D2|Koupelny+WC|Odsavač kuchyň|Náběh|Doběh|Odmrazování rekuperátoru"
        if (v1000 == 0):
            Devices[self.uModeCur].Update(int(int(v1001) >= 10), str(10))
        elif (v1000 == 1):
            Devices[self.uModeCur].Update(int(int(v1001) >= 10), str(20))
        elif (v1000 == 10):
            Devices[self.uModeCur].Update(1, str(30))
        elif (v1000 == 11):
            Devices[self.uModeCur].Update(1, str(40))
        elif (v1000 == 12):
            Devices[self.uModeCur].Update(1, str(50))
        elif (v1000 == 13):
            Devices[self.uModeCur].Update(1, str(60))
        elif (v1000 == 14):
            Devices[self.uModeCur].Update(1, str(70))
        elif (v1000 == 15):
            Devices[self.uModeCur].Update(1, str(80))
        elif (v1000 == 20):
            Devices[self.uModeCur].Update(1, str(90))
        elif (v1000 == 21):
            Devices[self.uModeCur].Update(1, str(100))
        elif (v1000 == 22):
            Devices[self.uModeCur].Update(1, str(110))

        # == Filter alarm from XML via HTTP
        try:
            bChangedFilter = True
            timeOfChange = 0
            xml = xmltodict.parse(
                requests.get("http://" + str(self.TCP_IP) +
                             "/config/alarms.xml").content)
            for i in xml['root']['errors']['i']:
                if int(i['@i']) == 100:
                    bChangedFilter = int(i['@p']) == 1
                    timeOfChange = i['@t']
            dtOfChange = datetime.fromtimestamp(int(timeOfChange))

            if bChangedFilter:
                Devices[self.uAlarmFilter].Update(
                    1,
                    self._("Filter last changed") + ": " + str(dtOfChange))
            else:
                Devices[self.uAlarmFilter].Update(
                    4,
                    self._("Filter to change since") + ": " + str(dtOfChange))
        except:
            Domoticz.Error(
                "Failed to get or process XML via HTML to get state of filter alarm."
            )

        return
Example #21
0
mqttc.on_subscribe = on_subscribe
# Uncomment to enable debug messages
#mqttc.on_log = on_log



is_mqttConnect = connect_to_MQTT()

mqttc.loop_start()


mqttc.subscribe("modbus/holding")

while True:
	#Read the first 8 inputs via Modbus
	regs = c.read_discrete_inputs(0, 8)
	toBroker = "{"
	print(is_mqttConnect)
	if (is_mqttConnect == 0) :
		if regs:
			#print(f"Send to Broker ",  json.dumps(convert(regs)))
			for idx, reg in enumerate(regs):
				
				if reg == False:
					toBroker += "0"
				else:
					toBroker += "1"
					
				if idx < 7:
					toBroker += ","
			
c = ModbusClient()
if not c.host(host_client):
    print("host error")
if not c.port(502):
    print("port error")

# Автоматическое соединение TCP по запросу Modbus, закрытие после него\TCP auto connect on modbus request, close after it
c = ModbusClient(host=host_client, auto_open=True, auto_close=True)

while True:
    if c.is_open():
        #    считываем регистры установки\read setup registers
        in_regs_read = c.read_input_registers(0, 51)
        hl_regs_read = c.read_holding_registers(0, 3)
        coil_regs_read = c.read_coils(0, 25)
        dis_in_regs = c.read_discrete_inputs(0, 72)
        #       присвоить переменным значение\assign variables a value
        CL_POWER, CL_TIMER, CL_WEEK, CL_Boost_MODE, CL_FPLC_MODE, CL_IntRH_CTRL, CL_ExtRH_CTRL, CL_IntCO2_CTRL, CL_ExtCO2_CTRL, CL_IntPM2_5_CTRL, CL_ExtPM2_5_CTRL, CL_IntVOC_CTRL, CL_ExtVOC_CTRL, CL_BoostSWITCH_CTRL, CL_FplcSWITCH_CTRL, CL_FireALARM_CTRL, CL_10V_SENSOR_CTRL, CL_RESET_FILTER_TIMER, CL_RESET_ALARM, CL_RESTORE_FACTORY, CL_CLOUD_CTRL, CL_MinSuAirOutTEMP_CTRL, CL_WaterPRESS_CTRL, CL_WaterFLOW_CTRL, CL_WaterHeaterAutoRestart = coil_regs_read
        IR_CurSelTEMP, IR_CurTEMP_SuAirIn, IR_CurTEMP_SuAirOut, IR_CurTEMP_ExAirIn, IR_CurTEMP_ExAirOut, unknown6in, unknown7in, IR_CurTEMP_Ext, IR_CurTEMP_Water, IR_CurVBAT, IR_CurRH_Int, IR_CurRH_Ext, IR_CurCO2_Int, IR_CurCO2_Ext, IR_CurPM2_5_Int, IR_CurPM2_5_Ext, IR_CurVOC_Int, IR_CurVOC_Ext, IR_Cur10V_SENSOR, IR_CurSuAirFLOW, IR_CurExAirFLOW, IR_CurSuPRESS, IR_CurExPRESS, IR_SuRPM, IR_ExRPM, unknown26in, IR_CurTIMER_TIME, unknown28in, IR_CurFILTER_TIMER, unknown30in, IR_TotalWorkingTime, IR_StateFILTER, IR_CurWeekSpeed, IR_CurWeekSetTemp, unknown35in, unknown36in, IR_VerMAIN_FMW, IR_DeviceTYPE, IR_ALARM, IR_RH_U, IR_CO2_U, IR_PM2_5_U, IR_VOC_U, IR_PreHeater_U, IR_MainHeater_U, IR_BPS_ROTOR_U, IR_KKB_U, IR_ReturnWater_U, IR_SuAirOutSetTemp, IR_WaterStandbySetTemp, IR_WaterStartSetTemp = in_regs_read
        DI_CurBoostSWITCH, DI_CurFplcSWITCH, DI_CurFireALARM, DI_StatusRH, DI_StatusCO2, DI_StatusPM2_5, DI_StatusVOC, DI_StatusHEATER, DI_StatusCOOLER, DI_StatusFanBLOWING, DI_CurPreHeaterThermostat, DI_CurMainHeaterThermostat, DI_CurSuFilterPRESS, DI_CurExFilterPRESS, DI_CurWaterPRESS, DI_CurWaterFLOW, DI_CurSuFanPRESS, DI_CurExFanPRESS, DI_WaterPreheatingStatus, DI_AlarmCODE0, DI_AlarmCODE1, DI_AlarmCODE2, DI_AlarmCODE3, DI_AlarmCODE4, DI_AlarmCODE5, DI_AlarmCODE6, DI_AlarmCODE7, DI_AlarmCODE8, DI_AlarmCODE9, DI_AlarmCODE10, DI_AlarmCODE11, DI_AlarmCODE12, DI_AlarmCODE13, DI_AlarmCODE14, DI_AlarmCODE15, DI_AlarmCODE16, DI_AlarmCODE17, DI_AlarmCODE18, DI_AlarmCODE19, DI_AlarmCODE20, DI_AlarmCODE21, DI_AlarmCODE22, DI_AlarmCODE23, DI_AlarmCODE24, DI_AlarmCODE25, DI_AlarmCODE26, DI_AlarmCODE27, DI_AlarmCODE28, DI_AlarmCODE29, DI_AlarmCODE30, DI_AlarmCODE31, DI_AlarmCODE32, DI_AlarmCODE33, DI_AlarmCODE34, DI_AlarmCODE35, DI_AlarmCODE36, DI_AlarmCODE37, DI_AlarmCODE38, DI_AlarmCODE39, DI_AlarmCODE40, DI_AlarmCODE41, DI_AlarmCODE42, DI_AlarmCODE43, DI_AlarmCODE44, DI_AlarmCODE45, DI_AlarmCODE46, DI_AlarmCODE47, DI_AlarmCODE48, DI_AlarmCODE49, DI_AlarmCODE50, DI_AlarmCODE51, DI_AlarmCODE52 = dis_in_regs
        HR_VENTILATION_MODE, HR_MaxSPEED_MODE, HR_SPEED_MODE = hl_regs_read
        print("Время", real_time)
        print("Время", type(real_time))
        #          тест списков :)
        #        print("количество значений списка переменних", len(other))
        print("количество значений списка регистров", type(hl_regs_read))
        print(CL_POWER)
        print(IR_CurSelTEMP)
        print(DI_StatusHEATER)
        print(HR_SPEED_MODE)
    else:
Example #23
0
class Device():
    def __init__(self, host, port, timeout, byteorder=BE):       
        # big_endian        :   Byte order of the device memory structure
        #                       True  >>  big endian
        #                       False >>  little endian
        if byteorder == BE:
            self.big_endian=True
        else:
            self.big_endian=False
        
        self.dev = ModbusClient()
        self.dev.host(host)
        self.dev.port(port)
        self.dev.timeout(timeout)
        self.dev.open()
        #self.dev.debug = True

    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ READ METHODS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
    #Method to read binary variable
    def read_bits(self, VarNameList, AddressList, functioncode=2):
        # Arguments:
        # VarNameList       :   list of variable name
        # AddressList       :   list of variable register address in decimal (relative address)
        # functioncode      :   functioncode for modbus reading operation
        #                       1 >> for Discrete Output (Coils)
        #                       2 >> for Discrete Input
        # Return            :   dictionary of variable name and its value
        
        self.values = []
        if functioncode == 1:
            for address in AddressList:
                self.values.extend(self.dev.read_coils(address[0], len(address)))
        elif functioncode == 2:
            for address in AddressList:
                self.values.extend(self.dev.read_discrete_inputs(address[0], len(address)))    
        self.Result = dict(zip(VarNameList, self.values))
        return self.Result

    #Method to read INT16 or UINT16 variable
    def read_INT16(self, VarNameList, AddressList, MultiplierList, signed=False, roundto=3, functioncode=3):
        # Arguments:
        # VarNameList       :   list of variable name
        # AddressList       :   list of variable register address in decimal (relative address)
        # MultiplierList    :   list of multiplier
        # roundto           :   number of digits after decimal point
        #                       any positive integer number >> to limit the number of digits after decimal point
        #                       None                        >> to disable
        # signed            :   True  >> for signed values
        #                       False >> for unsigned values
        # functioncode      :   functioncode for modbus reading operation
        #                       3 >> for Holding Register
        #                       4 >> for Input Register
        # Return            :   dictionary of variable name and its value
        
        self.values = []

        if functioncode == 3:
            for address in AddressList:
                self.values.extend(self.dev.read_holding_registers(address[0],len(address)))
        elif functioncode == 4:
            for address in AddressList:
                self.values.extend(self.dev.read_input_registers(address[0],len(address)))
        
        if signed:
            self.values = UINT16toINT16(self.values)
        
        for i in range(0, len(self.values)):
            self.values[i] = round(self.values[i]*MultiplierList[i],roundto)

        self.Result = dict(zip(VarNameList, self.values))
        return self.Result


    #Method to read INT32 or UINT32 variable
    def read_INT32(self, VarNameList, AddressList, MultiplierList, signed=False, roundto=3, functioncode=3):
        # Arguments:
        # VarNameList       :   list of variable name
        # AddressList       :   list of variable register address in decimal (relative address)
        # MultiplierList    :   list of multiplier
        # roundto           :   number of digits after decimal point
        #                       any positive integer number >> to limit the number of digits after decimal point
        #                       None                        >> to disable
        # signed            :   True  >> for signed values
        #                       False >> for unsigned values
        # functioncode      :   functioncode for modbus reading operation
        #                       3 >> for Holding Register
        #                       4 >> for Input Register
        # Return            :   dictionary of variable name and its value

        self.values = []

        if functioncode == 3:
            for address in AddressList:
                self.values.extend(self.dev.read_holding_registers(address[0],len(address)))
        elif functioncode == 4:
            for address in AddressList:
                self.values.extend(self.dev.read_input_registers(address[0],len(address)))

        self.values = UINT16toINT32(self.values, self.big_endian, signed)
        for i in range(0, len(self.values)):
            self.values[i] = round(self.values[i]*MultiplierList[i], roundto)

        self.Result = dict(zip(VarNameList, self.values))
        return self.Result
    
    #Method to read INT64 or UINT64 variable
    def read_INT64(self, VarNameList, AddressList, MultiplierList, signed=False, roundto=3, functioncode=3):
        # Arguments:
        # VarNameList       :   list of variable name
        # AddressList       :   list of variable register address in decimal (relative address)
        # MultiplierList    :   list of multiplier
        # roundto           :   number of digits after decimal point
        #                       any positive integer number >> to limit the number of digits after decimal point
        #                       None                        >> to disable
        # signed            :   True  >> for signed values
        #                       False >> for unsigned values
        # functioncode      :   functioncode for modbus reading operation
        #                       3 >> for Holding Register
        #                       4 >> for Input Register
        # Return            :   dictionary of variable name and its value
        
        self.values = []

        if functioncode == 3:
            for address in AddressList:
                self.values.extend(self.dev.read_holding_registers(address[0],len(address)))
        elif functioncode == 4:
            for address in AddressList:
                self.values.extend(self.dev.read_input_registers(address[0],len(address)))

        self.values = UINT16toINT64(self.values, self.big_endian, signed)
        for i in range(0, len(self.values)):
            self.values[i] = round(self.values[i]*MultiplierList[i], roundto)

        self.Result = dict(zip(VarNameList, self.values))
        return self.Result

    #Method to read FLOAT16 variable
    def read_FLOAT16(self, VarNameList, AddressList, MultiplierList, roundto=3, functioncode=3):
        # Arguments:
        # VarNameList       :   list of variable name
        # AddressList       :   list of variable register address in decimal (relative address)
        # MultiplierList    :   list of multiplier
        # roundto           :   number of digits after decimal point
        #                       any positive integer number >> to limit the number of digits after decimal point
        #                       None                        >> to disable
        # functioncode      :   functioncode for modbus reading operation
        #                       3 >> for Holding Register
        #                       4 >> for Input Register
        # Return            :   dictionary of variable name and its value
        
        self.values = []

        if functioncode == 3:
            for address in AddressList:
                self.values.extend(self.dev.read_holding_registers(address[0],len(address)))
        elif functioncode == 4:
            for address in AddressList:
                self.values.extend(self.dev.read_input_registers(address[0],len(address)))

        self.values = UINT16toFLOAT16(self.values)
        
        for i in range(0, len(self.values)):
            self.values[i] = round(self.values[i]*MultiplierList[i], roundto)

        self.Result = dict(zip(VarNameList, self.values))
        return self.Result
    
    #Method to read FLOAT32 variable
    def read_FLOAT32(self, VarNameList, AddressList, MultiplierList, roundto=3, functioncode=3):
        # Arguments:
        # VarNameList       :   list of variable name
        # AddressList       :   list of variable register address in decimal (relative address)
        # MultiplierList    :   list of multiplier
        # roundto           :   number of digits after decimal point
        #                       any positive integer number >> to limit the number of digits after decimal point
        #                       None                        >> to disable
        # functioncode      :   functioncode for modbus reading operation
        #                       3 >> for Holding Register
        #                       4 >> for Input Register
        # Return            :   dictionary of variable name and its value
        
        self.values = []

        if functioncode == 3:
            for address in AddressList:
                self.values.extend(self.dev.read_holding_registers(address[0],len(address)))
        elif functioncode == 4:
            for address in AddressList:
                self.values.extend(self.dev.read_input_registers(address[0],len(address)))

        self.values = UINT16toFLOAT32(self.values, self.big_endian)
        for i in range(0, len(self.values)):
            self.values[i] = round(self.values[i]*MultiplierList[i], roundto)
        
        self.Result = dict(zip(VarNameList, self.values))
        return self.Result
    
    #Method to read FLOAT64 variable
    def read_FLOAT64(self, VarNameList, AddressList, MultiplierList, roundto=3, functioncode=3):
        # Arguments:
        # VarNameList       :   list of variable name
        # AddressList       :   list of variable register address in decimal (relative address)
        # MultiplierList    :   list of multiplier
        # roundto           :   number of digits after decimal point
        #                       any positive integer number >> to limit the number of digits after decimal point
        #                       None                        >> to disable
        # functioncode      :   functioncode for modbus reading operation
        #                       3 >> for Holding Register
        #                       4 >> for Input Register
        # Return            :   dictionary of variable name and its value
        
        self.values = []

        if functioncode == 3:
            for address in AddressList:
                self.values.extend(self.dev.read_holding_registers(address[0],len(address)))
        elif functioncode == 4:
            for address in AddressList:
                self.values.extend(self.dev.read_input_registers(address[0],len(address)))

        self.values = UINT16toFLOAT64(self.values, self.big_endian)
        for i in range(0, len(self.values)):
            self.values[i] = round(self.values[i]*MultiplierList[i], roundto)

        self.Result = dict(zip(VarNameList, self.values))
        return self.Result

    #Method to read STRING variable
    def read_STRING(self, VarNameList, AddressList, functioncode=3):
        # Arguments:
        # VarNameList       :   list of variable name
        # AddressList       :   list of variable register address in decimal (relative address)
        # functioncode      :   functioncode for modbus reading operation
        #                       3 >> for Holding Register
        #                       4 >> for Input Register
        # Return            :   dictionary of variable name and its value
        
        self.values = []
        if functioncode == 3:
            for address in AddressList:
                _uint16Val = self.dev.read_holding_registers(address[0],len(address))
                self.values.append(UINT16toSTRING(_uint16Val, self.big_endian))
        elif functioncode == 4:
            for address in AddressList:
                _uint16Val = self.dev.read_input_registers(address[0],len(address))
                self.values.append(UINT16toSTRING(_uint16Val, self.big_endian))
        
        self.Result = dict(zip(VarNameList, self.values))
        return self.Result

    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ WRITE METHODS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
    # Method to write binary value on discrete output register (Coil)
    def write_bit(self, registerAddress, value):
        # Arguments:
        # registerAddress   :   register address in decimal (relative address)
        # value             :   0 or 1
        
        self.dev.write_single_coil(registerAddress, value)

    # Method to write numeric value on holding register
    def write_num(self, registerAddress, value, valueType):
        # Arguments:
        # registerAddress   :   register START address in decimal (relative address)
        # value             :   numerical value
        # valueType         :   UINT16, UINT32, UINT64, INT16, INT32, INT64, FLOAT16,
        #                       FLOAT32, FLOAT64, STRING

        startAddress = registerAddress
        val = None
        
        if valueType == UINT16:
            val = [value]
        elif valueType == INT16:
            val = INT16toUINT16([value])
        elif valueType == UINT32:
            val = INT32toUINT16(value, self.big_endian, signed=False)
        elif valueType == INT32:
            val = INT32toUINT16(value, self.big_endian, signed=True)
        elif valueType == UINT64:
            val = INT64toUINT16(value, self.big_endian, signed=False)
        elif valueType == INT64:
            val = INT64toUINT16(value, self.big_endian, signed=True)
        elif valueType == FLOAT16:
            val = FLOAT16toUINT16([value])
        elif valueType == FLOAT32:
            val = FLOAT32toUINT16(value, self.big_endian)
        elif valueType == FLOAT64:
            val = FLOAT64toUINT16(value, self.big_endian)
        elif valueType == STRING:
            val = STRINGtoUINT16(value, self.big_endian)
    
        # write multiple registers
        self.dev.write_multiple_registers(startAddress, val)

    def close(self):
        self.dev.close()
Example #24
0
class ClienteMODBUS():
    """
    Classe Cliente MODBUS
    """
    def __init__(self,
                 server_ip,
                 porta,
                 device_id=1,
                 scan_time=0.1,
                 valor=0,
                 dbpath="C:\database.db"):
        """
        Construtor
        """
        self._scan_time = scan_time
        self._server_ip = server_ip
        self._device_id = device_id
        self._port = porta
        self._cliente = ModbusClient(host=server_ip,
                                     port=porta,
                                     unit_id=device_id)

        self._dbpath = dbpath
        self._valor = valor
        self._con = sqlite3.connect(self._dbpath)
        self._cursor = self._con.cursor()

    def atendimento(self):
        """
        Método para atendimento do usuário
        """
        try:
            self._cliente.open()
            print('\n\033[33m --> Cliente Modbus conectado..\033[m\n')

        except Exception as e:
            print('\033[31mERRO: ', e.args, '\033[m')

        try:
            atendimento = True
            while atendimento:
                print('-' * 100)
                print('\033[34mCliente Modbus\033[m'.center(100))
                print('-' * 100)
                sel = input(
                    "Qual serviço? \n1- Leitura \n2- Escrita \n3- Configuração \n4- Sair \nNº Serviço: "
                )
                if sel == '1':
                    self.createTable()
                    self.createTableF01()
                    self.createTableF02()
                    self.createTableF03()
                    self.createTableF04()
                    print('\nQual tipo de dado deseja ler?')
                    print(
                        "1- Coil Status \n2- Input Status \n3- Holding Register \n4- Input Register"
                    )
                    while True:
                        tipo = int(input("Type: "))
                        if tipo > 4:
                            print('\033[31mDigite um tipo válido..\033[m')
                            sleep(0.5)
                        else:
                            break

                    if tipo == 3 or tipo == 4:
                        while True:
                            val = int(
                                input(
                                    "\n1- Decimal \n2- Floating Point \n3- Float Swapped \nLeitura: "
                                ))
                            if val > 3:
                                print('\033[31mDigite um tipo válido..\033[m')
                                sleep(0.5)
                            else:
                                break
                        if val == 1:  #valores decimais
                            addr = int(input(f'\nAddress: '))
                            leng = int(input(f'Length: '))
                            nvezes = input('Quantidade de leituras: ')
                            print('\nComeçando leitura Decimal..\n')
                            sleep(0.5)
                            try:
                                for i in range(0, int(nvezes)):
                                    print(f'\033[33mLeitura {i+1}:\033[m',
                                          end='')
                                    print(
                                        self.lerDado(int(tipo), int(addr),
                                                     leng))
                                    sleep(self._scan_time)
                                print(
                                    '\nValores lidos e inseridos no DB com sucesso!!\n'
                                )
                                sleep(0.5)
                            except Exception as e:
                                print('\033[31mERRO: ', e.args, '\033[m')
                                try:
                                    sleep(0.5)
                                    print(
                                        '\033[33m\nTentando novamente..\033[m')
                                    if not self._cliente.is_open():
                                        self._cliente.open()
                                    sleep(0.5)
                                    for i in range(0, int(nvezes)):
                                        print(
                                            f'\033[33mLeitura {i + 1}:\033[m',
                                            end='')
                                        print(
                                            self.lerDado(
                                                int(tipo), int(addr), leng))
                                        sleep(self._scan_time)
                                    print(
                                        '\nValores lidos e inseridos no DB com sucesso!!\n'
                                    )
                                    sleep(0.5)
                                except Exception as e:
                                    print('\033[31mERRO: ', e.args, '\033[m')
                                    print(
                                        '\nO Cliente não conseguiu receber uma resposta.. \nVoltando ao menu..\n\n'
                                    )
                                    sleep(1.5)

                        elif val == 2:  #valores FLOAT
                            addr = input(f'\nAddress: ')
                            leng = int(input(f'Length: '))
                            nvezes = input('Quantidade de leituras: ')
                            print('\nComeçando leitura FLOAT..\n')
                            sleep(0.5)
                            try:
                                for i in range(0, int(nvezes)):
                                    print(f'\033[33mLeitura {i + 1}:\033[m',
                                          end='')
                                    print(
                                        self.lerDadoFloat(
                                            int(tipo), int(addr), leng))
                                    sleep(self._scan_time)
                                print(
                                    '\nValores lidos e inseridos no DB com sucesso!!\n'
                                )
                                sleep(0.5)
                            except Exception as e:
                                print('\033[31mERRO: ', e.args, '\033[m\n')
                                print(
                                    'O Cliente não conseguiu receber uma resposta.. \nVoltando ao menu..\n\n'
                                )
                                sleep(1.5)

                        elif val == 3:  #valores FLOAT SWAPPED
                            addr = input(f'\nAddress: ')
                            leng = int(input(f'Length: '))
                            nvezes = input('Quantidade de leituras: ')
                            print('\nComeçando leitura FLOAT SWAPPED..\n')
                            sleep(0.5)
                            try:
                                for i in range(0, int(nvezes)):
                                    print(f'\033[33mLeitura {i + 1}:\033[m',
                                          end='')
                                    print(
                                        self.lerDadoFloatSwapped(
                                            int(tipo), int(addr), leng))
                                    sleep(self._scan_time)
                                print(
                                    '\nValores lidos e inseridos no DB com sucesso!!\n'
                                )
                                sleep(0.5)
                            except Exception as e:
                                print('\033[31mERRO: ', e.args, '\033[m\n')
                                print(
                                    'O Cliente não conseguiu receber uma resposta.. \nVoltando ao menu..\n\n'
                                )
                                sleep(1.5)

                        else:
                            print('\033[31mSeleção inválida..\033[m\n')
                            sleep(0.7)

                    else:
                        addr = input(f'\nAddress: ')
                        leng = int(input(f'Length: '))
                        nvezes = input('Quantidade de leituras: ')
                        print('\nComeçando leitura..\n')
                        sleep(0.5)
                        try:
                            for i in range(0, int(nvezes)):
                                print(f'\033[33mLeitura {i + 1}:\033[m',
                                      end='')
                                print(self.lerDado(int(tipo), int(addr), leng))
                                sleep(self._scan_time)
                            print(
                                '\nValores lidos e inseridos no DB com sucesso!!\n'
                            )
                            sleep(0.5)
                        except Exception as e:
                            print('\033[31mERRO: ', e.args, '\033[m\n')
                            print(
                                'O Cliente não conseguiu receber uma resposta.. \nVoltando ao menu..\n\n'
                            )
                            sleep(1.5)

                elif sel == '2':
                    print(
                        '\nQual tipo de dado deseja escrever? \n1- Coil Status \n2- Holding Register'
                    )
                    while True:
                        tipo = int(input("Tipo: "))
                        if tipo > 2:
                            print('\033[31mDigite um tipo válido..\033[m')
                            sleep(0.5)
                        else:
                            break
                    addr = input(f'Digite o endereço: ')
                    valor = int(input(f'Digite o valor que deseja escrever: '))
                    try:
                        print('\nEscrevendo..')
                        sleep(0.5)
                        self.escreveDado(int(tipo), int(addr), valor)
                    except Exception as e:
                        print('\033[31mERRO: ', e.args, '\033[m')
                        print(
                            '\nO Cliente não conseguiu escrever.. \nVoltando ao menu..\n\n'
                        )
                        sleep(1.5)

                elif sel == '3':
                    print('')
                    print('-' * 100)
                    print('Configurações de Leitura'.center(100))
                    print(
                        f'\n\033[32m->\033[m Configuração atual: - IP Addrs: \033[35m{self._server_ip}\033[m - TCP Port: \033[35m{self._port}\033[m - Device ID: \033[35m{self._device_id}\033[m - Scan_Time: \033[35m{self._scan_time}\033[ms'
                    )
                    print(
                        '\nQual tipo de configuração deseja fazer? \n1- Endereço IP \n2- Porta TCP \n3- Device ID \n4- ScanTime \n5- Voltar'
                    )
                    config = int(input("Configuração: "))
                    if config == 1:
                        ipserv = str(input(' Novo endereço IP: '))
                        try:
                            self._cliente.close()
                            self._server_ip = ipserv
                            self._cliente = ModbusClient(host=self._server_ip)
                            self._cliente.open()
                            print(
                                f'\nServer IP alterado para {ipserv} com sucesso!!\n'
                            )
                            sleep(0.5)
                        except Exception as e:
                            print('\033[31mERRO: ', e.args, '\033[m')
                            print(
                                '\nNão foi possível alterar o endereço IP.. \nVoltando ao menu..\n\n'
                            )
                            sleep(0.5)
                    elif config == 2:
                        porttcp = input(' Nova porta TCP: ')
                        try:
                            self._cliente.close()
                            self._port = int(porttcp)
                            self._cliente = ModbusClient(port=self._port)
                            self._cliente.open()
                            print(
                                f'\nTCP port alterado para {porttcp} com sucesso!!\n'
                            )
                            sleep(0.5)
                        except Exception as e:
                            print('\033[31mERRO: ', e.args, '\033[m')
                            print(
                                '\nNão foi possível alterar a porta.. \nVoltando ao menu..\n\n'
                            )
                            sleep(0.5)
                    elif config == 3:
                        while True:
                            iddevice = input(' Novo device ID: ')
                            if 0 <= int(iddevice) < 256:
                                break
                            else:
                                print(
                                    '\033[31mDevice ID deve ser um número inteiro entre 0 e 256.\033[m',
                                    end='')
                                sleep(0.5)
                        try:
                            self._cliente.close()
                            self._device_id = int(iddevice)
                            self._cliente = ModbusClient(
                                unit_id=self._device_id)
                            self._cliente.open()
                            print(
                                f'\nDevice ID alterado para {iddevice} com sucesso!!\n'
                            )
                            sleep(0.5)
                        except Exception as e:
                            print('\033[31mERRO: ', e.args, '\033[m')
                            print(
                                '\nNão foi possível alterar o ID do device.. \nVoltando ao menu..\n\n'
                            )
                            sleep(0.5)
                    elif config == 4:
                        scant = input(' Novo tempo de varredura [s]: ')
                        try:
                            self._scan_time = float(scant)
                            print(
                                f'\nScan_time alterado para {scant}s com sucesso!!\n'
                            )
                        except Exception as e:
                            print('\033[31mERRO: ', e.args, '\033[m')
                            print(
                                '\nNão foi possível alterar o tempo de varredura.. \nVoltando ao menu..\n\n'
                            )
                            sleep(0.5)
                    elif config == 5:
                        print('\nVoltando ao menu inicial..\n')
                        sleep(0.5)
                    else:
                        print('\033[31mSeleção inválida..\033[m\n')
                        sleep(0.7)

                elif sel == '4':
                    sleep(0.2)
                    print('\n\033[32mFechando sistema..\033[m')
                    sleep(0.5)
                    self._cliente.close()
                    atendimento = False

                else:
                    print('\033[31mSeleção inválida..\033[m\n')
                    sleep(0.7)
        except Exception as e:
            print('\033[31mERRO: ', e.args, '\033[m')

    def createTable(self):
        """
        Método que cria a tabela para armazenamento dos dados, caso ela não exista
        """
        try:
            sql_str = f"""
            CREATE TABLE IF NOT EXISTS pointValues (
                ID INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, Address TEXT, Type TEXT, Display TEXT, Value REAL, TimeStamp1 TEXT NOT NULL)
                """
            self._cursor.execute(sql_str)
            self._con.commit()
        except Exception as e:
            print('\033[31mERRO: ', e.args, '\033[m')

    def inserirDB(self, addrs, tipo, disp, value):
        """
        Método para inserção dos dados no DB
        """
        try:
            date = str(
                datetime.datetime.fromtimestamp(int(
                    time.time())).strftime("%Y-%m-%d %H:%M:%S"))
            str_values = f"'{addrs}', {tipo}, {disp}, {value}, '{date}'"
            sql_str = f'INSERT INTO pointValues (Address, Type, Display, Value, TimeStamp1) VALUES ({str_values})'
            self._cursor.execute(sql_str)
            self._con.commit()
        except Exception as e:
            print('\033[31mERRO: ', e.args, '\033[m')

    def createTableF01(self):
        """
        Método que cria a tabela para armazenamento dos dados, caso ela não exista
        """
        try:
            sql_str = f"""
            CREATE TABLE IF NOT EXISTS pointValuesF01 (
                ID INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, Address TEXT, Type TEXT, Display TEXT, Value REAL, TimeStamp1 TEXT NOT NULL)
                """
            self._cursor.execute(sql_str)
            self._con.commit()
        except Exception as e:
            print('\033[31mERRO: ', e.args, '\033[m')

    def createTableF02(self):
        """
        Método que cria a tabela para armazenamento dos dados, caso ela não exista
        """
        try:
            sql_str = f"""
            CREATE TABLE IF NOT EXISTS pointValuesF02 (
                ID INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, Address TEXT, Type TEXT, Display TEXT, Value REAL, TimeStamp1 TEXT NOT NULL)
                """
            self._cursor.execute(sql_str)
            self._con.commit()
        except Exception as e:
            print('\033[31mERRO: ', e.args, '\033[m')

    def createTableF03(self):
        """
        Método que cria a tabela para armazenamento dos dados, caso ela não exista
        """
        try:
            sql_str = f"""
            CREATE TABLE IF NOT EXISTS pointValuesF03 (
                ID INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, Address TEXT, Type TEXT, Display TEXT, Value REAL, TimeStamp1 TEXT NOT NULL)
                """
            self._cursor.execute(sql_str)
            self._con.commit()
        except Exception as e:
            print('\033[31mERRO: ', e.args, '\033[m')

    def createTableF04(self):
        """
        Método que cria a tabela para armazenamento dos dados, caso ela não exista
        """
        try:
            sql_str = f"""
            CREATE TABLE IF NOT EXISTS pointValuesF04 (
                ID INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, Address TEXT, Type TEXT, Display TEXT, Value REAL, TimeStamp1 TEXT NOT NULL)
                """
            self._cursor.execute(sql_str)
            self._con.commit()
        except Exception as e:
            print('\033[31mERRO: ', e.args, '\033[m')

    def inserirDBF0(self, addrs, tipo, disp, value):
        """
        Método para inserção dos dados no DB
        """
        try:
            if tipo == "'F01-CoilStatus'":
                date = str(
                    datetime.datetime.fromtimestamp(int(
                        time.time())).strftime("%Y-%m-%d %H:%M:%S"))
                str_values = f"'{addrs}', {tipo}, {disp}, {value}, '{date}'"
                sql_str = f'INSERT INTO pointValuesF01 (Address, Type, Display, Value, TimeStamp1) VALUES ({str_values})'
                self._cursor.execute(sql_str)
                self._con.commit()
            elif tipo == "'F02-InputStatus'":
                date = str(
                    datetime.datetime.fromtimestamp(int(
                        time.time())).strftime("%Y-%m-%d %H:%M:%S"))
                str_values = f"'{addrs}', {tipo}, {disp}, {value}, '{date}'"
                sql_str = f'INSERT INTO pointValuesF02 (Address, Type, Display, Value, TimeStamp1) VALUES ({str_values})'
                self._cursor.execute(sql_str)
                self._con.commit()
            elif tipo == "'F03-HoldingRegister'":
                date = str(
                    datetime.datetime.fromtimestamp(int(
                        time.time())).strftime("%Y-%m-%d %H:%M:%S"))
                str_values = f"'{addrs}', {tipo}, {disp}, {value}, '{date}'"
                sql_str = f'INSERT INTO pointValuesF03 (Address, Type, Display, Value, TimeStamp1) VALUES ({str_values})'
                self._cursor.execute(sql_str)
                self._con.commit()
            elif tipo == "'F04-InputRegister'":
                date = str(
                    datetime.datetime.fromtimestamp(int(
                        time.time())).strftime("%Y-%m-%d %H:%M:%S"))
                str_values = f"'{addrs}', {tipo}, {disp}, {value}, '{date}'"
                sql_str = f'INSERT INTO pointValuesF04 (Address, Type, Display, Value, TimeStamp1) VALUES ({str_values})'
                self._cursor.execute(sql_str)
                self._con.commit()
        except Exception as e:
            print('\033[31mERRO: ', e.args, '\033[m')

    def inserirDBFP(self, addrs, tipo, disp, value):
        """
        Método para inserção dos dados no DB
        """
        try:
            if tipo == "'F03-HoldingRegister'":
                date = str(
                    datetime.datetime.fromtimestamp(int(
                        time.time())).strftime("%Y-%m-%d %H:%M:%S"))
                str_values = f"'{addrs}', {tipo}, {disp}, {value}, '{date}'"
                sql_str = f'INSERT INTO pointValuesF03 (Address, Type, Display, Value, TimeStamp1) VALUES ({str_values})'
                self._cursor.execute(sql_str)
                self._con.commit()
            elif tipo == "'F04-InputRegister'":
                date = str(
                    datetime.datetime.fromtimestamp(int(
                        time.time())).strftime("%Y-%m-%d %H:%M:%S"))
                str_values = f"'{addrs}', {tipo}, {disp}, {value}, '{date}'"
                sql_str = f'INSERT INTO pointValuesF04 (Address, Type, Display, Value, TimeStamp1) VALUES ({str_values})'
                self._cursor.execute(sql_str)
                self._con.commit()
            else:
                print(
                    "Erro ao inserir no DB com Floating Point e Float Swapped!!"
                )
        except Exception as e:
            print('\033[31mERRO: ', e.args, '\033[m')

    def lerDado(self, tipo, addr, leng=1):
        """
        Método para leitura MODBUS
        """
        if tipo == 1:
            co = self._cliente.read_coils(addr - 1, leng)
            ic = 0
            while ic <= leng:
                if ic == leng:
                    break
                else:
                    value = co[0 + ic]
                    ic += 1
                    # print(value)
                    if value == True:
                        value = 1
                    else:
                        value = 0
                    ende = str(addr + ic - 1).zfill(5)
                    self.inserirDB(addrs=str(ende),
                                   tipo="'F01-CoilStatus'",
                                   disp="'Booleano'",
                                   value=value)
                    self.inserirDBF0(addrs=str(ende),
                                     tipo="'F01-CoilStatus'",
                                     disp="'Booleano'",
                                     value=value)
            return co

        elif tipo == 2:
            di = self._cliente.read_discrete_inputs(addr - 1, leng)
            idi = 0
            while idi <= leng:
                if idi == leng:
                    break
                else:
                    value = di[0 + idi]
                    idi += 1
                    # print(value)
                    self.inserirDB(addrs=(10000 + addr + idi - 1),
                                   tipo="'F02-InputStatus'",
                                   disp="'Booleano'",
                                   value=value)
                    self.inserirDBF0(addrs=(10000 + addr + idi - 1),
                                     tipo="'F02-InputStatus'",
                                     disp="'Booleano'",
                                     value=value)
            return di

        elif tipo == 3:
            hr = self._cliente.read_holding_registers(addr - 1, leng)
            ihr = 0
            while ihr <= leng:
                if ihr == leng:
                    break
                else:
                    value = hr[0 + ihr]
                    ihr += 1
                    # print(value)
                    self.inserirDB(addrs=(40000 + addr + ihr - 1),
                                   tipo="'F03-HoldingRegister'",
                                   disp="'Decimal'",
                                   value=value)
                    self.inserirDBF0(addrs=(40000 + addr + ihr - 1),
                                     tipo="'F03-HoldingRegister'",
                                     disp="'Decimal'",
                                     value=value)
            return hr

        elif tipo == 4:
            ir = self._cliente.read_input_registers(addr - 1, leng)
            iir = 0
            while iir <= leng:
                if iir == leng:
                    break
                else:
                    value = ir[0 + iir]
                    iir += 1
                    # print(value)
                    self.inserirDB(addrs=(30000 + addr + iir - 1),
                                   tipo="'F04-InputRegister'",
                                   disp="'Decimal'",
                                   value=value)
                    self.inserirDBF0(addrs=(30000 + addr + iir - 1),
                                     tipo="'F04-InputRegister'",
                                     disp="'Decimal'",
                                     value=value)
            return ir

        else:
            print('Tipo de leitura inválido..')

    def lerDadoFloat(self, tipo, addr, leng):
        """
        Método para leitura FLOAT MODBUS
        """
        i = 0
        g = 0
        e1 = []
        listfloat = []
        while i < leng:
            if tipo == 3:
                i1 = self._cliente.read_holding_registers(addr - 1 + g, 2)
                tipore = "'F03-HoldingRegister'"
                ende = 40000
            elif tipo == 4:
                i1 = self._cliente.read_input_registers(addr - 1 + g, 2)
                tipore = "'F04-InputRegister'"
                ende = 30000
            else:
                print('Tipo inválido..')
            for x in i1:
                x = bin(x).lstrip("0b")
                e1.insert(0 + g, x)
            i += 1
            g += 2
        e = 0
        while e <= leng:
            e2 = ''
            for x in e1:
                e2 = str(f'{e2}{x.rjust(16, "0")} ')
            e += 1
        b2 = str(f'{e2}')
        e3 = b2.split()
        y = 0
        while y < len(e3):
            ieee = f'{e3[0+y]}{e3[1+y]}'
            sign = int(ieee[0])
            expo = str(ieee[1:9])
            expodec = 0
            expopot = 7
            for i in range(8):
                expodec = expodec + (int(expo[i]) * (2**expopot))
                expopot -= 1
            mant = str(ieee[9:])
            mantdec = 0
            mantpot = -1
            for i in range(23):
                mantdec = mantdec + (int(mant[i]) * (2**mantpot))
                mantpot -= 1
            value = ((-1)**sign) * (1 + mantdec) * 2**(expodec - 127)
            # print(f'{round(value, 3)}')
            listfloat.append(round(value, 3))
            y += 2
            self.inserirDB(addrs=(ende + addr + y - 2),
                           tipo=tipore,
                           disp="'Floating Point'",
                           value=round(value, 3))
            self.inserirDBFP(addrs=(ende + addr + y - 2),
                             tipo=tipore,
                             disp="'Floating Point'",
                             value=round(value, 3))
        return listfloat

    def lerDadoFloatSwapped(self, tipo, addr, leng):
        """
        Método para leitura FLOAT SWAPPED MODBUS
        """
        i = 0
        g = 0
        e1 = []
        listfloatsp = []
        while i < leng:
            if tipo == 3:
                i1 = self._cliente.read_holding_registers(addr - 1 + g, 2)
                tipore = "'F03-HoldingRegister'"
                ende = 40000
            elif tipo == 4:
                i1 = self._cliente.read_input_registers(addr - 1 + g, 2)
                tipore = "'F04-InputRegister'"
                ende = 30000
            else:
                print('Tipo inválido..')
            i2 = i1[::-1]
            for x in i2:
                x = bin(x).lstrip("0b")
                e1.insert(0 + g, x)
            i += 1
            g += 2
        e = 0
        while e <= leng:
            e2 = ''
            for x in e1:
                e2 = str(f'{e2}{x.rjust(16, "0")} ')
            e += 1
        b2 = str(f'{e2}')
        e3 = b2.split()
        y = 0
        while y < len(e3):
            ieee = f'{e3[0+y]}{e3[1+y]}'
            sign = int(ieee[0])
            expo = str(ieee[1:9])
            expodec = 0
            expopot = 7
            for i in range(8):
                expodec = expodec + (int(expo[i]) * (2**expopot))
                expopot -= 1
            mant = str(ieee[9:])
            mantdec = 0
            mantpot = -1
            for i in range(23):
                mantdec = mantdec + (int(mant[i]) * (2**mantpot))
                mantpot -= 1
            value = ((-1)**sign) * (1 + mantdec) * 2**(expodec - 127)
            # print(f'{round(value, 3)}')
            listfloatsp.append(round(value, 3))
            y += 2
            self.inserirDB(addrs=(ende + addr + y - 2),
                           tipo=tipore,
                           disp="'Float (Swapped)'",
                           value=round(value, 3))
            self.inserirDBFP(addrs=(ende + addr + y - 2),
                             tipo=tipore,
                             disp="'Float (Swapped)'",
                             value=round(value, 3))
        return listfloatsp

    def escreveDado(self, tipo, addr, valor):
        """
        Método para escrita MODBUS
        """
        try:
            if tipo == 1:
                print(
                    f'\033[33mValor {valor} escrito no endereço {addr}\033[m\n'
                )
                return self._cliente.write_single_coil(addr - 1, valor)
            elif tipo == 2:
                print(
                    f'\033[33mValor {valor} escrito no endereço {addr}\033[m\n'
                )
                return self._cliente.write_single_register(addr - 1, valor)
            else:
                print('Tipo de escrita inválido..\n')

        except Exception as e:
            print('\033[31mERRO: ', e.args, '\033[m')