コード例 #1
0
ファイル: exceptions.py プロジェクト: Cougar/pymodbus_async
    def __init__(self, string=""):
        """ Initialize the exception

        :param string: The message to append to the error
        """
        message = "[Timeout] %s" % string
        ModbusException.__init__(self, message)
コード例 #2
0
ファイル: test_cover.py プロジェクト: nickovs/home-assistant
async def test_service_cover_move(hass, mock_modbus, mock_ha):
    """Run test for service homeassistant.update_entity."""

    mock_modbus.read_holding_registers.return_value = ReadResult([0x01])
    await hass.services.async_call("cover",
                                   "open_cover", {"entity_id": ENTITY_ID},
                                   blocking=True)
    assert hass.states.get(ENTITY_ID).state == STATE_OPEN

    mock_modbus.read_holding_registers.return_value = ReadResult([0x00])
    await hass.services.async_call("cover",
                                   "close_cover", {"entity_id": ENTITY_ID},
                                   blocking=True)
    assert hass.states.get(ENTITY_ID).state == STATE_CLOSED

    mock_modbus.reset()
    mock_modbus.read_holding_registers.side_effect = ModbusException(
        "fail write_")
    await hass.services.async_call("cover",
                                   "close_cover", {"entity_id": ENTITY_ID},
                                   blocking=True)
    assert mock_modbus.read_holding_registers.called
    assert hass.states.get(ENTITY_ID).state == STATE_UNAVAILABLE

    mock_modbus.read_coils.side_effect = ModbusException("fail write_")
    await hass.services.async_call("cover",
                                   "close_cover", {"entity_id": ENTITY_ID2},
                                   blocking=True)
    assert hass.states.get(ENTITY_ID2).state == STATE_UNAVAILABLE
コード例 #3
0
async def test_service_cover_move(hass, mock_pymodbus):
    """Run test for service homeassistant.update_entity."""

    ENTITY_ID2 = f"{ENTITY_ID}2"
    config = {
        CONF_COVERS: [
            {
                CONF_NAME: COVER_NAME,
                CONF_ADDRESS: 1234,
                CONF_STATUS_REGISTER_TYPE: CALL_TYPE_REGISTER_HOLDING,
                CONF_SCAN_INTERVAL: 0,
            },
            {
                CONF_NAME: f"{COVER_NAME}2",
                CONF_INPUT_TYPE: CALL_TYPE_COIL,
                CONF_ADDRESS: 1234,
                CONF_SCAN_INTERVAL: 0,
            },
        ]
    }
    mock_pymodbus.read_holding_registers.return_value = ReadResult([0x01])
    await prepare_service_update(
        hass,
        config,
    )
    await hass.services.async_call(
        "cover", "open_cover", {"entity_id": ENTITY_ID}, blocking=True
    )
    assert hass.states.get(ENTITY_ID).state == STATE_OPEN

    mock_pymodbus.read_holding_registers.return_value = ReadResult([0x00])
    await hass.services.async_call(
        "cover", "close_cover", {"entity_id": ENTITY_ID}, blocking=True
    )
    assert hass.states.get(ENTITY_ID).state == STATE_CLOSED

    mock_pymodbus.reset()
    mock_pymodbus.read_holding_registers.side_effect = ModbusException("fail write_")
    await hass.services.async_call(
        "cover", "close_cover", {"entity_id": ENTITY_ID}, blocking=True
    )
    assert mock_pymodbus.read_holding_registers.called
    assert hass.states.get(ENTITY_ID).state == STATE_UNAVAILABLE

    mock_pymodbus.read_coils.side_effect = ModbusException("fail write_")
    await hass.services.async_call(
        "cover", "close_cover", {"entity_id": ENTITY_ID2}, blocking=True
    )
    assert hass.states.get(ENTITY_ID2).state == STATE_UNAVAILABLE
コード例 #4
0
    def sync_write(self, value: int | float | str, obj: ModbusObj) -> None:
        """Write value to Modbus object.

        Args:
            value: Value to write
            obj: Object instance.
        """
        if obj.func_write is None:
            raise ModbusException("Object cannot be overwritten")
        if isinstance(value, str):
            raise NotImplementedError(
                "Modbus expected numbers to write. Got `str`.")

        payload = self._build_payload(value=value, obj=obj)

        if obj.func_write is ModbusWriteFunc.WRITE_REGISTER and isinstance(
                payload, list):
            # FIXME: hotfix
            assert len(payload) == 1
            payload = payload[0]  # type: ignore

        request = self.write_funcs[obj.func_write](
            obj.address,
            payload,
            unit=self._device_obj.property_list.rtu.unit,  # type: ignore
        )
        if request.isError():
            raise ModbusIOException("0x80")  # todo: resp.string
        self._LOG.debug("Successfully write",
                        extra={
                            "object": obj,
                            "value": value
                        })
コード例 #5
0
async def test_pymodbus_connect_fail(hass, caplog, mock_pymodbus):
    """Run test for failing pymodbus constructor."""
    config = {
        DOMAIN: [{
            CONF_TYPE: "tcp",
            CONF_HOST: "modbusTestHost",
            CONF_PORT: 5501,
        }]
    }
    caplog.set_level(logging.ERROR)
    mock_pymodbus.connect.side_effect = ModbusException("test connect fail")
    mock_pymodbus.close.side_effect = ModbusException("test connect fail")
    assert await async_setup_component(hass, DOMAIN, config) is True
    await hass.async_block_till_done()
    assert len(caplog.records) == 1
    assert caplog.records[0].levelname == "ERROR"
