diff --git a/CHANGELOG.md b/CHANGELOG.md index 184045f..6916883 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 2.0.20 + +- Additional validation for WebSockets disconnection with more logging +- Documentation for API +- Core alignment + ## 2.0.19 - Improved logic to identify interface types correctly and present all diff --git a/README.md b/README.md index 62d4564..a14f81d 100644 --- a/README.md +++ b/README.md @@ -158,3 +158,41 @@ data: | /api/edgeos/{ENTRY_ID}/ws | GET | JSON of all raw data from the EdgeOS WebSocket, per integration | **Authentication: Requires long-living token from HA** + + +### Examples + +#### List + +*Request* +```bash +curl https://ha_url:8123/api/edgeos/list + -H "Accept: application/json" + -H "Authorization: Bearer {token}" +``` + +#### Home Assistant Data + +*Request* +```bash +curl https://ha_url:8123/api/edgeos/{ENTRY_ID}/ha + -H "Accept: application/json" + -H "Authorization: Bearer {token}" +``` + +#### WebSockets Data + +*Request* +```bash +curl https://ha_url:8123/api/edgeos/{ENTRY_ID}/ws + -H "Accept: application/json" + -H "Authorization: Bearer {token}" +``` + +#### API Data + +```bash +curl https://ha_url:8123/api/edgeos/{ENTRY_ID}/api + -H "Accept: application/json" + -H "Authorization: Bearer {token}" +``` diff --git a/custom_components/edgeos/component/api/websocket.py b/custom_components/edgeos/component/api/websocket.py index 8b4617e..35935cb 100644 --- a/custom_components/edgeos/component/api/websocket.py +++ b/custom_components/edgeos/component/api/websocket.py @@ -145,6 +145,8 @@ async def async_send_heartbeat(self): if self._session is None or self._session.closed: await self.set_status(ConnectivityStatus.NotConnected) + return + if self.status == ConnectivityStatus.Connected: content = { "CLIENT_PING": "", @@ -157,7 +159,12 @@ async def async_send_heartbeat(self): _LOGGER.debug(f"Keep alive data to be sent: {data_for_log}") - await self._ws.send_str(data) + try: + await self._ws.send_str(data) + except ConnectionResetError as cre: + _LOGGER.warning(f"Connection reset error raise by the client, will try to reconnect soon, Error: {cre}") + + await self.set_status(ConnectivityStatus.Failed) async def _listen(self): _LOGGER.info(f"Starting to listen connected") @@ -171,12 +178,13 @@ async def _listen(self): while listening and self.status == ConnectivityStatus.Connected: async for msg in self._ws: + is_connected = self.status == ConnectivityStatus.Connected is_closing_type = msg.type in WS_CLOSING_MESSAGE is_error = msg.type == aiohttp.WSMsgType.ERROR is_closing_data = False if is_closing_type or is_error else msg.data == "close" session_is_closed = self._session is None or self._session.closed - if is_closing_type or is_error or is_closing_data or session_is_closed: + if is_closing_type or is_error or is_closing_data or session_is_closed or not is_connected: _LOGGER.warning( f"WS stopped listening, " f"Message: {str(msg)}, " @@ -192,6 +200,8 @@ async def _listen(self): await self.parse_message(msg.data) + _LOGGER.info("Message queue is empty, will try to resample in a second") + await sleep(1) _LOGGER.info(f"Stop listening") diff --git a/custom_components/edgeos/component/managers/home_assistant.py b/custom_components/edgeos/component/managers/home_assistant.py index 2614fee..a44e2c8 100644 --- a/custom_components/edgeos/component/managers/home_assistant.py +++ b/custom_components/edgeos/component/managers/home_assistant.py @@ -96,7 +96,7 @@ async def _ws_data_changed(self): await self._extract_ws_data() async def _api_status_changed(self, status: ConnectivityStatus): - _LOGGER.info(f"API Status changed to {status}, WS Status: {self.ws.status}") + _LOGGER.info(f"API Status changed to {status.name}, WS Status: {self.ws.status.name}") if status == ConnectivityStatus.Connected: await self.api.async_update() @@ -111,7 +111,7 @@ async def _api_status_changed(self, status: ConnectivityStatus): await self.ws.terminate() async def _ws_status_changed(self, status: ConnectivityStatus): - _LOGGER.info(f"WS Status changed to {status}, API Status: {self.api.status}") + _LOGGER.info(f"WS Status changed to {status.name}, API Status: {self.api.status.name}") api_connected = self.api.status == ConnectivityStatus.Connected ws_connected = status == ConnectivityStatus.Connected diff --git a/custom_components/edgeos/core/components/camera.py b/custom_components/edgeos/core/components/camera.py index fa5bc3b..027d7e9 100644 --- a/custom_components/edgeos/core/components/camera.py +++ b/custom_components/edgeos/core/components/camera.py @@ -60,7 +60,10 @@ def initialize( username = config_data.username password = config_data.password - fps = int(entity.details.get(ATTR_STREAM_FPS, 1)) + fps_str = entity.details.get(ATTR_STREAM_FPS, SINGLE_FRAME_PS) + + fps = SINGLE_FRAME_PS if fps_str == EMPTY_STRING else int(float(fps_str)) + stream_source = entity.attributes.get(CONF_STREAM_SOURCE) snapshot = entity.attributes.get(CONF_STILL_IMAGE_URL) @@ -75,7 +78,7 @@ def initialize( self._still_image_url.hass = hass self._stream_source = stream_source - self._frame_interval = 1 / fps + self._frame_interval = SINGLE_FRAME_PS / fps self._supported_features = stream_support_flag self._is_recording_state = self.entity.details.get(ATTR_MODE_RECORD) diff --git a/custom_components/edgeos/core/helpers/const.py b/custom_components/edgeos/core/helpers/const.py index 1142908..00daae6 100644 --- a/custom_components/edgeos/core/helpers/const.py +++ b/custom_components/edgeos/core/helpers/const.py @@ -71,3 +71,6 @@ ACTION_CORE_ENTITY_SELECT_OPTION = "select_option" ACTION_CORE_ENTITY_ENABLE_MOTION_DETECTION = "enable_motion_detection" ACTION_CORE_ENTITY_DISABLE_MOTION_DETECTION = "disable_motion_detection" + +SINGLE_FRAME_PS = 1 +EMPTY_STRING = "" diff --git a/custom_components/edgeos/manifest.json b/custom_components/edgeos/manifest.json index cb3b68a..e4e10dd 100644 --- a/custom_components/edgeos/manifest.json +++ b/custom_components/edgeos/manifest.json @@ -7,6 +7,6 @@ "codeowners": ["@elad-bar"], "requirements": ["aiohttp"], "config_flow": true, - "version": "2.0.18", + "version": "2.0.20", "iot_class": "local_polling" } diff --git a/info.md b/info.md index 62d4564..a14f81d 100644 --- a/info.md +++ b/info.md @@ -158,3 +158,41 @@ data: | /api/edgeos/{ENTRY_ID}/ws | GET | JSON of all raw data from the EdgeOS WebSocket, per integration | **Authentication: Requires long-living token from HA** + + +### Examples + +#### List + +*Request* +```bash +curl https://ha_url:8123/api/edgeos/list + -H "Accept: application/json" + -H "Authorization: Bearer {token}" +``` + +#### Home Assistant Data + +*Request* +```bash +curl https://ha_url:8123/api/edgeos/{ENTRY_ID}/ha + -H "Accept: application/json" + -H "Authorization: Bearer {token}" +``` + +#### WebSockets Data + +*Request* +```bash +curl https://ha_url:8123/api/edgeos/{ENTRY_ID}/ws + -H "Accept: application/json" + -H "Authorization: Bearer {token}" +``` + +#### API Data + +```bash +curl https://ha_url:8123/api/edgeos/{ENTRY_ID}/api + -H "Accept: application/json" + -H "Authorization: Bearer {token}" +```