def async_setup_platform(hass, config, async_add_devices, discovery_info=None): """Set up Hook by getting the access token and list of actions.""" username = config.get(CONF_USERNAME) password = config.get(CONF_PASSWORD) websession = async_get_clientsession(hass) response = None try: with async_timeout.timeout(TIMEOUT, loop=hass.loop): response = yield from websession.post( '{}{}'.format(HOOK_ENDPOINT, 'user/login'), data={ 'username': username, 'password': password}) data = yield from response.json() except (asyncio.TimeoutError, aiohttp.errors.ClientError, aiohttp.errors.ClientDisconnectedError) as error: _LOGGER.error("Failed authentication API call: %s", error) return False finally: if response is not None: yield from response.release() try: token = data['data']['token'] except KeyError: _LOGGER.error("No token. Check username and password") return False response = None try: with async_timeout.timeout(TIMEOUT, loop=hass.loop): response = yield from websession.get( '{}{}'.format(HOOK_ENDPOINT, 'device'), params={"token": data['data']['token']}) data = yield from response.json() except (asyncio.TimeoutError, aiohttp.errors.ClientError, aiohttp.errors.ClientDisconnectedError) as error: _LOGGER.error("Failed getting devices: %s", error) return False finally: if response is not None: yield from response.release() yield from async_add_devices( HookSmartHome( hass, token, d['device_id'], d['device_name']) for lst in data['data'] for d in lst)
async def test_events(docker, testing_images, event_loop): subscriber = docker.events.subscribe() # Do some stuffs to generate events. config = {"Cmd": ["/bin/ash"], "Image": "alpine:latest"} container = await docker.containers.create_or_replace( config=config, name="aiodocker-testing-temp" ) await container.start() await container.delete(force=True) events_occurred = [] while True: try: with timeout(0.2): event = await subscriber.get() if event["Actor"]["ID"] == container._id: events_occurred.append(event["Action"]) except asyncio.TimeoutError: # no more events break except asyncio.CancelledError: break assert events_occurred == ["create", "start", "kill", "die", "destroy"] await docker.events.stop()
async def async_service_handler(service): """Execute a shell command service.""" payload = None if template_payload: payload = bytes( template_payload.async_render(variables=service.data), 'utf-8') try: with async_timeout.timeout(timeout, loop=hass.loop): request = await getattr(websession, method)( template_url.async_render(variables=service.data), data=payload, auth=auth, headers=headers ) if request.status < 400: _LOGGER.info("Success call %s.", request.url) else: _LOGGER.warning( "Error %d on call %s.", request.status, request.url) except asyncio.TimeoutError: _LOGGER.warning("Timeout call %s.", request.url) except aiohttp.ClientError: _LOGGER.error("Client error %s.", request.url)
async def websocket_subscription(hass, connection, msg): """Handle request for account info.""" cloud = hass.data[DOMAIN] with async_timeout.timeout(REQUEST_TIMEOUT, loop=hass.loop): response = await cloud.fetch_subscription_info() if response.status != 200: connection.send_message(websocket_api.error_message( msg['id'], 'request_failed', 'Failed to request subscription')) data = await response.json() # Check if a user is subscribed but local info is outdated # In that case, let's refresh and reconnect if data.get('provider') and cloud.iot.state != STATE_CONNECTED: _LOGGER.debug( "Found disconnected account with valid subscriotion, connecting") await hass.async_add_executor_job( auth_api.renew_access_token, cloud) # Cancel reconnect in progress if cloud.iot.state != STATE_DISCONNECTED: await cloud.iot.disconnect() hass.async_create_task(cloud.iot.connect()) connection.send_message(websocket_api.result_message(msg['id'], data))
async def async_start(self) -> None: """Finalize startup from inside the event loop. This method is a coroutine. """ _LOGGER.info("Starting Home Assistant") self.state = CoreState.starting setattr(self.loop, '_thread_ident', threading.get_ident()) self.bus.async_fire(EVENT_HOMEASSISTANT_START) try: # Only block for EVENT_HOMEASSISTANT_START listener self.async_stop_track_tasks() with timeout(TIMEOUT_EVENT_START): await self.async_block_till_done() except asyncio.TimeoutError: _LOGGER.warning( 'Something is blocking Home Assistant from wrapping up the ' 'start up phase. We\'re going to continue anyway. Please ' 'report the following info at http://bit.ly/2ogP58T : %s', ', '.join(self.config.components)) # Allow automations to set up the start triggers before changing state await asyncio.sleep(0) if self.state != CoreState.starting: _LOGGER.warning( 'Home Assistant startup has been interrupted. ' 'Its state may be inconsistent.') return self.state = CoreState.running _async_create_timer(self)
async def wait_for_groups(hass, groups): """Wait until all groups are present, or timeout.""" # pylint: disable=protected-access def _test_groups(groups): """Return whether all groups exist now.""" for group in groups: coordinator = group[0] # Test that coordinator is coordinating current_group = coordinator._sonos_group if coordinator != current_group[0]: return False # Test that slaves match if set(group[1:]) != set(current_group[1:]): return False return True try: with async_timeout.timeout(5): while not _test_groups(groups): await hass.data[DATA_SONOS].topology_condition.wait() except asyncio.TimeoutError: _LOGGER.warning("Timeout waiting for target groups %s", groups) for entity in hass.data[DATA_SONOS].entities: entity.soco._zgs_cache.clear()
async def async_aiohttp_proxy_web(hass, request, web_coro, buffer_size=102400, timeout=10): """Stream websession request to aiohttp web response.""" try: with async_timeout.timeout(timeout, loop=hass.loop): req = await web_coro except asyncio.CancelledError: # The user cancelled the request return except asyncio.TimeoutError as err: # Timeout trying to start the web request raise HTTPGatewayTimeout() from err except aiohttp.ClientError as err: # Something went wrong with the connection raise HTTPBadGateway() from err try: return await async_aiohttp_proxy_stream( hass, request, req.content, req.headers.get(CONTENT_TYPE) ) finally: req.close()
def async_get_tts_audio(self, message): """Load TTS from voicerss.""" websession = async_get_clientsession(self.hass) form_data = self.form_data.copy() form_data['src'] = message request = None try: with async_timeout.timeout(10, loop=self.hass.loop): request = yield from websession.post( VOICERSS_API_URL, data=form_data ) if request.status != 200: _LOGGER.error("Error %d on load url %s.", request.status, request.url) return (None, None) data = yield from request.read() if data in ERROR_MSG: _LOGGER.error( "Error receive %s from voicerss.", str(data, 'utf-8')) return (None, None) except (asyncio.TimeoutError, aiohttp.errors.ClientError): _LOGGER.error("Timeout for voicerss api.") return (None, None) finally: if request is not None: yield from request.release() return (self.extension, data)
def _call_web_gateway(self, resource, use_get=True): """Call web gateway for data.""" response = None session = None url = self._build_url(resource) try: _LOGGER.debug("Attempting to retrieve SPC data from %s", url) session = aiohttp.ClientSession() with async_timeout.timeout(10, loop=self._hass.loop): action = session.get if use_get else session.put response = yield from action(url) if response.status != 200: _LOGGER.error( "SPC Web Gateway returned http status %d, response %s", response.status, (yield from response.text())) return False result = yield from response.json() except asyncio.TimeoutError: _LOGGER.error("Timeout getting SPC data from %s", url) return False except aiohttp.ClientError: _LOGGER.exception("Error getting SPC data from %s", url) return False finally: if session: yield from session.close() if response: yield from response.release() _LOGGER.debug("Data from SPC: %s", result) return result
async def get_device(hass, config, event_types=None, signal_callback=None): """Create a Axis device.""" import axis device = axis.AxisDevice( loop=hass.loop, host=config[CONF_HOST], username=config[CONF_USERNAME], password=config[CONF_PASSWORD], port=config[CONF_PORT], web_proto='http', event_types=event_types, signal=signal_callback) try: with async_timeout.timeout(15): await hass.async_add_executor_job(device.vapix.load_params) return device except axis.Unauthorized: LOGGER.warning("Connected to device at %s but not registered.", config[CONF_HOST]) raise AuthenticationRequired except (asyncio.TimeoutError, axis.RequestError): LOGGER.error("Error connecting to the Axis device at %s", config[CONF_HOST]) raise CannotConnect except axis.AxisException: LOGGER.exception('Unknown Axis communication error occurred') raise AuthenticationRequired
def get_session_id(hass, websession, username, password, login_url): """Get a session id.""" auth_payload = { 'api': AUTH_API, 'method': 'Login', 'version': '2', 'account': username, 'passwd': password, 'session': 'SurveillanceStation', 'format': 'sid' } auth_req = None try: with async_timeout.timeout(TIMEOUT, loop=hass.loop): auth_req = yield from websession.get( login_url, params=auth_payload ) auth_resp = yield from auth_req.json() return auth_resp['data']['sid'] except (asyncio.TimeoutError, aiohttp.errors.ClientError): _LOGGER.exception("Error on %s", login_url) return False finally: if auth_req is not None: yield from auth_req.release()
def async_camera_image(self): """Return a still image response from the camera.""" image_url = SYNO_API_URL.format( self._synology_url, WEBAPI_PATH, self._camera_path) image_payload = { 'api': CAMERA_API, 'method': 'GetSnapshot', 'version': '1', 'cameraId': self._camera_id } try: with async_timeout.timeout(TIMEOUT, loop=self.hass.loop): response = yield from self._websession.get( image_url, params=image_payload ) except (asyncio.TimeoutError, aiohttp.errors.ClientError): _LOGGER.exception("Error on %s", image_url) return None image = yield from response.read() yield from response.release() return image
def is_connected(self): """Return True if it connected to HassIO supervisor. This method is a coroutine. """ try: with async_timeout.timeout(TIMEOUT, loop=self.loop): request = yield from self.websession.get( "http://{}{}".format(self._ip, "/supervisor/ping") ) if request.status != 200: _LOGGER.error("Ping return code %d.", request.status) return False answer = yield from request.json() return answer and answer['result'] == 'ok' except asyncio.TimeoutError: _LOGGER.error("Timeout on ping request") except aiohttp.ClientError as err: _LOGGER.error("Client error on ping request %s", err) return False
async def async_update(self): """Get the ComEd Hourly Pricing data from the web service.""" try: if self.type == CONF_FIVE_MINUTE or \ self.type == CONF_CURRENT_HOUR_AVERAGE: url_string = _RESOURCE if self.type == CONF_FIVE_MINUTE: url_string += '?type=5minutefeed' else: url_string += '?type=currenthouraverage' with async_timeout.timeout(60, loop=self.loop): response = await self.websession.get(url_string) # The API responds with MIME type 'text/html' text = await response.text() data = json.loads(text) self._state = round( float(data[0]['price']) + self.offset, 2) else: self._state = None except (asyncio.TimeoutError, aiohttp.ClientError) as err: _LOGGER.error("Could not get data from ComEd API: %s", err) except (ValueError, KeyError): _LOGGER.warning("Could not update status for %s", self.name)
def command_proxy(self, path, request): """Return a client request with proxy origin for HassIO supervisor. This method is a coroutine. """ try: data = None headers = None with async_timeout.timeout(TIMEOUT, loop=self.loop): data = yield from request.read() if data: headers = {CONTENT_TYPE: request.content_type} else: data = None method = getattr(self.websession, request.method.lower()) client = yield from method( "http://{}/{}".format(self._ip, path), data=data, headers=headers ) return client except aiohttp.ClientError as err: _LOGGER.error("Client error on api %s request %s.", path, err) except asyncio.TimeoutError: _LOGGER.error("Client timeout error on api request %s.", path) raise HTTPBadGateway()
def async_get_last_state(hass, entity_id: str): """Restore state.""" if DATA_RESTORE_CACHE in hass.data: return hass.data[DATA_RESTORE_CACHE].get(entity_id) if _RECORDER not in hass.config.components: return None if hass.state not in (CoreState.starting, CoreState.not_running): _LOGGER.debug("Cache for %s can only be loaded during startup, not %s", entity_id, hass.state) return None try: with async_timeout.timeout(RECORDER_TIMEOUT, loop=hass.loop): connected = yield from wait_connection_ready(hass) except asyncio.TimeoutError: return None if not connected: return None if _LOCK not in hass.data: hass.data[_LOCK] = asyncio.Lock(loop=hass.loop) with (yield from hass.data[_LOCK]): if DATA_RESTORE_CACHE not in hass.data: yield from hass.async_add_job( _load_restore_cache, hass) return hass.data.get(DATA_RESTORE_CACHE, {}).get(entity_id)
def async_get_tts_audio(self, message, language, options=None): """Load TTS from yandex.""" websession = async_get_clientsession(self.hass) actual_language = language try: with async_timeout.timeout(10, loop=self.hass.loop): url_param = { 'text': message, 'lang': actual_language, 'key': self._key, 'speaker': self._speaker, 'format': self._codec, 'emotion': self._emotion, 'speed': self._speed } request = yield from websession.get( YANDEX_API_URL, params=url_param) if request.status != 200: _LOGGER.error("Error %d on load URL %s", request.status, request.url) return (None, None) data = yield from request.read() except (asyncio.TimeoutError, aiohttp.ClientError): _LOGGER.error("Timeout for yandex speech kit API") return (None, None) return (self._codec, data)
async def get_data(self, url): """Load data from specified url.""" from buienradar.buienradar import (CONTENT, MESSAGE, STATUS_CODE, SUCCESS) _LOGGER.debug("Calling url: %s...", url) result = {SUCCESS: False, MESSAGE: None} resp = None try: websession = async_get_clientsession(self.hass) with async_timeout.timeout(10, loop=self.hass.loop): resp = await websession.get(url) result[STATUS_CODE] = resp.status result[CONTENT] = await resp.text() if resp.status == 200: result[SUCCESS] = True else: result[MESSAGE] = "Got http statuscode: %d" % (resp.status) return result except (asyncio.TimeoutError, aiohttp.ClientError) as err: result[MESSAGE] = "%s" % err return result finally: if resp is not None: await resp.release()
async def post(self, request): """Trigger a Google Actions sync.""" hass = request.app['hass'] cloud = hass.data[DOMAIN] websession = hass.helpers.aiohttp_client.async_get_clientsession() with async_timeout.timeout(REQUEST_TIMEOUT, loop=hass.loop): await hass.async_add_job(auth_api.check_token, cloud) with async_timeout.timeout(REQUEST_TIMEOUT, loop=hass.loop): req = await websession.post( cloud.google_actions_sync_url, headers={ 'authorization': cloud.id_token }) return self.json({}, status_code=req.status)
def async_start(self): """Finalize startup from inside the event loop. This method is a coroutine. """ _LOGGER.info("Starting Home Assistant") self.state = CoreState.starting # pylint: disable=protected-access self.loop._thread_ident = threading.get_ident() self.bus.async_fire(EVENT_HOMEASSISTANT_START) try: # Only block for EVENT_HOMEASSISTANT_START listener self.async_stop_track_tasks() with timeout(TIMEOUT_EVENT_START, loop=self.loop): yield from self.async_block_till_done() except asyncio.TimeoutError: _LOGGER.warning( 'Something is blocking Home Assistant from wrapping up the ' 'start up phase. We\'re going to continue anyway. Please ' 'report the following info at http://bit.ly/2ogP58T : %s', ', '.join(self.config.components)) # Allow automations to set up the start triggers before changing state yield from asyncio.sleep(0, loop=self.loop) self.state = CoreState.running _async_create_timer(self)
def _async_ws_function(self, function): """Execute a command on UPC firmware webservice.""" try: with async_timeout.timeout(10, loop=self.hass.loop): # The 'token' parameter has to be first, and 'fun' second # or the UPC firmware will return an error response = yield from self.websession.post( "http://{}/xml/getter.xml".format(self.host), data="token={}&fun={}".format(self.token, function), headers=self.headers, allow_redirects=False ) # error? if response.status != 200: _LOGGER.warning("Receive http code %d", response.status) self.token = None return # load data, store token for next request self.token = response.cookies['sessionToken'].value return (yield from response.text()) except (asyncio.TimeoutError, aiohttp.ClientError): _LOGGER.error("Error on %s", function) self.token = None
def send_command(self, command, method="post", payload=None, timeout=10): """Send API command to Hass.io. This method is a coroutine. """ try: with async_timeout.timeout(timeout, loop=self.loop): request = yield from self.websession.request( method, "http://{}{}".format(self._ip, command), json=payload, headers={ X_HASSIO: os.environ.get('HASSIO_TOKEN', "") }) if request.status not in (200, 400): _LOGGER.error( "%s return code %d.", command, request.status) return None answer = yield from request.json() return answer except asyncio.TimeoutError: _LOGGER.error("Timeout on %s request", command) except aiohttp.ClientError as err: _LOGGER.error("Client error on %s request %s", command, err) return None
async def receive(self, timeout: Optional[float]=None) -> WSMessage: while True: if self._waiting is not None: raise RuntimeError( 'Concurrent call to receive() is not allowed') if self._closed: return WS_CLOSED_MESSAGE elif self._closing: await self.close() return WS_CLOSED_MESSAGE try: self._waiting = self._loop.create_future() try: with async_timeout.timeout( timeout or self._receive_timeout, loop=self._loop): msg = await self._reader.read() self._reset_heartbeat() finally: waiter = self._waiting self._waiting = None set_result(waiter, True) except (asyncio.CancelledError, asyncio.TimeoutError): self._close_code = 1006 raise except EofStream: self._close_code = 1000 await self.close() return WSMessage(WSMsgType.CLOSED, None, None) except ClientError: self._closed = True self._close_code = 1006 return WS_CLOSED_MESSAGE except WebSocketError as exc: self._close_code = exc.code await self.close(code=exc.code) return WSMessage(WSMsgType.ERROR, exc, None) except Exception as exc: self._exception = exc self._closing = True self._close_code = 1006 await self.close() return WSMessage(WSMsgType.ERROR, exc, None) if msg.type == WSMsgType.CLOSE: self._closing = True self._close_code = msg.data if not self._closed and self._autoclose: await self.close() elif msg.type == WSMsgType.CLOSING: self._closing = True elif msg.type == WSMsgType.PING and self._autoping: await self.pong(msg.data) continue elif msg.type == WSMsgType.PONG and self._autoping: continue return msg
async def async_update(self): """Get the TekSavvy bandwidth data from the web service.""" headers = {"TekSavvy-APIKey": self.api_key} _LOGGER.debug("Updating TekSavvy data") url = "https://api.teksavvy.com/"\ "web/Usage/UsageSummaryRecords?$filter=IsCurrent%20eq%20true" with async_timeout.timeout(REQUEST_TIMEOUT, loop=self.loop): req = await self.websession.get(url, headers=headers) if req.status != 200: _LOGGER.error("Request failed with status: %u", req.status) return False try: data = await req.json() for (api, ha_name) in API_HA_MAP: self.data[ha_name] = float(data["value"][0][api]) on_peak_download = self.data["onpeak_download"] on_peak_upload = self.data["onpeak_upload"] off_peak_download = self.data["offpeak_download"] off_peak_upload = self.data["offpeak_upload"] limit = self.data["limit"] # Support "unlimited" users if self.bandwidth_cap > 0: self.data["usage"] = 100*on_peak_download/self.bandwidth_cap else: self.data["usage"] = 0 self.data["usage_gb"] = on_peak_download self.data["onpeak_total"] = on_peak_download + on_peak_upload self.data["offpeak_total"] =\ off_peak_download + off_peak_upload self.data["onpeak_remaining"] = limit - on_peak_download return True except ValueError: _LOGGER.error("JSON Decode Failed") return False
async def fetching_data(self, *_): """Get the latest data from yr.no.""" import xmltodict def try_again(err: str): """Retry in 15 to 20 minutes.""" minutes = 15 + randrange(6) _LOGGER.error("Retrying in %i minutes: %s", minutes, err) async_call_later(self.hass, minutes*60, self.fetching_data) try: websession = async_get_clientsession(self.hass) with async_timeout.timeout(10, loop=self.hass.loop): resp = await websession.get( self._url, params=self._urlparams) if resp.status != 200: try_again('{} returned {}'.format(resp.url, resp.status)) return text = await resp.text() except (asyncio.TimeoutError, aiohttp.ClientError) as err: try_again(err) return try: self.data = xmltodict.parse(text)['weatherdata'] except (ExpatError, IndexError) as err: try_again(err) return await self.updating_devices() async_call_later(self.hass, 60*60, self.fetching_data)
def _command_proxy(self, path, request): """Return a client request with proxy origin for Hass.io supervisor. This method is a coroutine. """ read_timeout = _get_timeout(path) hass = request.app['hass'] try: data = None headers = {X_HASSIO: os.environ.get('HASSIO_TOKEN', "")} with async_timeout.timeout(10, loop=hass.loop): data = yield from request.read() if data: headers[CONTENT_TYPE] = request.content_type else: data = None method = getattr(self._websession, request.method.lower()) client = yield from method( "http://{}/{}".format(self._host, path), data=data, headers=headers, timeout=read_timeout ) return client except aiohttp.ClientError as err: _LOGGER.error("Client error on api %s request %s", path, err) except asyncio.TimeoutError: _LOGGER.error("Client timeout error on API request %s", path) raise HTTPBadGateway()
async def _gw_start(hass, gateway): """Start the gateway.""" # Don't use hass.async_create_task to avoid holding up setup indefinitely. connect_task = hass.loop.create_task(gateway.start()) @callback def gw_stop(event): """Trigger to stop the gateway.""" hass.async_create_task(gateway.stop()) if not connect_task.done(): connect_task.cancel() hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, gw_stop) if gateway.device == 'mqtt': # Gatways connected via mqtt doesn't send gateway ready message. return gateway_ready = asyncio.Future() gateway_ready_key = MYSENSORS_GATEWAY_READY.format(id(gateway)) hass.data[gateway_ready_key] = gateway_ready try: with async_timeout.timeout(GATEWAY_READY_TIMEOUT, loop=hass.loop): await gateway_ready except asyncio.TimeoutError: _LOGGER.warning( "Gateway %s not ready after %s secs so continuing with setup", gateway.device, GATEWAY_READY_TIMEOUT) finally: hass.data.pop(gateway_ready_key, None)
def test_recv_timeout(loop, test_client): @asyncio.coroutine def handler(request): ws = web.WebSocketResponse() yield from ws.prepare(request) yield from ws.receive_str() yield from asyncio.sleep(0.1, loop=request.app.loop) yield from ws.close() return ws app = web.Application() app.router.add_route('GET', '/', handler) client = yield from test_client(app) resp = yield from client.ws_connect('/') yield from resp.send_str('ask') with pytest.raises(asyncio.TimeoutError): with async_timeout.timeout(0.01, loop=app.loop): yield from resp.receive() yield from resp.close()
def get_newest_version(hass, huuid, include_components): """Get the newest Home Assistant version.""" if huuid: info_object = yield from get_system_info(hass, include_components) info_object['huuid'] = huuid else: info_object = {} session = async_get_clientsession(hass) try: with async_timeout.timeout(5, loop=hass.loop): req = yield from session.post(UPDATER_URL, json=info_object) _LOGGER.info(("Submitted analytics to Home Assistant servers. " "Information submitted includes %s"), info_object) except (asyncio.TimeoutError, aiohttp.ClientError): _LOGGER.error("Could not contact Home Assistant Update to check " "for updates") return None try: res = yield from req.json() except ValueError: _LOGGER.error("Received invalid JSON from Home Assistant Update") return None try: res = RESPONSE_SCHEMA(res) return res['version'], res['release-notes'] except vol.Invalid: _LOGGER.error("Got unexpected response: %s", res) return None
async def get_device_state(self, hass): """Get the latest data from REST API and update the state.""" websession = async_get_clientsession(hass) with async_timeout.timeout(self._timeout, loop=hass.loop): req = await websession.get(self._resource, auth=self._auth, headers=self._headers) text = await req.text() if self._is_on_template is not None: text = self._is_on_template.async_render_with_possible_json_value( text, 'None') text = text.lower() if text == 'true': self._state = True elif text == 'false': self._state = False else: self._state = None else: if text == self._body_on.template: self._state = True elif text == self._body_off.template: self._state = False else: self._state = None return req
async def get_controller(hass, host, username, password, port, site, verify_ssl, async_callback=None): """Create a controller object and verify authentication.""" sslcontext = None if verify_ssl: session = aiohttp_client.async_get_clientsession(hass) if isinstance(verify_ssl, str): sslcontext = ssl.create_default_context(cafile=verify_ssl) else: session = aiohttp_client.async_create_clientsession( hass, verify_ssl=verify_ssl, cookie_jar=CookieJar(unsafe=True)) controller = aiounifi.Controller( host, username=username, password=password, port=port, site=site, websession=session, sslcontext=sslcontext, callback=async_callback, ) try: async with async_timeout.timeout(10): await controller.check_unifi_os() await controller.login() return controller except aiounifi.Unauthorized as err: LOGGER.warning( "Connected to UniFi Network at %s but not registered: %s", host, err, ) raise AuthenticationRequired from err except ( asyncio.TimeoutError, aiounifi.BadGateway, aiounifi.ServiceUnavailable, aiounifi.RequestError, aiounifi.ResponseError, ) as err: LOGGER.error("Error connecting to the UniFi Network at %s: %s", host, err) raise CannotConnect from err except aiounifi.LoginRequired as err: LOGGER.warning( "Connected to UniFi Network at %s but login required: %s", host, err, ) raise AuthenticationRequired from err except aiounifi.AiounifiException as err: LOGGER.exception( "Unknown UniFi Network communication error occurred: %s", err) raise AuthenticationRequired from err
async def get_the_latest_chapter(chapter_url, timeout=15): try: with async_timeout.timeout(timeout): url = parse_qs(urlparse(chapter_url).query).get('url', '') novels_name = parse_qs(urlparse(chapter_url).query).get('novels_name', '') data = None if url and novels_name: url = url[0] novels_name = novels_name[0] netloc = urlparse(url).netloc if netloc in LATEST_RULES.keys(): headers = { 'user-agent': await get_random_user_agent() } try: html = await target_fetch(url=url, headers=headers, timeout=timeout) if html is None: html = get_html_by_requests(url=url, headers=headers, timeout=timeout) except TypeError: html = get_html_by_requests(url=url, headers=headers, timeout=timeout) except Exception as e: LOGGER.exception(e) return None try: soup = BeautifulSoup(html, 'html5lib') except Exception as e: LOGGER.exception(e) return None latest_chapter_name, latest_chapter_url = None, None if LATEST_RULES[netloc].plan: meta_value = LATEST_RULES[netloc].meta_value latest_chapter_name = soup.select( 'meta[property="{0}"]'.format(meta_value["latest_chapter_name"])) or soup.select( 'meta[name="{0}"]'.format(meta_value["latest_chapter_name"])) latest_chapter_name = latest_chapter_name[0].get('content', None) if latest_chapter_name else None latest_chapter_url = soup.select( 'meta[property="{0}"]'.format(meta_value["latest_chapter_url"])) or soup.select( 'meta[name="{0}"]'.format(meta_value["latest_chapter_url"])) latest_chapter_url = urljoin(chapter_url, latest_chapter_url[0].get('content', None)) if latest_chapter_url else None else: selector = LATEST_RULES[netloc].selector content_url = selector.get('content_url') if selector.get('id', None): latest_chapter_soup = soup.find_all(id=selector['id']) elif selector.get('class', None): latest_chapter_soup = soup.find_all(class_=selector['class']) else: latest_chapter_soup = soup.select(selector.get('tag')) if latest_chapter_soup: if content_url == '1': # TODO pass elif content_url == '0': # TODO pass else: latest_chapter_url = content_url + latest_chapter_soup[0].get('href', None) latest_chapter_name = latest_chapter_soup[0].get('title', None) if latest_chapter_name and latest_chapter_url: time_current = get_time() # print(latest_chapter_url) data = { "latest_chapter_name": latest_chapter_name, "latest_chapter_url": latest_chapter_url, "owllook_chapter_url": chapter_url, "owllook_content_url": "/owllook_content?url={latest_chapter_url}&name={name}&chapter_url={chapter_url}&novels_name={novels_name}".format( latest_chapter_url=latest_chapter_url, name=latest_chapter_name, chapter_url=url, novels_name=novels_name, ), } # 存储最新章节 motor_db = MotorBase().get_db() await motor_db.latest_chapter.update_one( {"novels_name": novels_name, 'owllook_chapter_url': chapter_url}, {'$set': {'data': data, "finished_at": time_current}}, upsert=True) return data except Exception as e: LOGGER.exception(e) return None
async def fetch(session: aiohttp.ClientSession, feed_url: str) -> dict: with async_timeout.timeout(10): async with session.get(feed_url) as response: return await response.text()
async def get_tide_table(config, last_tide_in_the_past=None): # get the tide data from Weather Underground logging.info('loading new tide table') while True: try: async with aiohttp.ClientSession() as session: async with async_timeout.timeout(config.seconds_for_timeout): async with session.get(config.target_url) as response: raw_tide_data = json.loads(await response.text()) break except Exception as e: logging.error('problem reading {}: {}'.format( config.target_url, e)) logging.info('retrying after 20 second pause') asyncio.sleep(20.0) raise # The raw tide data has junk in it that we don't want # Pare it down to just the High Tide and Low Tide events # ignoring all the other events that Weather Underground # gives in the tide data (sunset, sunrise, moonset, moonrise, # moon phase, ...) raw_tide_list = [] try: for item in raw_tide_data["tide"]["tideSummary"]: if item["data"]["type"] in ("High Tide", "Low Tide"): raw_tide_list.append((item["data"]["type"], datetime( int(item["utcdate"]["year"]), int(item["utcdate"]["mon"]), int(item["utcdate"]["mday"]), int(item["utcdate"]["hour"]), int(item["utcdate"]["min"]), ))) except KeyError: logging.error( 'Weather Underground is not currently supplying Tide data for this location' ) raise Exception('Bad Location') if not len(raw_tide_list): logging.error( 'Weather Underground is not currently supplying Tide data for this location' ) raise Exception('Bad Location') # Now create a more useful list of tide events as tuples of # (TideType, TideTime, TimeToNextTide, StepTimeForNextTide future_tides_list = [] for i, (tide_type_str, tide_datetime) in enumerate(raw_tide_list[:-1]): future_tides_list.append(( tide_type_str, # TideType tide_datetime, # TideTime raw_tide_list[i + 1][1] - tide_datetime, # TimeToNextTide (raw_tide_list[i + 1][1] - tide_datetime) / 120 # StepTimeForNextTide )) # We need the last tide event, but Weather Underground only gives us # future events. Guess about timing of the previous tide was if it wasn't # already passed in to this method if last_tide_in_the_past is None: logging.debug( '{}, {} no previous tide information, guessing...'.format( config.city_name, config.state_code, )) last_tide_in_the_past = ( "Low Tide" if future_tides_list[0][0] == "High Tide" else "High Tide", future_tides_list[0][1] - future_tides_list[0][2], future_tides_list[0][2], future_tides_list[0][3], ) # Create a tide table - a list of tide tuples where the first entry is the # most recent tide event in the past tide_table = [last_tide_in_the_past] tide_table.extend(future_tides_list) return tide_table
async def async_call( self, domain: str, service: str, service_data: Optional[Dict] = None, blocking: bool = False, context: Optional[Context] = None, ) -> Optional[bool]: """ Call a service. Specify blocking=True to wait till service is executed. Waits a maximum of SERVICE_CALL_LIMIT. If blocking = True, will return boolean if service executed successfully within SERVICE_CALL_LIMIT. This method will fire an event to call the service. This event will be picked up by this ServiceRegistry and any other ServiceRegistry that is listening on the EventBus. Because the service is sent as an event you are not allowed to use the keys ATTR_DOMAIN and ATTR_SERVICE in your service_data. This method is a coroutine. """ domain = domain.lower() service = service.lower() context = context or Context() service_data = service_data or {} try: handler = self._services[domain][service] except KeyError: raise ServiceNotFound(domain, service) from None if handler.schema: processed_data = handler.schema(service_data) else: processed_data = service_data service_call = ServiceCall(domain, service, processed_data, context) self._hass.bus.async_fire( EVENT_CALL_SERVICE, { ATTR_DOMAIN: domain.lower(), ATTR_SERVICE: service.lower(), ATTR_SERVICE_DATA: service_data, }, context=context, ) if not blocking: self._hass.async_create_task( self._safe_execute(handler, service_call)) return None try: with timeout(SERVICE_CALL_LIMIT): await asyncio.shield( self._execute_service(handler, service_call)) return True except asyncio.TimeoutError: return False
async def async_setup_entry(hass: HomeAssistant, entry: config_entries.ConfigEntry) -> bool: """Set up the ISY 994 integration.""" # As there currently is no way to import options from yaml # when setting up a config entry, we fallback to adding # the options to the config entry and pull them out here if # they are missing from the options _async_import_options_from_data_if_missing(hass, entry) hass.data[DOMAIN][entry.entry_id] = {} hass_isy_data = hass.data[DOMAIN][entry.entry_id] hass_isy_data[ISY994_NODES] = {SENSOR_AUX: []} for platform in PLATFORMS: hass_isy_data[ISY994_NODES][platform] = [] hass_isy_data[ISY994_PROGRAMS] = {} for platform in PROGRAM_PLATFORMS: hass_isy_data[ISY994_PROGRAMS][platform] = [] hass_isy_data[ISY994_VARIABLES] = [] isy_config = entry.data isy_options = entry.options # Required user = isy_config[CONF_USERNAME] password = isy_config[CONF_PASSWORD] host = urlparse(isy_config[CONF_HOST]) # Optional tls_version = isy_config.get(CONF_TLS_VER) ignore_identifier = isy_options.get(CONF_IGNORE_STRING, DEFAULT_IGNORE_STRING) sensor_identifier = isy_options.get(CONF_SENSOR_STRING, DEFAULT_SENSOR_STRING) variable_identifier = isy_options.get(CONF_VAR_SENSOR_STRING, DEFAULT_VAR_SENSOR_STRING) if host.scheme == "http": https = False port = host.port or 80 session = aiohttp_client.async_create_clientsession( hass, verify_ssl=False, cookie_jar=CookieJar(unsafe=True)) elif host.scheme == "https": https = True port = host.port or 443 session = aiohttp_client.async_get_clientsession(hass) else: _LOGGER.error("The isy994 host value in configuration is invalid") return False # Connect to ISY controller. isy = ISY( host.hostname, port, username=user, password=password, use_https=https, tls_ver=tls_version, webroot=host.path, websession=session, use_websocket=True, ) try: async with async_timeout.timeout(60): await isy.initialize() except asyncio.TimeoutError as err: raise ConfigEntryNotReady( f"Timed out initializing the ISY; device may be busy, trying again later: {err}" ) from err except ISYInvalidAuthError as err: raise ConfigEntryAuthFailed( f"Invalid credentials for the ISY: {err}") from err except ISYConnectionError as err: raise ConfigEntryNotReady( f"Failed to connect to the ISY, please adjust settings and try again: {err}" ) from err except ISYResponseParseError as err: raise ConfigEntryNotReady( f"Invalid XML response from ISY; Ensure the ISY is running the latest firmware: {err}" ) from err _categorize_nodes(hass_isy_data, isy.nodes, ignore_identifier, sensor_identifier) _categorize_programs(hass_isy_data, isy.programs) _categorize_variables(hass_isy_data, isy.variables, variable_identifier) # Dump ISY Clock Information. Future: Add ISY as sensor to Hass with attrs _LOGGER.info(repr(isy.clock)) hass_isy_data[ISY994_ISY] = isy _async_get_or_create_isy_device_in_registry(hass, entry, isy) # Load platforms for the devices in the ISY controller that we support. await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) @callback def _async_stop_auto_update(event: Event) -> None: """Stop the isy auto update on Home Assistant Shutdown.""" _LOGGER.debug("ISY Stopping Event Stream and automatic updates") isy.websocket.stop() _LOGGER.debug("ISY Starting Event Stream and automatic updates") isy.websocket.start() entry.async_on_unload(entry.add_update_listener(_async_update_listener)) entry.async_on_unload( hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, _async_stop_auto_update)) # Register Integration-wide Services: async_setup_services(hass) return True
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): """Set up Shelly from a config entry.""" hass.data[DOMAIN][DATA_CONFIG_ENTRY][entry.entry_id] = {} hass.data[DOMAIN][DATA_CONFIG_ENTRY][entry.entry_id][DEVICE] = None temperature_unit = "C" if hass.config.units.is_metric else "F" options = aioshelly.ConnectionOptions( entry.data[CONF_HOST], entry.data.get(CONF_USERNAME), entry.data.get(CONF_PASSWORD), temperature_unit, ) coap_context = await get_coap_context(hass) device = await aioshelly.Device.create( aiohttp_client.async_get_clientsession(hass), coap_context, options, False, ) dev_reg = await device_registry.async_get_registry(hass) identifier = (DOMAIN, entry.unique_id) device_entry = dev_reg.async_get_device(identifiers={identifier}, connections=set()) if device_entry and entry.entry_id not in device_entry.config_entries: device_entry = None sleep_period = entry.data.get("sleep_period") @callback def _async_device_online(_): _LOGGER.debug("Device %s is online, resuming setup", entry.title) hass.data[DOMAIN][DATA_CONFIG_ENTRY][entry.entry_id][DEVICE] = None if sleep_period is None: data = {**entry.data} data["sleep_period"] = get_device_sleep_period(device.settings) data["model"] = device.settings["device"]["type"] hass.config_entries.async_update_entry(entry, data=data) hass.async_create_task(async_device_setup(hass, entry, device)) if sleep_period == 0: # Not a sleeping device, finish setup _LOGGER.debug("Setting up online device %s", entry.title) try: async with async_timeout.timeout(AIOSHELLY_DEVICE_TIMEOUT_SEC): await device.initialize(True) except (asyncio.TimeoutError, OSError) as err: raise ConfigEntryNotReady from err await async_device_setup(hass, entry, device) elif sleep_period is None or device_entry is None: # Need to get sleep info or first time sleeping device setup, wait for device hass.data[DOMAIN][DATA_CONFIG_ENTRY][entry.entry_id][DEVICE] = device _LOGGER.debug( "Setup for device %s will resume when device is online", entry.title ) device.subscribe_updates(_async_device_online) await device.coap_request("s") else: # Restore sensors for sleeping device _LOGGER.debug("Setting up offline device %s", entry.title) await async_device_setup(hass, entry, device) return True
async def trim_fn(c, m): chat_id = m.chat.id if c.CURRENT_PROCESSES.get(chat_id, 0) == Config.MAX_PROCESSES_PER_USER: await m.reply_text( 'You have reached the maximum parallel processes! Try again after one of them finishes.', True) return if not c.CURRENT_PROCESSES.get(chat_id): c.CURRENT_PROCESSES[chat_id] = 0 c.CURRENT_PROCESSES[chat_id] += 1 message = await c.get_messages(chat_id, m.reply_to_message.message_id) await m.reply_to_message.delete() media_msg = message.reply_to_message if media_msg.empty: await m.reply_text( 'Why did you delete the file 😠, Now i cannot help you 😒.', True) c.CURRENT_PROCESSES[chat_id] -= 1 return try: start, end = [int(i) for i in m.text.split(':')] except: await m.reply_text('Please follow the specified format', True) c.CURRENT_PROCESSES[chat_id] -= 1 return if (start >= end) or (start < 0): await m.reply_text('Invalid range!', True) c.CURRENT_PROCESSES[chat_id] -= 1 return request_duration = end - start if request_duration > Config.MAX_TRIM_DURATION: await m.reply_text( f'Please provide any range that\'s upto {Config.MAX_TRIM_DURATION}s. Your requested range **{start}:{end}** is `{request_duration}s` long!', True) c.CURRENT_PROCESSES[chat_id] -= 1 return uid = str(uuid.uuid4()) output_folder = Config.SMPL_OP_FLDR.joinpath(uid) os.makedirs(output_folder, exist_ok=True) if Config.TRACK_CHANNEL: tr_msg = await media_msg.forward(Config.TRACK_CHANNEL) await tr_msg.reply_text(f"User id: `{chat_id}`") if media_msg.media: typ = 1 else: typ = 2 snt = await m.reply_text('Processing your request, Please wait! 😴', True) try: async with timeout(Config.TIMEOUT) as cm: start_time = time.time() if typ == 2: file_link = media_msg.text else: file_link = generate_stream_link(media_msg) await snt.edit_text( '😀 Trimming Your Video! This might take some time.') duration = await get_duration(file_link) if isinstance(duration, str): await snt.edit_text("😟 Sorry! I cannot open the file.") l = await media_msg.forward(Config.LOG_CHANNEL) await l.reply_text( f'stream link : {file_link}\n\ntrim video requested\n\n{start}:{end}', True) c.CURRENT_PROCESSES[chat_id] -= 1 return if (start >= duration) or (end >= duration): await snt.edit_text( "😟 Sorry! The requested range is out of the video's duration!." ) c.CURRENT_PROCESSES[chat_id] -= 1 return log.info( f"Trimming video (duration {request_duration}s from {start}) from location: {file_link} for {chat_id}" ) sample_file = output_folder.joinpath(f'trim_video.mkv') subtitle_option = await fix_subtitle_codec(file_link) ffmpeg_cmd = f"ffmpeg -hide_banner -ss {start} -i {shlex.quote(file_link)} -t {request_duration} -map 0 -c copy {subtitle_option} {sample_file}" output = await run_subprocess(ffmpeg_cmd) log.debug(output) if (not sample_file.exists()) or (os.path.getsize(sample_file) == 0): await snt.edit_text( '😟 Sorry! video trimming failed possibly due to some infrastructure failure 😥.' ) ffmpeg_output = output[0].decode() + '\n' + output[1].decode() l = await media_msg.forward(Config.LOG_CHANNEL) await l.reply_text( f'stream link : {file_link}\n\nVideo trimm failed. **{start}:{end}**\n\n{ffmpeg_output}', True) c.CURRENT_PROCESSES[chat_id] -= 1 return thumb = await generate_thumbnail_file(sample_file, uid) await snt.edit_text( '🤓 Video trimmed successfully!, Now starting to upload!') await m.reply_chat_action("upload_video") await m.reply_video( video=str(sample_file), quote=True, caption= f"Trimmed video from {datetime.timedelta(seconds=start)} to {datetime.timedelta(seconds=end)}", duration=request_duration, thumb=thumb, supports_streaming=True) await snt.edit_text( f'Successfully completed process in {datetime.timedelta(seconds=int(time.time()-start_time))}\n\nIf You find me helpful, please rate me [here](tg://resolve?domain=botsarchive&post=1206).' ) c.CURRENT_PROCESSES[chat_id] -= 1 except (asyncio.TimeoutError, asyncio.CancelledError): await snt.edit_text( '😟 Sorry! Video trimming failed due to timeout. Your process was taking too long to complete, hence cancelled' ) c.CURRENT_PROCESSES[chat_id] -= 1 except Exception as e: log.error(e, exc_info=True) await snt.edit_text( '😟 Sorry! Video trimming failed possibly due to some infrastructure failure 😥.' ) l = await media_msg.forward(Config.LOG_CHANNEL) await l.reply_text( f'sample video requested and some error occoured\n\n{traceback.format_exc()}', True) c.CURRENT_PROCESSES[chat_id] -= 1