Example #1
0
async def turn_off_handler(
    request: Request,
    ip_address: str,
    phone_id: str,
    device_id: str,
    device_password: str,
) -> HTTPResponse:
    """Use for handling requests to /switcher/turn_off.

    Args:
      request: ``sanic``'s request object.
      ip_address: the local ip address.
      phone_id: the extracted phone id.
      device_id: the extracted device id.
      device_password: the extracted device password.

    Raises:
      sanic.exceptions.ServerError: when encounterd any error.

    Returns:
      Json object represnting the request status.

      More information is available in the ``Usage`` section.

    Note:
      Accepts arguments as json body or query parameters.

    """
    try:
        async with SwitcherV2Api(
                get_running_loop(),
                ip_address,
                phone_id,
                device_id,
                device_password,
        ) as swapi:
            response = await swapi.control_device(COMMAND_OFF)

        if (response
                and response.msg_type == messages.ResponseMessageType.CONTROL):
            return json({consts.KEY_SUCCESSFUL: response.successful})
        return json({
            consts.KEY_SUCCESSFUL: False,
            consts.KEY_MESSAGE: "Failed turning off the device.",
        })
    except ExceptionSet as exc:
        raise ServerError("Failed turning off the device.", 500) from exc
Example #2
0
    async def _control_device(self, send_on: bool) -> None:
        """Turn the entity on or off."""
        response: SwitcherV2ControlResponseMSG = None
        async with SwitcherV2Api(
                self.hass.loop,
                self._device_data.ip_addr,
                self._device_data.phone_id,
                self._device_data.device_id,
                self._device_data.device_password,
        ) as swapi:
            response = await swapi.control_device(
                COMMAND_ON if send_on else COMMAND_OFF)

        if response and response.successful:
            self._self_initiated = True
            self._state = SWITCHER_STATE_ON if send_on else SWITCHER_STATE_OFF
            self.async_write_ha_state()
Example #3
0
async def test_api_set_auto_shutdown_success(
    event_loop: AbstractEventLoop,
    tcp_connection: CoroutineMock,
    api_stage_success_set_auto_off: List[bytes],
) -> None:
    """Test the SwitcherV2Api successful set_auto_shutdown."""
    async with SwitcherV2Api(
            event_loop,
            DUMMY_IP_ADDRESS,
            DUMMY_PHONE_ID,
            DUMMY_DEVICE_ID,
            DUMMY_DEVICE_PASSWORD,
    ) as swapi:
        reader = tcp_connection
        reader.read.side_effect = api_stage_success_set_auto_off
        response = await swapi.set_auto_shutdown(timedelta(hours=1))

        await assert_api_messege_base_type(response,
                                           ResponseMessageType.AUTO_OFF)
Example #4
0
async def test_api_disable_enable_schedule_success(
    event_loop: AbstractEventLoop,
    tcp_connection: CoroutineMock,
    api_stage_success_en_disable_schedule: List[bytes],
) -> None:
    """Test the SwitcherV2Api successful disable_enable_schedule."""
    async with SwitcherV2Api(
            event_loop,
            DUMMY_IP_ADDRESS,
            DUMMY_PHONE_ID,
            DUMMY_DEVICE_ID,
            DUMMY_DEVICE_PASSWORD,
    ) as swapi:
        reader = tcp_connection
        reader.read.side_effect = api_stage_success_en_disable_schedule
        response = await swapi.disable_enable_schedule("")

        await assert_api_messege_base_type(
            response, ResponseMessageType.DISABLE_ENABLE_SCHEDULE)
Example #5
0
async def test_api_set_device_name_success(
    event_loop: AbstractEventLoop,
    tcp_connection: CoroutineMock,
    api_stage_success_update_name: List[bytes],
) -> None:
    """Test the SwitcherV2Api successful set_device_name."""
    async with SwitcherV2Api(
            event_loop,
            DUMMY_IP_ADDRESS,
            DUMMY_PHONE_ID,
            DUMMY_DEVICE_ID,
            DUMMY_DEVICE_PASSWORD,
    ) as swapi:
        reader = tcp_connection
        reader.read.side_effect = api_stage_success_update_name
        response = await swapi.set_device_name("irrelevant")

        await assert_api_messege_base_type(response,
                                           ResponseMessageType.UPDATE_NAME)
Example #6
0
async def test_api_control_success(
    event_loop: AbstractEventLoop,
    tcp_connection: CoroutineMock,
    api_stage_success_control: List[bytes],
) -> None:
    """Test the SwitcherV2Api successful control."""
    async with SwitcherV2Api(
            event_loop,
            DUMMY_IP_ADDRESS,
            DUMMY_PHONE_ID,
            DUMMY_DEVICE_ID,
            DUMMY_DEVICE_PASSWORD,
    ) as swapi:
        reader = tcp_connection
        reader.read.side_effect = api_stage_success_control
        response = await swapi.control_device(COMMAND_ON)

        await assert_api_messege_base_type(response,
                                           ResponseMessageType.CONTROL)