コード例 #6
0
ファイル: test_init.py プロジェクト: tpaulus/core
async def test_pb_service_write(hass, do_write, caplog, mock_modbus):
    """Run test for service write_register."""

    func_name = {
        CALL_TYPE_WRITE_COIL: mock_modbus.write_coil,
        CALL_TYPE_WRITE_COILS: mock_modbus.write_coils,
        CALL_TYPE_WRITE_REGISTER: mock_modbus.write_register,
        CALL_TYPE_WRITE_REGISTERS: mock_modbus.write_registers,
    }

    data = {
        ATTR_HUB: TEST_MODBUS_NAME,
        ATTR_UNIT: 17,
        ATTR_ADDRESS: 16,
        do_write[DATA]: do_write[VALUE],
    }
    await hass.services.async_call(DOMAIN, do_write[SERVICE], data, blocking=True)
    assert func_name[do_write[FUNC]].called
    assert func_name[do_write[FUNC]].call_args[0] == (
        data[ATTR_ADDRESS],
        data[do_write[DATA]],
    )
    mock_modbus.reset_mock()

    for return_value in [
        ExceptionResponse(0x06),
        IllegalFunctionRequest(0x06),
        ModbusException("fail write_"),
    ]:
        caplog.set_level(logging.DEBUG)
        func_name[do_write[FUNC]].return_value = return_value
        await hass.services.async_call(DOMAIN, do_write[SERVICE], data, blocking=True)
        assert func_name[do_write[FUNC]].called
        assert caplog.messages[-1].startswith("Pymodbus:")
        mock_modbus.reset_mock()
コード例 #7
0
    def _helper(self, data):
        '''
        This factory is used to generate the correct response object
        from a valid response packet. This decodes from a list of the
        currently implemented request types.

        :param data: The response packet to decode
        :returns: The decoded request or an exception response object
        '''
        function_code = ord(data[0])
        _logger.debug("Factory Response[%d]" % function_code)
        response = self.__lookup.get(function_code, lambda: None)()
        if function_code > 0x80:
            code = function_code & 0x7f  # strip error portion
            response = ExceptionResponse(code, ecode.IllegalFunction)
        if not response:
            raise ModbusException("Unknown response %d" % function_code)
        response.decode(data[1:])

        if hasattr(response, 'sub_function_code'):
            lookup = self.__sub_lookup.get(response.function_code, {})
            subtype = lookup.get(response.sub_function_code, None)
            if subtype: response.__class__ = subtype

        return response
コード例 #8
0
async def test_service_cover_move(opp, mock_pymodbus):
    """Run test for service openpeerpower.update_entity."""

    entity_id = "cover.test"
    entity_id2 = "cover.test2"
    config = {
        CONF_COVERS: [
            {
                CONF_NAME: "test",
                CONF_REGISTER: 1234,
                CONF_STATUS_REGISTER_TYPE: CALL_TYPE_REGISTER_HOLDING,
            },
            {
                CONF_NAME: "test2",
                CALL_TYPE_COIL: 1234,
            },
        ]
    }
    mock_pymodbus.read_holding_registers.return_value = ReadResult([0x01])
    await prepare_service_update(
        opp,
        config,
    )
    await opp.services.async_call("cover",
                                  "open_cover", {"entity_id": entity_id},
                                  blocking=True)
    assert opp.states.get(entity_id).state == STATE_OPEN

    mock_pymodbus.read_holding_registers.return_value = ReadResult([0x00])
    await opp.services.async_call("cover",
                                  "close_cover", {"entity_id": entity_id},
                                  blocking=True)
    assert opp.states.get(entity_id).state == STATE_CLOSED

    mock_pymodbus.read_holding_registers.side_effect = ModbusException(
        "fail write_")
    await opp.services.async_call("cover",
                                  "close_cover", {"entity_id": entity_id},
                                  blocking=True)
    assert opp.states.get(entity_id).state == STATE_UNAVAILABLE

    mock_pymodbus.read_coils.side_effect = ModbusException("fail write_")
    await opp.services.async_call("cover",
                                  "close_cover", {"entity_id": entity_id2},
                                  blocking=True)
    assert opp.states.get(entity_id2).state == STATE_UNAVAILABLE
コード例 #9
0
ファイル: conftest.py プロジェクト: pgenera/home-assistant
async def mock_pymodbus_exception(hass, do_exception, mock_modbus):
    """Trigger update call with time_changed event."""
    if do_exception:
        exc = ModbusException("fail read_coils")
        mock_modbus.read_coils.side_effect = exc
        mock_modbus.read_discrete_inputs.side_effect = exc
        mock_modbus.read_input_registers.side_effect = exc
        mock_modbus.read_holding_registers.side_effect = exc
コード例 #10
0
    def _write(self, address, value, **kwargs):
        """Perform the write, enforcing Defaults.Timeout around the entire transaction.  Normally
        returns None, but may raise a ModbusException or a PlcOffline if there are communications
        problems.

        Use a supplied 'unit' ID, or the one specified/deduced at construction.

        """
        self.client.timeout = True

        if not self.client.connect():
            raise PlcOffline(
                "Modbus Write to PLC %s/%6d failed: Offline; Connect failure" %
                (self.description, address))

        # Use address to deduce Holding Register or Coil (the only writable
        # entities); Statuses and Input Registers result in a pymodbus
        # ParameterException
        multi = hasattr(value, '__iter__')
        writer = None
        if 400001 <= address <= 465536:
            # 400001-465536: Holding Registers
            writer = (WriteMultipleRegistersRequest
                      if multi or self.multi else WriteSingleRegisterRequest)
            address -= 400001
        elif 40001 <= address <= 99999:
            #  40001-99999: Holding Registers
            writer = (WriteMultipleRegistersRequest
                      if multi or self.multi else WriteSingleRegisterRequest)
            address -= 40001
        elif 1 <= address <= 9999:
            #      1-9999: Coils
            writer = (
                WriteMultipleCoilsRequest if multi  # *don't* force multi
                else WriteSingleCoilRequest)
            address -= 1
        else:
            # 100001-165536: Statuses (not writable)
            # 300001-365536: Input Registers (not writable)
            # 10001-19999: Statuses (not writable)
            # 30001-39999: Input Registers (not writable)
            pass
        if not writer:
            raise ParameterException("Invalid Modbus address for write: %d" %
                                     (address))

        if writer is WriteMultipleRegistersRequest:
            # Overcome bug in 1.2.0/1.3.0 in handling single requests.  Also reifies generators.
            value = list(value) if multi else [value]

        unit = kwargs.pop('unit', self.unit)
        result = self.client.execute(
            writer(address, value, unit=unit, **kwargs))
        if isinstance(result, ExceptionResponse):
            raise ModbusException(str(result))
        assert isinstance(
            result,
            ModbusResponse), "Unexpected non-ModbusResponse: %r" % result
