async def _listen_for_incoming_websocket_data(self, incoming_parser): """Creates a websocket connection, listens for incoming data and uses the incoming parser to parse the incoming data. """ try: for i in range(self._restCallRequestCounter): try: await self._connect_to_websocket() break except (asyncio.TimeoutError, aiohttp.ClientConnectionError): logger.warning( 'websocket connection timed-out. or other connection error occurred.' ) await asyncio.sleep(self._restCallTimout) else: # exit while loop without break. Raising error which # should be handled by user. raise HmipConnectionError( "Problem connecting to hmip websocket connection") logger.info('Connected to HMIP websocket.') while True: try: # It doesn't seem to be possible to observe an unexpected # internet disconnect. To keep the connection persistent # the connection is wrapped in a timeout after which a # reconnect attempt is made. with async_timeout.timeout(self.reconnect_timeout, loop=self._loop): async for msg in self.socket_connection: logger.debug(msg) if msg.tp == aiohttp.WSMsgType.BINARY: message = str(msg.data, 'utf-8') incoming_parser(None, message) elif msg.tp in [ aiohttp.WSMsgType.CLOSE, aiohttp.WSMsgType.CLOSED, aiohttp.WSMsgType.ERROR ]: # Server has closed the connection. # Raising error which should be handled by # user. raise HmipConnectionError( "Server closed websocket connection") except asyncio.TimeoutError: #await self.socket_connection.close() logger.debug( 'controlled stopping of websocket. Reconnecting') except CancelledError: logger.debug('stopping websocket incoming listener')
async def _connect_to_websocket(self): try: self.socket_connection = await asyncio.wait_for( websockets.connect(self._urlWebSocket, extra_headers={ ATTR_AUTH_TOKEN: self._auth_token, ATTR_CLIENT_AUTH: self._clientauth_token }), timeout=self.connect_timeout) except asyncio.TimeoutError: raise HmipConnectionError( "Connecting to hmip ws socket timed out.") except Exception as err: logger.exception(err) raise HmipConnectionError()
async def api_call(self, path, body=None, full_url=False): """Make the actual call to the HMIP server. Throws `HmipWrongHttpStatusError` or `HmipConnectionError` if connection has failed or response is not correct.""" result = None if not full_url: path = self.full_url(path) for i in range(self._restCallRequestCounter): try: with async_timeout.timeout(self._restCallTimout, loop=self._loop): result = await self._websession.post(path, data=body, headers=self.headers) if result.status == 200: if result.content_type == 'application/json': ret = await result.json() else: ret = True return ret else: raise HmipWrongHttpStatusError except (asyncio.TimeoutError, aiohttp.ClientConnectionError): # Both exceptions occur when connecting to the server does # somehow not work. logger.debug( "Connection timed out or another error occurred %s" % path) except JSONDecodeError as err: logger.exception(err) finally: if result is not None: await result.release() raise HmipConnectionError("Failed to connect to HomeMaticIp server")
async def _ws_loop(self, on_message, on_error): try: while True: msg = await self.socket_connection.recv() logger.debug("incoming hmip message") on_message(msg.decode()) except TypeError: logger.error("Problem converting incoming bytes %s", msg) except ConnectionClosed: logger.debug("Connection closed by server") except CancelledError: logger.info("Reading task is cancelled.") except Exception as err: logger.debug("WS Reader task stop.") logger.exception(err) finally: await self.close_websocket_connection(source_is_reading_loop=True) await self._closing_task raise HmipConnectionError()