Example #7
0
    async def _control_device(self, send_on: bool) -> None:
        """Turn the entity on or off."""
        from aioswitcher.api import SwitcherV2Api
        from aioswitcher.consts import (COMMAND_OFF, COMMAND_ON,
                                        STATE_OFF as SWITCHER_STATE_OFF,
                                        STATE_ON as SWITCHER_STATE_ON)

        response = None  # type: SwitcherV2ControlResponseMSG
        async with SwitcherV2Api(
                self.hass.loop, self._device_data.ip_addr,
                self._device_data.phone_id, self._device_data.device_id,
                self._device_data.device_password) as swapi:
            response = await swapi.control_device(
                COMMAND_ON if send_on else COMMAND_OFF)

        if response and response.successful:
            self._self_initiated = True
            self._state = \
                SWITCHER_STATE_ON if send_on else SWITCHER_STATE_OFF
            self.async_schedule_update_ha_state()
Example #8
0
async def test_api_login_fail(
    event_loop: AbstractEventLoop,
    tcp_connection: CoroutineMock,
    api_stage_failed_login: bytes,
) -> None:
    """Test the SwitcherV2Api failed login."""
    async with SwitcherV2Api(
            event_loop,
            DUMMY_IP_ADDRESS,
            DUMMY_PHONE_ID,
            DUMMY_DEVICE_ID,
            DUMMY_DEVICE_PASSWORD,
    ) as swapi:
        reader = tcp_connection
        reader.read.return_value = api_stage_failed_login

        with raises(DecodingError) as exc_info:
            await swapi.login()

        assert exc_info.type is DecodingError
Example #9
0
async def test_api_get_state_success(
        event_loop: AbstractEventLoop, tcp_connection: CoroutineMock,
        api_stage_success_get_state: List[bytes]) -> None:
    """Test the SwitcherV2Api successful get_state."""
    async with SwitcherV2Api(event_loop, DUMMY_IP_ADDRESS, DUMMY_PHONE_ID,
                             DUMMY_DEVICE_ID, DUMMY_DEVICE_PASSWORD) as swapi:
        reader = tcp_connection
        reader.read.side_effect = api_stage_success_get_state
        response = await swapi.get_state()

        assert response

        await wait([response.init_future])

        assert response.state == STATE_OFF
        assert response.time_left == '00:00:00'
        assert response.auto_off == '01:30:00'
        assert response.power == 0
        assert response.current == 0.0

        await assert_api_messege_base_type(response, ResponseMessageType.STATE)
Example #10
0
async def test_api_login_success(
    event_loop: AbstractEventLoop,
    tcp_connection: CoroutineMock,
    api_stage_success_login: bytes,
) -> None:
    """Test the SwitcherV2Api successful login."""
    async with SwitcherV2Api(
            event_loop,
            DUMMY_IP_ADDRESS,
            DUMMY_PHONE_ID,
            DUMMY_DEVICE_ID,
            DUMMY_DEVICE_PASSWORD,
    ) as swapi:
        reader = tcp_connection
        reader.read.return_value = api_stage_success_login
        response = await swapi.login()

        assert response
        assert response.session_id == "f050834e"

        await assert_api_messege_base_type(response, ResponseMessageType.LOGIN)
Example #11
0
async def test_api_get_state_fail(
    event_loop: AbstractEventLoop,
    tcp_connection: CoroutineMock,
    api_stage_fail_get_state: Tuple[bytes, str],
) -> None:
    """Test the SwitcherV2Api failed get_state."""
    async with SwitcherV2Api(
            event_loop,
            DUMMY_IP_ADDRESS,
            DUMMY_PHONE_ID,
            DUMMY_DEVICE_ID,
            DUMMY_DEVICE_PASSWORD,
    ) as swapi:
        reader = tcp_connection
        reader.read.side_effect = api_stage_fail_get_state
        response = await swapi.get_state()

        assert response

        await wait([response.init_future])

        assert response.init_future.exception()