コード例 #11
0
ファイル: test_light.py プロジェクト: rikroe/core
async def test_light_service_turn(hass, caplog, mock_modbus):
    """Run test for service turn_on/turn_off."""

    assert MODBUS_DOMAIN in hass.config.components

    assert hass.states.get(ENTITY_ID).state == STATE_OFF
    await hass.services.async_call("light",
                                   "turn_on",
                                   service_data={"entity_id": ENTITY_ID})
    await hass.async_block_till_done()
    assert hass.states.get(ENTITY_ID).state == STATE_ON
    await hass.services.async_call("light",
                                   "turn_off",
                                   service_data={"entity_id": ENTITY_ID})
    await hass.async_block_till_done()
    assert hass.states.get(ENTITY_ID).state == STATE_OFF

    mock_modbus.read_holding_registers.return_value = ReadResult([0x01])
    assert hass.states.get(ENTITY_ID2).state == STATE_OFF
    await hass.services.async_call("light",
                                   "turn_on",
                                   service_data={"entity_id": ENTITY_ID2})
    await hass.async_block_till_done()
    assert hass.states.get(ENTITY_ID2).state == STATE_ON
    mock_modbus.read_holding_registers.return_value = ReadResult([0x00])
    await hass.services.async_call("light",
                                   "turn_off",
                                   service_data={"entity_id": ENTITY_ID2})
    await hass.async_block_till_done()
    assert hass.states.get(ENTITY_ID2).state == STATE_OFF

    mock_modbus.write_register.side_effect = ModbusException("fail write_")
    await hass.services.async_call("light",
                                   "turn_on",
                                   service_data={"entity_id": ENTITY_ID2})
    await hass.async_block_till_done()
    assert hass.states.get(ENTITY_ID2).state == STATE_UNAVAILABLE
    mock_modbus.write_coil.side_effect = ModbusException("fail write_")
    await hass.services.async_call("light",
                                   "turn_off",
                                   service_data={"entity_id": ENTITY_ID})
    await hass.async_block_till_done()
    assert hass.states.get(ENTITY_ID).state == STATE_UNAVAILABLE
コード例 #12
0
async def test_pymodbus_close_fail(hass, caplog, mock_pymodbus):
    """Run test for failing pymodbus close."""
    config = {
        DOMAIN: [{
            CONF_TYPE: "tcp",
            CONF_HOST: TEST_HOST,
            CONF_PORT: 5501,
        }]
    }
    caplog.set_level(logging.ERROR)
    mock_pymodbus.connect.return_value = True
    mock_pymodbus.close.side_effect = ModbusException("close fail")
    assert await async_setup_component(hass, DOMAIN, config) is True
    await hass.async_block_till_done()
コード例 #13
0
ファイル: libmodbus-client.py プロジェクト: ibaranov-cp/jhu05
    def __execute(self, command, *args):
        ''' Run the supplied command against the currently
        instantiated client with the supplied arguments. This
        will make sure to correctly handle resulting errors.

        :param command: The command to execute against the context
        :param *args: The arguments for the given command
        :returns: The result of the operation unless -1 which throws
        '''
        result = command(self.client, *args)
        if result == -1:
            message = LIB.modbus_strerror(compiler.errno)
            raise ModbusException(compiler.string(message))
        return result
コード例 #14
0
async def test_pymodbus_connect_fail(hass, caplog, mock_pymodbus):
    """Run test for failing pymodbus constructor."""
    config = {
        DOMAIN: [{
            CONF_NAME: TEST_MODBUS_NAME,
            CONF_TYPE: TCP,
            CONF_HOST: TEST_MODBUS_HOST,
            CONF_PORT: TEST_PORT_TCP,
        }]
    }
    caplog.set_level(logging.WARNING)
    ExceptionMessage = "test connect exception"
    mock_pymodbus.connect.side_effect = ModbusException(ExceptionMessage)
    assert await async_setup_component(hass, DOMAIN, config) is False
    assert ExceptionMessage in caplog.text
コード例 #15
0
async def test_pymodbus_constructor_fail(hass, caplog):
    """Run test for failing pymodbus constructor."""
    config = {
        DOMAIN: [{
            CONF_TYPE: "tcp",
            CONF_HOST: "modbusTestHost",
            CONF_PORT: 5501,
        }]
    }
    with mock.patch("homeassistant.components.modbus.modbus.ModbusTcpClient"
                    ) as mock_pb:
        caplog.set_level(logging.ERROR)
        mock_pb.side_effect = ModbusException("test no class")
        assert await async_setup_component(hass, DOMAIN, config) is True
        await hass.async_block_till_done()
        assert len(caplog.records) == 1
        assert caplog.records[0].levelname == "ERROR"
        assert mock_pb.called
