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
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()
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)
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)
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)
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)
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()
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
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)
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)
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()
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 )
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
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
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
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