def VMB4RYNO_module_info_exchange(module_address):
    return (VelbusFrame(
        address=module_address,
        message=ModuleTypeRequest(),
    ).to_bytes(),
            VelbusFrame(
                address=module_address,
                message=ModuleType(module_info=VMB4RYNO_mi(), ),
            ).to_bytes())
 def velbus_query(self,
                  question: VelbusFrame,
                  response_type: type,
                  response_address: int = None,
                  timeout: int = 2,
                  additional_check=(lambda vbm: True)):
     assert question == VelbusFrame(address=1, message=ModuleTypeRequest())
     return make_awaitable(
         VelbusFrame(address=1, message=ModuleType(module_info=VMB4RYNO_mi()))
     )
async def test_reply(mock_velbus, module_address):
    mock_velbus.set_expected_conversation([
        (VelbusFrame(
            address=module_address,
            message=ModuleTypeRequest(),
        ).to_bytes(),
         VelbusFrame(
             address=module_address,
             message=ModuleType(module_info=VMB4RYNO(), ),
         ).to_bytes())
    ])
    bus = VelbusProtocol(client_id="INTERNAL")
    await bus.velbus_query(
        VelbusFrame(
            address=module_address,
            message=ModuleTypeRequest(),
        ),
        ModuleType,
    )
def test_decode():
    b = b'\x0f\xfb\x01\x40\xb5\x04'
    a = VelbusFrame.from_bytes(b)
    assert a.to_bytes() == b

    assert a == VelbusFrame(address=1, message=ModuleTypeRequest())

    assert json.loads(json.dumps(a.message.to_json_able())) == {
        'type': 'ModuleTypeRequest',
        'properties': {}
    }
def test_decode_rtr():
    b = b'\x0f\xfb\x00\x40\xb6\x04'
    a = VelbusFrame.from_bytes(b)
    assert a.message == ModuleTypeRequest()
    assert a.to_bytes() == b

    assert json.loads(json.dumps(a.to_json_able())) == {
        'address': 0,
        'message': {
            'type': 'ModuleTypeRequest',
            'properties': {},
        }
    }
async def test_no_reply(mock_velbus):
    mock_velbus.set_expected_conversation([
        (VelbusFrame(
            address=0x01,
            message=ModuleTypeRequest(),
        ).to_bytes(),
         VelbusFrame(
             address=0x01,
             message=ModuleType(module_info=VMB4RYNO(), ),
         ).to_bytes()),
    ])
    bus = VelbusProtocol(client_id="INTERNAL")

    with pytest.raises(TimeoutError):
        await bus.velbus_query(
            VelbusFrame(
                address=0x02,
                message=ModuleTypeRequest(),
            ),
            ModuleType,
            timeout=0.01,
        )
async def test_VMB2BL_instantiation(generate_sanic_request, module_address,
                                    mock_velbus):
    mock_velbus.set_expected_conversation([
        (VelbusFrame(
            address=module_address,
            message=ModuleTypeRequest(),
        ).to_bytes(),
         VelbusFrame(
             address=module_address,
             message=ModuleType(module_info=VMB2BL_mi(), ),
         ).to_bytes()),
    ])

    req = generate_sanic_request()
    resp = await module_req(req, f'{module_address:02x}', '/type')
    mock_velbus.assert_conversation_happened_exactly()

    assert 200 == resp.status
    assert f'VMB2BL at 0x{module_address:02x}\r\n' == resp.body.decode('utf-8')
async def test_get_module_timeout(generate_sanic_request):
    req = generate_sanic_request(path='/modules/aA/')
    give_request_ip(req)

    with patch('velbus.VelbusProtocol.VelbusHttpProtocol.process_message', new_callable=CoroMock) as velbus_pm:
        start_time = datetime.datetime.now()
        with pytest.raises(CachedTimeoutError):
            _ = await HttpApi.module_req(req, 'aA', '')
        duration = (datetime.datetime.now() - start_time).total_seconds()
        assert (2 * .9 < duration < 2 * 1.1)  # give 10% slack

        velbus_pm.assert_called_with(VelbusFrame(
            address=0xaa,
            message=ModuleTypeRequest(),
        ))

        start_time = datetime.datetime.now()
        with pytest.raises(CachedTimeoutError):
            _ = await HttpApi.module_req(req, 'Aa', '')
        duration = (datetime.datetime.now() - start_time).total_seconds()
        assert (duration < .1)  # Should return immediately
async def test_VMB2BL_status_position_estimation(generate_sanic_request,
                                                 mock_velbus):
    mock_velbus.set_expected_conversation([
        (VelbusFrame(
            address=0x11,
            message=ModuleTypeRequest(),
        ).to_bytes(),
         VelbusFrame(
             address=0x11,
             message=ModuleType(module_info=VMB2BL_mi(), ),
         ).to_bytes()),
        (VelbusFrame(address=0x11,
                     message=ModuleStatusRequest(channel=1)).to_bytes(),
         VelbusFrame(
             address=0x11,
             message=BlindStatusV1(
                 channel=BlindNumber(1),
                 blind_status=BlindStatusV1.BlindStatus.Off,
             ),
         ).to_bytes()),
    ])

    with freeze_time() as frozen_datetime:
        req = generate_sanic_request()
        resp = await module_req(req, '11', '/1/position')

        mock_velbus.assert_conversation_happened_exactly()

        assert 200 == resp.status
        assert '50' == resp.body.decode('utf-8')

        message(
            VelbusFrame(
                address=0x11,
                message=BlindStatusV1(
                    channel=BlindNumber(1),
                    blind_status=BlindStatusV1.BlindStatus.Blind1Down,
                ),
            ))

        frozen_datetime.tick(delta=datetime.timedelta(seconds=15))

        message(
            VelbusFrame(
                address=0x11,
                message=BlindStatusV1(
                    channel=BlindNumber(1),
                    blind_status=BlindStatusV1.BlindStatus.Off,
                ),
            ))

        req = generate_sanic_request()
        resp = await module_req(req, '11', '/1/position')
        assert 200 == resp.status
        assert '100' == resp.body.decode('utf-8')

        message(
            VelbusFrame(
                address=0x11,
                message=BlindStatusV1(
                    channel=BlindNumber(1),
                    blind_status=BlindStatusV1.BlindStatus.Blind1Up,
                ),
            ))

        frozen_datetime.tick(delta=datetime.timedelta(seconds=3))

        message(
            VelbusFrame(
                address=0x11,
                message=BlindStatusV1(
                    channel=BlindNumber(1),
                    blind_status=BlindStatusV1.BlindStatus.Off,
                ),
            ))

        req = generate_sanic_request()
        resp = await module_req(req, '11', '/1/position')
        assert 200 == resp.status
        assert 80. == float(resp.body.decode('utf-8'))
def test_decode_wrong_rtr():
    b = b'\x0f\xfb\x01\x00\xf5\x04'
    a = VelbusFrame.from_bytes(b)
    assert a.to_bytes() == b

    assert a.message != ModuleTypeRequest()