Example #12
0
async def test_api_get_schedules_success(
    event_loop: AbstractEventLoop,
    tcp_connection: AsyncMock,
    api_stage_success_get_schedules: List[bytes],
) -> None:
    """Test the SwitcherV2Api successful get_schedules."""
    async with SwitcherV2Api(
        event_loop,
        DUMMY_IP_ADDRESS,
        DUMMY_PHONE_ID,
        DUMMY_DEVICE_ID,
        DUMMY_DEVICE_PASSWORD,
    ) as swapi:
        reader = tcp_connection
        reader.read.side_effect = api_stage_success_get_schedules
        response = await swapi.get_schedules()

        assert response
        assert response.found_schedules

        futures = []
        for schedule in response.get_schedules:
            futures.append(schedule.init_future)
        await wait(futures)

        schedule_data_list = []
        for fut in futures:
            schedule_data_list.append(fut.result().schedule_data)

        await assert_lists_equal(
            schedule_data_list,
            ["0001fc01e871a35cf87fa35c", "01010201e06aa35cf078a35c"],
        )

        await assert_api_messege_base_type(
            response, ResponseMessageType.GET_SCHEDULES
        )
Example #13
0
async def set_auto_shutdown_handler(
    request: Request,
    ip_address: str,
    phone_id: str,
    device_id: str,
    device_password: str,
) -> HTTPResponse:
    """Use for handling requests to /switcher/set_auto_shutdown.

    Args:
      request: ``sanic``'s request object.
      ip_address: the local ip address.
      phone_id: the extracted phone id.
      device_id: the extracted device id.
      device_password: the extracted device password.

    Raises:
      sanic.exceptions.InvalidUsage: when requested is not 59-180 minutes.
      sanic.exceptions.ServerError: when encounterd any error.

    Returns:
      Json object represnting the request status.

      More information is available in the ``Usage`` section.

    Note:
      Accepts arguments as json body or query parameters.

    """
    try:
        if (request.args and consts.PARAM_HOURS in request.args
                and consts.PARAM_MINUTES in request.args):
            hours = int(request.args[consts.PARAM_HOURS][0])
            minutes = int(request.args[consts.PARAM_MINUTES][0])
        elif (request.json and consts.PARAM_HOURS in request.json
              and consts.PARAM_MINUTES in request.json):
            hours = int(request.json[consts.PARAM_HOURS])
            minutes = int(request.json[consts.PARAM_MINUTES])
        else:
            raise InvalidUsage(
                "One of the arguments hours or minutes is missing.", 400)

        time_guard = (hours *
                      60 if hours > 0 else 0) + (minutes if minutes > 0 else 0)
        if time_guard < 59 or time_guard > 180:
            raise InvalidUsage(
                "Auto shutdown can be set between 1 and 3 hours.", 400)

        time_to_off_timedelta = timedelta(hours=hours, minutes=minutes)

        async with SwitcherV2Api(
                get_running_loop(),
                ip_address,
                phone_id,
                device_id,
                device_password,
        ) as swapi:
            response = await swapi.set_auto_shutdown(time_to_off_timedelta)

        if (response and response.msg_type
                == messages.ResponseMessageType.AUTO_OFF):
            return json({consts.KEY_SUCCESSFUL: response.successful})
        return json({
            consts.KEY_SUCCESSFUL:
            False,
            consts.KEY_MESSAGE:
            "Failed setting auto shutdown on device.",
        })
    except ExceptionSet as exc:
        raise ServerError("Failed setting auto shutdown on device.",
                          500) from exc
Example #14
0
async def get_state_handler(
    request: Request,
    ip_address: str,
    phone_id: str,
    device_id: str,
    device_password: str,
) -> HTTPResponse:
    """Use for handling requests to /switcher/get_state.

    Args:
      request: ``sanic``'s request object.
      ip_address: the local ip address.
      phone_id: the extracted phone id.
      device_id: the extracted device id.
      device_password: the extracted device password.

    Raises:
      sanic.exceptions.ServerError: when encounterd any error.

    Returns:
      Json object represnting the current state of the device.

      More information is available in the ``Usage`` section.

    Note:
      Accepts arguments as json body or query parameters.

    """
    try:
        async with SwitcherV2Api(
                get_running_loop(),
                ip_address,
                phone_id,
                device_id,
                device_password,
        ) as swapi:
            response = await swapi.get_state()

        if not response:
            raise ServiceUnavailable("Failed to get response from api.", 503)

        await response.init_future
        state_response = response.init_future.result()

        if (state_response and state_response.successful and
                state_response.msg_type == messages.ResponseMessageType.STATE):
            return json({
                consts.KEY_SUCCESSFUL: state_response.successful,
                consts.KEY_STATE: state_response.state,
                consts.KEY_TIME_LEFT: state_response.time_left,
                consts.KEY_TIME_ON: state_response.time_on,
                consts.KEY_AUTO_OFF: state_response.auto_off,
                consts.KEY_POWER_CONSUMPTION: state_response.power,
                consts.KEY_ELECTRIC_CURRENT: state_response.current,
            })
        return json({
            consts.KEY_SUCCESSFUL:
            False,
            consts.KEY_MESSAGE:
            "Failed retrieving the device's state.",
        })
    except ExceptionSet as exc:
        raise ServerError("Failed to get the device state.", 500) from exc