コード例 #16
0
ファイル: test_init.py プロジェクト: home-ha/home-assistant
async def test_pymodbus_constructor_fail(hass, caplog):
    """Run test for failing pymodbus constructor."""
    config = {
        DOMAIN: [{
            CONF_NAME: TEST_MODBUS_NAME,
            CONF_TYPE: TCP,
            CONF_HOST: TEST_MODBUS_HOST,
            CONF_PORT: TEST_PORT_TCP,
        }]
    }
    with mock.patch("homeassistant.components.modbus.modbus.ModbusTcpClient",
                    autospec=True) as mock_pb:
        caplog.set_level(logging.ERROR)
        mock_pb.side_effect = ModbusException("test no class")
        assert await async_setup_component(hass, DOMAIN, config) is False
        await hass.async_block_till_done()
        message = f"Pymodbus: {TEST_MODBUS_NAME}: Modbus Error: test"
        assert caplog.messages[0].startswith(message)
        assert caplog.records[0].levelname == "ERROR"
        assert mock_pb.called
コード例 #17
0
async def test_pb_service_write_coil(hass, caplog, mock_modbus):
    """Run test for service write_coil."""

    # Pymodbus write single, response OK.
    data = {
        ATTR_HUB: TEST_MODBUS_NAME,
        ATTR_UNIT: 17,
        ATTR_ADDRESS: 16,
        ATTR_STATE: False,
    }
    await hass.services.async_call(DOMAIN,
                                   SERVICE_WRITE_COIL,
                                   data,
                                   blocking=True)
    assert mock_modbus.write_coil.called
    assert mock_modbus.write_coil.call_args[0] == (
        data[ATTR_ADDRESS],
        data[ATTR_STATE],
    )
    mock_modbus.reset_mock()

    # Pymodbus write single, response error or exception
    caplog.set_level(logging.DEBUG)
    mock_modbus.write_coil.return_value = ExceptionResponse(0x06)
    await hass.services.async_call(DOMAIN,
                                   SERVICE_WRITE_COIL,
                                   data,
                                   blocking=True)
    assert mock_modbus.write_coil.called
    assert caplog.messages[-1].startswith("Pymodbus:")
    mock_modbus.reset_mock()

    mock_modbus.write_coil.return_value = IllegalFunctionRequest(0x06)
    await hass.services.async_call(DOMAIN,
                                   SERVICE_WRITE_COIL,
                                   data,
                                   blocking=True)
    assert mock_modbus.write_coil.called
    assert caplog.messages[-1].startswith("Pymodbus:")
    mock_modbus.reset_mock()

    mock_modbus.write_coil.side_effect = ModbusException("fail write_")
    await hass.services.async_call(DOMAIN,
                                   SERVICE_WRITE_COIL,
                                   data,
                                   blocking=True)
    assert mock_modbus.write_coil.called
    assert caplog.messages[-1].startswith("Pymodbus:")
    mock_modbus.reset_mock()

    # Pymodbus write multiple, response OK.
    data[ATTR_STATE] = [True, False, True]
    await hass.services.async_call(DOMAIN,
                                   SERVICE_WRITE_COIL,
                                   data,
                                   blocking=True)
    assert mock_modbus.write_coils.called
    assert mock_modbus.write_coils.call_args[0] == (
        data[ATTR_ADDRESS],
        data[ATTR_STATE],
    )
    mock_modbus.reset_mock()

    # Pymodbus write multiple, response error or exception
    mock_modbus.write_coils.return_value = ExceptionResponse(0x06)
    await hass.services.async_call(DOMAIN,
                                   SERVICE_WRITE_COIL,
                                   data,
                                   blocking=True)
    assert mock_modbus.write_coils.called
    assert caplog.messages[-1].startswith("Pymodbus:")
    mock_modbus.reset_mock()

    mock_modbus.write_coils.return_value = IllegalFunctionRequest(0x06)
    await hass.services.async_call(DOMAIN,
                                   SERVICE_WRITE_COIL,
                                   data,
                                   blocking=True)
    assert mock_modbus.write_coils.called
    assert caplog.messages[-1].startswith("Pymodbus:")
    mock_modbus.reset_mock()

    mock_modbus.write_coils.side_effect = ModbusException("fail write_")
    await hass.services.async_call(DOMAIN,
                                   SERVICE_WRITE_COIL,
                                   data,
                                   blocking=True)
    assert mock_modbus.write_coils.called
    assert caplog.messages[-1].startswith("Pymodbus:")
    mock_modbus.reset_mock()
コード例 #18
0
        await hass.async_block_till_done()
    now = now + timedelta(seconds=DEFAULT_SCAN_INTERVAL + 60)
    with mock.patch("homeassistant.helpers.event.dt_util.utcnow",
                    return_value=now):
        async_fire_time_changed(hass, now)
        await hass.async_block_till_done()


@pytest.mark.parametrize(
    "do_return,do_exception,do_expect",
    [
        [ReadResult([7]), None, "7"],
        [IllegalFunctionRequest(0x99), None, STATE_UNAVAILABLE],
        [ExceptionResponse(0x99), None, STATE_UNAVAILABLE],
        [ReadResult([7]),
         ModbusException("fail read_"), STATE_UNAVAILABLE],
    ],
)
@pytest.mark.parametrize(
    "do_type",
    [CALL_TYPE_REGISTER_HOLDING, CALL_TYPE_REGISTER_INPUT],
)
async def test_pb_read_value(hass, caplog, do_type, do_return, do_exception,
                             do_expect, mock_pymodbus):
    """Run test for different read."""

    # the purpose of this test is to test the special
    # return values from pymodbus:
    #     ExceptionResponse, IllegalResponse
    # and exceptions.
    # We "hijiack" binary_sensor and sensor in order
コード例 #19
0
def _raise_exception(_):
    raise ModbusException('something')