Example #15
0
async def get_schedules_handler(
    request: Request,
    ip_address: str,
    phone_id: str,
    device_id: str,
    device_password: str,
) -> HTTPResponse:
    """Use for handling requests to /switcher/get_schedules.

    Args:
      request: ``sanic``'s request object.
      ip_address: the local ip address.
      phone_id: the extracted phone id.
      device_id: the extracted device id.
      device_password: the extracted device password.

    Raises:
      sanic.exceptions.ServerError: when encounterd any error.

    Returns:
      Json object represnting the configured schedules on the device.

      More information is available in the ``Usage`` section.

    Note:
      Accepts arguments as json body or query parameters.

    """
    try:
        async with SwitcherV2Api(
                get_running_loop(),
                ip_address,
                phone_id,
                device_id,
                device_password,
        ) as swapi:
            response = await swapi.get_schedules()

        if response and response.successful:
            schedules_list = []  # type: List[Dict]
            if response.found_schedules:
                for schedule in response.get_schedules:
                    await schedule.init_future
                    schedule_obj = schedule.init_future.result()
                    next_run = await calc_next_run_for_schedule(
                        get_running_loop(), schedule_obj)
                    schedules_list.append({
                        consts.KEY_SCHEDULE_ID:
                        schedule_obj.schedule_id,
                        consts.KEY_ENABLED:
                        schedule_obj.enabled,
                        consts.KEY_RECURRING:
                        schedule_obj.recurring,
                        consts.KEY_DAYS:
                        schedule_obj.days,
                        consts.KEY_START_TIME:
                        schedule_obj.start_time,
                        consts.KEY_END_TIME:
                        schedule_obj.end_time,
                        consts.KEY_DURATION:
                        schedule_obj.duration,
                        consts.KEY_SCHEDULE_DATA:
                        schedule_obj.schedule_data,  # noqa: E501
                        consts.KEY_NEXT_RUN:
                        next_run,
                    })
            return json({
                consts.KEY_SUCCESSFUL: response.successful,
                consts.KEY_FOUND_SCHEDULES: response.found_schedules,
                consts.KEY_SCHEDULES: schedules_list,
            })
        return json({
            consts.KEY_SUCCESSFUL: False,
            consts.KEY_MESSAGE: "Failed getting the device schedules.",
        })
    except ExceptionSet as exc:
        raise ServerError("Failed to get the device schedules.", 500) from exc
Example #16
0
async def enable_schedule_handler(
    request: Request,
    ip_address: str,
    phone_id: str,
    device_id: str,
    device_password: str,
) -> HTTPResponse:
    """Use for handling requests to /switcher/enable_schedule.

    Args:
      request: ``sanic``'s request object.
      ip_address: the local ip address.
      phone_id: the extracted phone id.
      device_id: the extracted device id.
      device_password: the extracted device password.

    Raises:
      sanic.exceptions.InvalidUsage: when encounterd faulty data.
      sanic.exceptions.ServerError: when encounterd any error.

    Returns:
      Json object represnting the request status.

      More information is available in the ``Usage`` section.

    Note:
      Accepts arguments as json body or query parameters.

    """
    try:
        if request.args and consts.PARAM_SCHEDULE_DATA in request.args:
            schedule_data = request.args[consts.PARAM_SCHEDULE_DATA][0]
        elif request.json and consts.PARAM_SCHEDULE_DATA in request.json:
            schedule_data = str(request.json[consts.PARAM_SCHEDULE_DATA])
        else:
            raise InvalidUsage("Argument schedule_data is missing.", 400)
        if len(schedule_data) != 24:
            raise InvalidUsage("Argument schedule_data is length is no 24.",
                               400)
        updated_schedule_data = (schedule_data[0:2] + ENABLE_SCHEDULE +
                                 schedule_data[4:])

        async with SwitcherV2Api(
                get_running_loop(),
                ip_address,
                phone_id,
                device_id,
                device_password,
        ) as swapi:
            response = await swapi.disable_enable_schedule(
                updated_schedule_data)

        if (response and response.msg_type
                == messages.ResponseMessageType.DISABLE_ENABLE_SCHEDULE):
            return json({consts.KEY_SUCCESSFUL: response.successful})
        return json({
            consts.KEY_SUCCESSFUL: False,
            consts.KEY_MESSAGE: "Failed enabling the schedule.",
        })
    except ExceptionSet as exc:
        raise ServerError("Failed enabling the schedule.", 500) from exc