コード例 #20
0
            [0xFE],
            STATE_ON,
        ),
        (
            [0xFF],
            STATE_ON,
        ),
        (
            [0x01],
            STATE_OFF,
        ),
        (
            [0x20],
            STATE_ON,
        ),
        (ModbusException("Modbus Exception"), STATE_UNAVAILABLE),
        (ConnectionException("Modbus Exception"), STATE_UNAVAILABLE),
    ],
)
async def test_register_switch(hass, regs, expected):
    """Run test for given config."""
    switch_name = "modbus_test_switch"
    state = await base_test(
        hass,
        {
            CONF_NAME: switch_name,
            CONF_INPUT_TYPE: CALL_TYPE_REGISTER_INPUT,
            CONF_ADDRESS: 1234,
            CONF_SLAVE: 1,
            CONF_COMMAND_BIT_NUMBER: 5,
        },
コード例 #21
0
    "do_return",
    [
        {
            VALUE: ReadResult([0x0001]),
            DATA: ""
        },
        {
            VALUE: ExceptionResponse(0x06),
            DATA: "Pymodbus:"
        },
        {
            VALUE: IllegalFunctionRequest(0x06),
            DATA: "Pymodbus:"
        },
        {
            VALUE: ModbusException("fail write_"),
            DATA: "Pymodbus:"
        },
    ],
)
async def test_pb_service_write(hass, do_write, do_return, caplog,
                                mock_modbus_with_pymodbus):
    """Run test for service write_register."""

    func_name = {
        CALL_TYPE_WRITE_COIL: mock_modbus_with_pymodbus.write_coil,
        CALL_TYPE_WRITE_COILS: mock_modbus_with_pymodbus.write_coils,
        CALL_TYPE_WRITE_REGISTER: mock_modbus_with_pymodbus.write_register,
        CALL_TYPE_WRITE_REGISTERS: mock_modbus_with_pymodbus.write_registers,
    }
コード例 #22
0
ファイル: test_init.py プロジェクト: tpaulus/core
    with mock.patch("homeassistant.helpers.event.dt_util.utcnow", return_value=now):
        assert await async_setup_component(hass, DOMAIN, config) is True
        await hass.async_block_till_done()
    now = now + timedelta(seconds=DEFAULT_SCAN_INTERVAL + 60)
    with mock.patch("homeassistant.helpers.event.dt_util.utcnow", return_value=now):
        async_fire_time_changed(hass, now)
        await hass.async_block_till_done()


@pytest.mark.parametrize(
    "do_return,do_exception,do_expect",
    [
        [ReadResult([7]), None, "7"],
        [IllegalFunctionRequest(0x99), None, STATE_UNAVAILABLE],
        [ExceptionResponse(0x99), None, STATE_UNAVAILABLE],
        [ReadResult([7]), ModbusException("fail read_"), STATE_UNAVAILABLE],
    ],
)
@pytest.mark.parametrize(
    "do_type",
    [CALL_TYPE_REGISTER_HOLDING, CALL_TYPE_REGISTER_INPUT],
)
async def test_pb_read_value(
    hass, caplog, do_type, do_return, do_exception, do_expect, mock_pymodbus
):
    """Run test for different read."""

    # the purpose of this test is to test the special
    # return values from pymodbus:
    #     ExceptionResponse, IllegalResponse
    # and exceptions.
コード例 #23
0
        },
        {
            DATA: ATTR_STATE,
            VALUE: [True, False, True],
            SERVICE: SERVICE_WRITE_COIL,
            FUNC: CALL_TYPE_WRITE_COILS,
        },
    ],
)
@pytest.mark.parametrize(
    "do_return",
    [
        {VALUE: ReadResult([0x0001]), DATA: ""},
        {VALUE: ExceptionResponse(0x06), DATA: "Pymodbus:"},
        {VALUE: IllegalFunctionRequest(0x06), DATA: "Pymodbus:"},
        {VALUE: ModbusException("fail write_"), DATA: "Pymodbus:"},
    ],
)
async def test_pb_service_write(
    hass, do_write, do_return, caplog, mock_modbus_with_pymodbus
):
    """Run test for service write_register."""

    func_name = {
        CALL_TYPE_WRITE_COIL: mock_modbus_with_pymodbus.write_coil,
        CALL_TYPE_WRITE_COILS: mock_modbus_with_pymodbus.write_coils,
        CALL_TYPE_WRITE_REGISTER: mock_modbus_with_pymodbus.write_register,
        CALL_TYPE_WRITE_REGISTERS: mock_modbus_with_pymodbus.write_registers,
    }

    data = {
コード例 #24
0
async def test_switch_service_turn(hass, caplog, mock_pymodbus):
    """Run test for service turn_on/turn_off."""

    ENTITY_ID2 = f"{SWITCH_DOMAIN}.{SWITCH_NAME}2"
    config = {
        MODBUS_DOMAIN: {
            CONF_TYPE: "tcp",
            CONF_HOST: "modbusTestHost",
            CONF_PORT: 5501,
            CONF_SWITCHES: [
                {
                    CONF_NAME: SWITCH_NAME,
                    CONF_ADDRESS: 17,
                    CONF_WRITE_TYPE: CALL_TYPE_REGISTER_HOLDING,
                },
                {
                    CONF_NAME: f"{SWITCH_NAME}2",
                    CONF_ADDRESS: 17,
                    CONF_WRITE_TYPE: CALL_TYPE_REGISTER_HOLDING,
                    CONF_VERIFY: {},
                },
            ],
        },
    }
    assert await async_setup_component(hass, MODBUS_DOMAIN, config) is True
    await hass.async_block_till_done()
    assert MODBUS_DOMAIN in hass.config.components

    assert hass.states.get(ENTITY_ID).state == STATE_OFF
    await hass.services.async_call(
        "switch", "turn_on", service_data={"entity_id": ENTITY_ID}
    )
    await hass.async_block_till_done()
    assert hass.states.get(ENTITY_ID).state == STATE_ON
    await hass.services.async_call(
        "switch", "turn_off", service_data={"entity_id": ENTITY_ID}
    )
    await hass.async_block_till_done()
    assert hass.states.get(ENTITY_ID).state == STATE_OFF

    mock_pymodbus.read_holding_registers.return_value = ReadResult([0x01])
    assert hass.states.get(ENTITY_ID2).state == STATE_OFF
    await hass.services.async_call(
        "switch", "turn_on", service_data={"entity_id": ENTITY_ID2}
    )
    await hass.async_block_till_done()
    assert hass.states.get(ENTITY_ID2).state == STATE_ON
    mock_pymodbus.read_holding_registers.return_value = ReadResult([0x00])
    await hass.services.async_call(
        "switch", "turn_off", service_data={"entity_id": ENTITY_ID2}
    )
    await hass.async_block_till_done()
    assert hass.states.get(ENTITY_ID2).state == STATE_OFF

    mock_pymodbus.write_register.side_effect = ModbusException("fail write_")
    await hass.services.async_call(
        "switch", "turn_on", service_data={"entity_id": ENTITY_ID2}
    )
    await hass.async_block_till_done()
    assert hass.states.get(ENTITY_ID2).state == STATE_UNAVAILABLE
    mock_pymodbus.write_coil.side_effect = ModbusException("fail write_")
    await hass.services.async_call(
        "switch", "turn_off", service_data={"entity_id": ENTITY_ID}
    )
    await hass.async_block_till_done()
    assert hass.states.get(ENTITY_ID).state == STATE_UNAVAILABLE
コード例 #25
0
    def _read(self, address, count=1, **kwargs):
        """Perform the read, enforcing Defaults.Timeout around the entire transaction.  Returns the
        result bit(s)/register(s), or raises an Exception; probably a ModbusException or a
        PlcOffline for communications errors, but could be some other type of Exception.

        Use a supplied 'unit' ID, or the one specified/deduced at construction.

        """
        self.client.timeout = True

        if not self.client.connect():
            raise PlcOffline(
                "Modbus Read  of PLC %s/%6d failed: Offline; Connect failure" %
                (self.description, address))

        # Use address to deduce Holding/Input Register or Coil/Status.
        reader = None
        xformed = address
        if 400001 <= address <= 465536:
            reader = ReadHoldingRegistersRequest
            xformed -= 400001
        elif 300001 <= address <= 365536:
            reader = ReadInputRegistersRequest
            xformed -= 300001
        elif 100001 <= address <= 165536:
            reader = ReadDiscreteInputsRequest
            xformed -= 100001
        elif 40001 <= address <= 99999:
            reader = ReadHoldingRegistersRequest
            xformed -= 40001
        elif 30001 <= address <= 39999:
            reader = ReadInputRegistersRequest
            xformed -= 30001
        elif 10001 <= address <= 19999:
            reader = ReadDiscreteInputsRequest
            xformed -= 10001
        elif 1 <= address <= 9999:
            reader = ReadCoilsRequest
            xformed -= 1
        else:
            # Invalid address
            pass
        if not reader:
            raise ParameterException("Invalid Modbus address for read: %d" %
                                     (address))

        unit = kwargs.pop('unit', self.unit)
        request = reader(xformed, count, unit=unit, **kwargs)
        log.debug("%s/%6d-%6d transformed to %s", self.description, address,
                  address + count - 1, request)

        result = self.client.execute(request)
        if isinstance(result, ExceptionResponse):
            # The remote PLC returned a response indicating it encountered an
            # error processing the request.  Convert it to raise a ModbusException.
            raise ModbusException(str(result))
        assert isinstance(
            result,
            ModbusResponse), "Unexpected non-ModbusResponse: %r" % result

        # The result may contain .bits or .registers,  1 or more values
        values = result.bits if hasattr(result, 'bits') else result.registers
        return values if len(values) > 1 else values[0]
コード例 #26
0
async def test_light_service_turn(hass, caplog, mock_pymodbus):
    """Run test for service turn_on/turn_off."""

    config = {
        MODBUS_DOMAIN: {
            CONF_TYPE:
            TCP,
            CONF_HOST:
            TEST_MODBUS_HOST,
            CONF_PORT:
            TEST_PORT_TCP,
            CONF_LIGHTS: [
                {
                    CONF_NAME: TEST_ENTITY_NAME,
                    CONF_ADDRESS: 17,
                    CONF_WRITE_TYPE: CALL_TYPE_REGISTER_HOLDING,
                    CONF_SCAN_INTERVAL: 0,
                },
                {
                    CONF_NAME: f"{TEST_ENTITY_NAME}2",
                    CONF_ADDRESS: 18,
                    CONF_WRITE_TYPE: CALL_TYPE_REGISTER_HOLDING,
                    CONF_SCAN_INTERVAL: 0,
                    CONF_VERIFY: {},
                },
            ],
        },
    }
    assert await async_setup_component(hass, MODBUS_DOMAIN, config) is True
    await hass.async_block_till_done()
    assert MODBUS_DOMAIN in hass.config.components

    assert hass.states.get(ENTITY_ID).state == STATE_OFF
    await hass.services.async_call("light",
                                   "turn_on",
                                   service_data={"entity_id": ENTITY_ID})
    await hass.async_block_till_done()
    assert hass.states.get(ENTITY_ID).state == STATE_ON
    await hass.services.async_call("light",
                                   "turn_off",
                                   service_data={"entity_id": ENTITY_ID})
    await hass.async_block_till_done()
    assert hass.states.get(ENTITY_ID).state == STATE_OFF

    mock_pymodbus.read_holding_registers.return_value = ReadResult([0x01])
    assert hass.states.get(ENTITY_ID2).state == STATE_OFF
    await hass.services.async_call("light",
                                   "turn_on",
                                   service_data={"entity_id": ENTITY_ID2})
    await hass.async_block_till_done()
    assert hass.states.get(ENTITY_ID2).state == STATE_ON
    mock_pymodbus.read_holding_registers.return_value = ReadResult([0x00])
    await hass.services.async_call("light",
                                   "turn_off",
                                   service_data={"entity_id": ENTITY_ID2})
    await hass.async_block_till_done()
    assert hass.states.get(ENTITY_ID2).state == STATE_OFF

    mock_pymodbus.write_register.side_effect = ModbusException("fail write_")
    await hass.services.async_call("light",
                                   "turn_on",
                                   service_data={"entity_id": ENTITY_ID2})
    await hass.async_block_till_done()
    assert hass.states.get(ENTITY_ID2).state == STATE_UNAVAILABLE
    mock_pymodbus.write_coil.side_effect = ModbusException("fail write_")
    await hass.services.async_call("light",
                                   "turn_off",
                                   service_data={"entity_id": ENTITY_ID})
    await hass.async_block_till_done()
    assert hass.states.get(ENTITY_ID).state == STATE_UNAVAILABLE
コード例 #27
0
    def register_value(self, a_register_index, a_register_length,
                       a_slave_address):
        """
		Returns a given register value
		@a_register_length: 1 register is 16 bits (2 bytes = 1 word)
		"""
        assert self.is_connected(), 'register_value->device is not connected'
        assert isinstance(a_register_index,
                          int), 'register_value->Slave address is not an int'
        assert self.valid_slave_address(
            a_slave_address
        ), 'register_value->Slave address is not valid:' + str(a_slave_address)

        #self._logger.debug('register_value-> _substract_one_to_register_index:%s' % (self._substract_one_to_register_index))
        if self._substract_one_to_register_index:
            l_register_index = a_register_index - 1
            l_register_index_s_debug = str(a_register_index) + '-1'
        else:
            l_register_index = a_register_index
            l_register_index_s_debug = str(l_register_index)
        l_retries_count = 0
        while l_retries_count < self.MAX_MODBUS_REGISTER_RETRIES_COUNT:
            try:
                #Starting add, num of reg to read, slave unit.
                self._logger.debug(
                    'register_value-> index:{} length:{} unit:{} _substract_one_to_register_index:{}'
                    .format(l_register_index, a_register_length,
                            a_slave_address,
                            self._substract_one_to_register_index))
                l_result = self._modbus_client.read_holding_registers(
                    l_register_index, a_register_length,
                    unit=a_slave_address)  # Average current
                if l_result is not None:
                    if (hasattr(l_result, 'function_code')
                            and l_result.function_code < 0xFFFFFFFF):
                        self._logger.debug(
                            "register_value-> read register index:%s (%s) length:%s slave_address:%s"
                            % (l_register_index, l_register_index_s_debug,
                               a_register_length, a_slave_address))
                        #self._logger.debug(l_result)
                        #self._logger.debug("register_value->register 0 value:%s" % l_result.getRegister(1))
                        #self._logger.debug("register_value-> 0 type:%s" % type(l_result.getRegister(0)))
                        #self._logger.debug(l_result._str_())
                    else:
                        self._logger.error(
                            "register_value-> returned code is invalid: {}".
                            format(l_result))
                else:
                    l_msg = "register_value-> No register received, l_result is None"
                    self._logger.error(l_msg)
                    raise ModbusException(l_msg)

                if not hasattr(l_result, 'registers'):
                    l_msg = 'register_value-> read register has no registers attribute, slave:{} reading register:{} length:{}'.format(
                        a_slave_address, l_register_index, a_register_length)
                    self._logger.error(l_msg)
                    raise ModbusException(l_msg)

                return l_result
            except KeyboardInterrupt:
                self._logger.exception(
                    "register_value-> Keyboard interruption")
            except ModbusException as l_e:
                l_retries_count += 1
                if l_retries_count >= self.MAX_MODBUS_REGISTER_RETRIES_COUNT:
                    self._logger.error(
                        'register_value-> error with ModbusException not retrying but raising'
                    )
                    raise l_e
                else:
                    self._logger.error(
                        'register_value-> error with ModbusException retrying {}'
                        .format(l_retries_count))
                    self.disconnect
                    time.sleep(0.2)
                    self.connect
            except Exception as l_e:
                self._logger.exception(
                    "register_value-> Exception occured, msg:%s" % l_e)
                raise l_e
コード例 #28
0
async def test_light_service_turn(opp, caplog, mock_pymodbus):
    """Run test for service turn_on/turn_off."""

    entity_id1 = f"{LIGHT_DOMAIN}.light1"
    entity_id2 = f"{LIGHT_DOMAIN}.light2"
    config = {
        MODBUS_DOMAIN: {
            CONF_TYPE:
            "tcp",
            CONF_HOST:
            "modbusTestHost",
            CONF_PORT:
            5501,
            CONF_LIGHTS: [
                {
                    CONF_NAME: "light1",
                    CONF_ADDRESS: 17,
                    CONF_WRITE_TYPE: CALL_TYPE_REGISTER_HOLDING,
                },
                {
                    CONF_NAME: "light2",
                    CONF_ADDRESS: 17,
                    CONF_WRITE_TYPE: CALL_TYPE_REGISTER_HOLDING,
                    CONF_VERIFY: {},
                },
            ],
        },
    }
    assert await async_setup_component(opp, MODBUS_DOMAIN, config) is True
    await opp.async_block_till_done()
    assert MODBUS_DOMAIN in opp.config.components

    assert opp.states.get(entity_id1).state == STATE_OFF
    await opp.services.async_call("light",
                                  "turn_on",
                                  service_data={"entity_id": entity_id1})
    await opp.async_block_till_done()
    assert opp.states.get(entity_id1).state == STATE_ON
    await opp.services.async_call("light",
                                  "turn_off",
                                  service_data={"entity_id": entity_id1})
    await opp.async_block_till_done()
    assert opp.states.get(entity_id1).state == STATE_OFF

    mock_pymodbus.read_holding_registers.return_value = ReadResult([0x01])
    assert opp.states.get(entity_id2).state == STATE_OFF
    await opp.services.async_call("light",
                                  "turn_on",
                                  service_data={"entity_id": entity_id2})
    await opp.async_block_till_done()
    assert opp.states.get(entity_id2).state == STATE_ON
    mock_pymodbus.read_holding_registers.return_value = ReadResult([0x00])
    await opp.services.async_call("light",
                                  "turn_off",
                                  service_data={"entity_id": entity_id2})
    await opp.async_block_till_done()
    assert opp.states.get(entity_id2).state == STATE_OFF

    mock_pymodbus.write_register.side_effect = ModbusException("fail write_")
    await opp.services.async_call("light",
                                  "turn_on",
                                  service_data={"entity_id": entity_id2})
    await opp.async_block_till_done()
    assert opp.states.get(entity_id2).state == STATE_UNAVAILABLE
    mock_pymodbus.write_coil.side_effect = ModbusException("fail write_")
    await opp.services.async_call("light",
                                  "turn_off",
                                  service_data={"entity_id": entity_id1})
    await opp.async_block_till_done()
    assert opp.states.get(entity_id1).state == STATE_UNAVAILABLE
コード例 #29
0
async def base_test(
    hass,
    config_device,
    device_name,
    entity_domain,
    array_name_discovery,
    array_name_old_config,
    register_words,
    expected,
    method_discovery=False,
    config_modbus=None,
    scan_interval=None,
    expect_init_to_fail=False,
    expect_setup_to_fail=False,
):
    """Run test on device for given config."""

    if config_modbus is None:
        config_modbus = {
            DOMAIN: {
                CONF_NAME: DEFAULT_HUB,
                CONF_TYPE: "tcp",
                CONF_HOST: "modbusTest",
                CONF_PORT: 5001,
            },
        }

    mock_sync = mock.MagicMock()
    with mock.patch(
            "homeassistant.components.modbus.modbus.ModbusTcpClient",
            autospec=True,
            return_value=mock_sync,
    ):

        # Setup inputs for the sensor
        if register_words is None:
            mock_sync.read_coils.side_effect = ModbusException(
                "fail read_coils")
            mock_sync.read_discrete_inputs.side_effect = ModbusException(
                "fail read_coils")
            mock_sync.read_input_registers.side_effect = ModbusException(
                "fail read_coils")
            mock_sync.read_holding_registers.side_effect = ModbusException(
                "fail read_coils")
        else:
            read_result = ReadResult(register_words)
            mock_sync.read_coils.return_value = read_result
            mock_sync.read_discrete_inputs.return_value = read_result
            mock_sync.read_input_registers.return_value = read_result
            mock_sync.read_holding_registers.return_value = read_result

        # mock timer and add old/new config
        now = dt_util.utcnow()
        with mock.patch("homeassistant.helpers.event.dt_util.utcnow",
                        return_value=now):
            if method_discovery and config_device is not None:
                # setup modbus which in turn does setup for the devices
                config_modbus[DOMAIN].update(
                    {array_name_discovery: [{
                        **config_device
                    }]})
                config_device = None
            assert (await async_setup_component(hass, DOMAIN, config_modbus)
                    is not expect_setup_to_fail)
            await hass.async_block_till_done()

            # setup platform old style
            if config_device is not None:
                config_device = {
                    entity_domain: {
                        CONF_PLATFORM: DOMAIN,
                        array_name_old_config: [{
                            **config_device,
                        }],
                    }
                }
                if scan_interval is not None:
                    config_device[entity_domain][
                        CONF_SCAN_INTERVAL] = scan_interval
                assert await async_setup_component(hass, entity_domain,
                                                   config_device)
                await hass.async_block_till_done()

        assert (DOMAIN in hass.config.components) is not expect_setup_to_fail
        if config_device is not None:
            entity_id = f"{entity_domain}.{device_name}"
            device = hass.states.get(entity_id)

            if expect_init_to_fail:
                assert device is None
            elif device is None:
                pytest.fail("CONFIG failed, see output")

        # Trigger update call with time_changed event
        now = now + timedelta(seconds=scan_interval + 60)
        with mock.patch("homeassistant.helpers.event.dt_util.utcnow",
                        return_value=now):
            async_fire_time_changed(hass, now)
            await hass.async_block_till_done()

        # Check state
        entity_id = f"{entity_domain}.{device_name}"
        return hass.states.get(entity_id).state
コード例 #30
0
    "do_return",
    [
        {
            VALUE: ReadResult([0x0001]),
            DATA: ""
        },
        {
            VALUE: ExceptionResponse(0x06),
            DATA: "Pymodbus:"
        },
        {
            VALUE: IllegalFunctionRequest(0x06),
            DATA: "Pymodbus:"
        },
        {
            VALUE: ModbusException("fail write_"),
            DATA: "Pymodbus:"
        },
    ],
)
async def test_pb_service_write(hass, do_write, do_return, caplog,
                                mock_modbus_with_pymodbus):
    """Run test for service write_register."""

    func_name = {
        CALL_TYPE_WRITE_COIL: mock_modbus_with_pymodbus.write_coil,
        CALL_TYPE_WRITE_COILS: mock_modbus_with_pymodbus.write_coils,
        CALL_TYPE_WRITE_REGISTER: mock_modbus_with_pymodbus.write_register,
        CALL_TYPE_WRITE_REGISTERS: mock_modbus_with_pymodbus.write_registers,
    }