diff --git a/README.md b/README.md index 4f3c583..1680f91 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,6 @@ English | [繁體中文](README_zhHant.md)
![config_flow_image](https://github.com/J1A-T13N/ha-trem/assets/29163857/a6f4cc49-0521-4f27-a894-9fb1273be1cf) ![simulator_earthquake_demo](https://github.com/J1A-T13N/ha-trem/assets/29163857/b62dab7a-2935-4477-8297-f7e275df0a81) -

@@ -31,6 +30,16 @@ English | [繁體中文](README_zhHant.md)
>The source of earthquake early warning is provided by ExpTech Studio and is for reference only.
>The actual results are subject to the content published by [CWA](https://scweb.cwa.gov.tw/en-US). +
+
+ + +## Feature + +- [x] Isoseismal map image (can also be saved as file). +- [x] Simulator earthquake service. +- [x] RTS Notification (Exptech VIP Only). +- [x] Tsunami Notification (Exptech VIP Only).

@@ -93,12 +102,16 @@ English | [繁體中文](README_zhHant.md)
- If the integration didn't show up in the list please REFRESH the page - If the integration is still not in the list, you need to clear the browser cache. +*A Region code can be search [here](https://github.com/ExpTechTW/API/blob/master/resource/region.json).*


-## API Node +## Data Source +- [x] HTTPS API (or use your self-server) +- [x] Websocket. (Exptech VIP Only) +### HTTPS API | Node | Description | | :----------------: | :-----------------------------------------: | | tainan_cache_limit | The number of requests is limited | @@ -112,12 +125,16 @@ English | [繁體中文](README_zhHant.md)
| pingtung | The data is real-time but the load is high | | pingtung_2 | The data is real-time but the load is high | +### Websocket +**Exptech VIP Only** +You can goto [https://exptech.com.tw/pricing](https://exptech.com.tw/pricing) to subscribe. + *An API server can be monitored [here](https://status.exptech.dev/).*
## Known issues -> :tada: No issues found yet +1. Not support Home Assistant 2024.8 and higher yet.

@@ -125,7 +142,7 @@ English | [繁體中文](README_zhHant.md)
## Contribution -- ExpTech Studio `EEW Source` +- ExpTech Studio `Data Source` - watermelon1024 `Contributor` - kukuxx `Test Partner` @@ -135,20 +152,6 @@ English | [繁體中文](README_zhHant.md)

-## Future - -- [x] Integration: Convert components from sensor to platform. -- [x] Integration: Add isoseismal map image. -- [x] Integration Service: Simulator earthquake. -- [x] Integration Service: Save as image. -- [x] Integration Service: Reload entity. -- [x] ExptechTW Features: Earthquake early warning Source from WebSocket. (Exptech VIP Only) -- [ ] ExptechTW Features: TREM-Net EEW、RTS...etc. (Exptech VIP Only) - -
-
- - ## Donate | Buy me a coffee | LINE Bank | JKao Pay | @@ -162,6 +165,8 @@ English | [繁體中文](README_zhHant.md)
## License AGPL-3.0 license +**2024-08-15 Agreement reached with ExpTech Studio.** + [releases-shield]: https://img.shields.io/github/release/gaojiafamily/ha-trem.svg?style=for-the-badge [releases]: https://github.com/gaojiafamily/ha-trem/releases diff --git a/README_zhHant.md b/README_zhHant.md index fa45315..5e86cdd 100644 --- a/README_zhHant.md +++ b/README_zhHant.md @@ -34,6 +34,17 @@
+## Feature + +- [x] Isoseismal map image (can also be saved as file). +- [x] Simulator earthquake service. +- [x] RTS Notification (Exptech VIP Only). +- [x] Tsunami Notification (Exptech VIP Only). + +
+
+ + ## 測試結果 | 環境 | Home Assistant OS | Home Assistant Core | Home Assistant Supervisor | @@ -84,14 +95,23 @@ ## 設定 + **請跟隨設定流程新增.** +1. 配置 > 整合 > 新增整合 > Taiwan Real-time Earthquake Monitoring + - 如果整合未顯示在清單中,請重新整理頁面 + - 如果整合仍然不在清單中,您需要清除瀏覽器快取。 + +*地區代碼可以[到這](https://github.com/ExpTechTW/API/blob/master/resource/region.json) 查詢*


-## API 節點 +## 資料來源 +- [x] HTTPS API (or use your self-server) +- [x] Websocket. (Exptech VIP Only) +### HTTPS API | Node | Description | | :----------------: | :--------------: | | tainan_cache_limit | 請求次數遭到限制  | @@ -105,12 +125,16 @@ | pingtung | 即時資料,但延遲高 | | pingtung_2 | 即時資料,但延遲高 | -*An API server can be monitored [here](https://status.exptech.dev/).*
+### Websocket +**需要Exptech VIP** +您可以到 [https://exptech.com.tw/pricing](https://exptech.com.tw/pricing) 訂閱VIP + +*伺服器狀態可 [在這](https://status.exptech.dev/) 查看*
## 已知問題 -> :tada: 暫時沒有發現問題 +1. 暫不支援 2024.8 及更高版本的 Home Assistant

@@ -128,20 +152,6 @@
-## 未來功能 - -- [x] Integration 相關: Convert components from sensor to platform. -- [x] Integration 功能: 新增等震圖. -- [x] Integration 功能: 模擬地震 (用於測試自動化)。 -- [x] Integration 服務: 另存等震圖. -- [x] Integration 服務: 重新載入整合. -- [x] ExptechTW 訂閱功能: 使用WebSocket作為地震速報來源,減少流量及延遲。 (Exptech VIP 資格) -- [ ] ExptechTW 訂閱功能: TREM-Net EEW、RTS...等。 (Exptech VIP 資格) - -
-
- - ## 贊助 | Buy me a coffee | LINE Bank | JKao Pay | @@ -153,7 +163,9 @@ ## 授權 -AGPL-3.0 license +AGPL-3.0 license. + +**2024-08-15 Agreement reached with ExpTech Studio.** [releases-shield]: https://img.shields.io/github/release/gaojiafamily/ha-trem.svg?style=for-the-badge diff --git a/custom_components/trem/__init__.py b/custom_components/trem/__init__.py index 73fdd92..0862c0e 100644 --- a/custom_components/trem/__init__.py +++ b/custom_components/trem/__init__.py @@ -23,7 +23,6 @@ CLIENT_NAME, CONF_NODE, CONF_PASS, - DEFAULT_NAME, DOMAIN, HTTPS_API_COORDINATOR_UPDATE_INTERVAL, MIN_HA_MAJ_VER, diff --git a/custom_components/trem/binary_sensor.py b/custom_components/trem/binary_sensor.py index 90a0935..bbd600f 100644 --- a/custom_components/trem/binary_sensor.py +++ b/custom_components/trem/binary_sensor.py @@ -7,7 +7,10 @@ import logging from typing import Any -from homeassistant.components.binary_sensor import BinarySensorEntity +from homeassistant.components.binary_sensor import ( + BinarySensorDeviceClass, + BinarySensorEntity, +) from homeassistant.config_entries import ConfigEntry from homeassistant.const import ATTR_ATTRIBUTION, CONF_EMAIL from homeassistant.core import HomeAssistant, callback @@ -18,7 +21,6 @@ ATTRIBUTION, DOMAIN, MANUFACTURER, - MONITOR_ICON, TREM_COORDINATOR, TREM_NAME, ) @@ -82,14 +84,13 @@ def __init__( def update(self): """Schedule a custom update via the common entity update service.""" + self._attr_value = {} self._attributes[ATTR_NODE] = self._coordinator.station rtsData: dict = self._coordinator.rtsData if "int" in rtsData: rts: list = rtsData["int"] - if len(rts) == 0: - self._attr_value = {} - else: + if len(rts) > 0: for k in rts: self._attr_value[k["code"]] = k["i"] @@ -116,23 +117,23 @@ def available(self): return True @property - def state(self) -> bool: + def is_on(self) -> bool: """Return the state of the sensor.""" return self._state - @property - def icon(self) -> str: - """Icon to use in the frontend, if any.""" - - return MONITOR_ICON - @property def unit_of_measurement(self): """Return the unit of measurement.""" return None + @property + def device_class(self): + """Return the device class.""" + + return BinarySensorDeviceClass.VIBRATION + @property def extra_state_attributes(self) -> dict[str, Any]: """Return extra attributes.""" diff --git a/custom_components/trem/config_flow.py b/custom_components/trem/config_flow.py index 0a703f5..82321a6 100644 --- a/custom_components/trem/config_flow.py +++ b/custom_components/trem/config_flow.py @@ -181,7 +181,6 @@ def __init__(self) -> None: self._node: str | None = None self._email: str | None = None self._password: str | None = None - self._token: str | None = None self._preserve_data: bool | None = None self._draw_map: bool | None = None @@ -291,7 +290,6 @@ async def async_step_cloud( self._email = user_input.get(CONF_EMAIL, "") self._password = user_input.get(CONF_PASSWORD, "") self._region = user_input.get(CONF_REGION, None) - # self._token = user_input.get(CONF_TOKEN, "") self._preserve_data = user_input.get(CONF_PRESERVE_DATA, False) self._draw_map = user_input.get(CONF_DRAW_MAP, False) @@ -300,7 +298,6 @@ async def async_step_cloud( vol.Required(CONF_EMAIL, default=self._email): str, vol.Required(CONF_PASSWORD, default=self._password): str, vol.Required(CONF_REGION, default=self._region): int, - # vol.Optional(CONF_TOKEN, default=self._token): str, vol.Optional(CONF_PRESERVE_DATA, default=self._preserve_data): bool, vol.Optional(CONF_DRAW_MAP, default=self._draw_map): bool, } @@ -324,7 +321,6 @@ def __init__(self, config_entry: ConfigEntry) -> None: self._node: str | None = None self._email: str | None = None self._password: str | None = None - self._token: str | None = None self._preserve_data: bool | None = None self._draw_map: bool | None = None @@ -416,7 +412,6 @@ async def async_step_cloud( self._region = self._config.options.get(CONF_REGION, None) self._email = self._config.options.get(CONF_EMAIL, "") self._password = self._config.options.get(CONF_PASSWORD, "") - self._token = self._config.options.get(CONF_TOKEN, "") self._preserve_data = self._config.options.get(CONF_PRESERVE_DATA, False) self._draw_map = self._config.options.get(CONF_DRAW_MAP, False) @@ -424,7 +419,6 @@ async def async_step_cloud( { vol.Required(CONF_EMAIL, default=self._email): str, vol.Optional(CONF_PASSWORD, default=self._password): str, - # vol.Optional(CONF_TOKEN, default=self._token): str, vol.Optional(CONF_PRESERVE_DATA, default=self._preserve_data): bool, vol.Optional(CONF_DRAW_MAP, default=self._draw_map): bool, } diff --git a/custom_components/trem/const.py b/custom_components/trem/const.py index 3379e21..5b85e05 100644 --- a/custom_components/trem/const.py +++ b/custom_components/trem/const.py @@ -5,21 +5,20 @@ # Initialize DEFAULT_NAME = "TREM" DEFAULT_ICON = "mdi:checkbox-blank-outline" -MONITOR_ICON = "mdi:monitor-eye" TSUNAMI_ICON = "mdi:tsunami" DOMAIN = "trem" PLATFORMS = ["binary_sensor", "image", "sensor"] # Proj CLIENT_NAME = "TREM-HA" -PROJECT_URL = "https://github.com/J1A-T13N/ha-trem/" +PROJECT_URL = "https://github.com/gaojiafamily/ha-trem/" ISSUE_URL = f"{PROJECT_URL}issues" # Version MIN_HA_MAJ_VER = 2024 MIN_HA_MIN_VER = 3 __min_ha_version__ = f"{MIN_HA_MAJ_VER}.{MIN_HA_MIN_VER}.0" -__version__ = "1.3.2" +__version__ = "1.3.3" # Earthquake Icon EARTHQUAKE_ICON = { @@ -50,6 +49,7 @@ ATTR_EST = "estimate" ATTR_CODE = "region" ATTR_NODE = "API_Node" +ATTR_PROTOCOL = "protocol" ATTR_EQDATA = "earthquake_data" EARTHQUAKE_ATTR = [ ATTR_ID, @@ -62,7 +62,6 @@ ATTR_TIME, ATTR_INT, ATTR_EST, - ATTR_CODE, ] TSUNAMI_ATTR = [ ATTR_ID, @@ -77,18 +76,14 @@ CONF_PRESERVE_DATA = "preserve_data" # Coordinator -DPIP_COORDINATOR = "dpip_coordinator" TREM_COORDINATOR = "trem_coordinator" TREM_NAME = "trem_name" UPDATE_LISTENER = "update_listener" HTTPS_API_COORDINATOR_UPDATE_INTERVAL = timedelta(seconds=5) WEBSOCKET_COORDINATOR_UPDATE_INTERVAL = timedelta(seconds=1) -DPIP_COORDINATOR_UPDATE_INTERVAL = timedelta(seconds=60) # REST -HA_USER_AGENT = ( - "TREM custom integration for Home Assistant (https://github.com/j1a-t13n/ha-trem)" -) +HA_USER_AGENT = "TREM custom integration for Home Assistant (https://github.com/gaojiafamily/ha-trem)" BASE_URLS = { "tainan_cache_limit": "https://api-1.exptech.com.tw", "tainan_cache": "https://api-1.exptech.dev", @@ -117,7 +112,7 @@ # STRINGS CUSTOMIZE_PLAN = "Customize (Free Plan)" FREE_PLAN = "Http(s) API (Free Plan)" -SUBSCRIBE_PLAN = "WebSocket (Subscribe Plan)" +SUBSCRIBE_PLAN = "Websocket (Subscribe Plan)" WS_MSG_TOO_BIG = ( f"Please consider increasing message size with `{DEFAULT_MAX_MSG_SIZE}`." diff --git a/custom_components/trem/image.py b/custom_components/trem/image.py index 8999e85..a98d1e4 100644 --- a/custom_components/trem/image.py +++ b/custom_components/trem/image.py @@ -13,7 +13,7 @@ from homeassistant.components.image import ImageEntity from homeassistant.config_entries import ConfigEntry -from homeassistant.const import ATTR_ATTRIBUTION, CONF_EMAIL, CONF_REGION +from homeassistant.const import ATTR_ATTRIBUTION, CONF_REGION from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity import DeviceInfo from homeassistant.util import dt as dt_util diff --git a/custom_components/trem/manifest.json b/custom_components/trem/manifest.json index 057bc25..bc1bb02 100644 --- a/custom_components/trem/manifest.json +++ b/custom_components/trem/manifest.json @@ -2,10 +2,10 @@ "codeowners": ["@J1A-T13N", "@watermelon1024"], "domain": "trem", "name": "Taiwan Real-time Earthquake Monitoring", - "version": "1.3.2", + "version": "1.3.3", "config_flow": true, - "documentation": "https://github.com/J1A-T13N/ha-trem/blob/master/README.md", - "issue_tracker": "https://github.com/J1A-T13N/ha-trem/issues", + "documentation": "https://github.com/gaojiafamily/ha-trem/blob/master/README.md", + "issue_tracker": "https://github.com/gaojiafamily/ha-trem/issues", "requirements": [ "geopandas==0.14.4", "matplotlib==3.9.0", diff --git a/custom_components/trem/sensor.py b/custom_components/trem/sensor.py index 7ad7b7e..c412593 100644 --- a/custom_components/trem/sensor.py +++ b/custom_components/trem/sensor.py @@ -26,6 +26,7 @@ ATTR_LOC, ATTR_MAG, ATTR_NODE, + ATTR_PROTOCOL, ATTR_TIME, ATTRIBUTION, CONF_DRAW_MAP, @@ -199,8 +200,9 @@ def update(self): else: self._attr_value[ATTR_EST] = 0 - self._attr_value[ATTR_CODE] = self._name + self._attributes[ATTR_PROTOCOL] = self._coordinator.protocol self._attributes[ATTR_NODE] = self._coordinator.station + self._attributes[ATTR_CODE] = self._name if not self._preserve_data: self._attr_value = {} diff --git a/custom_components/trem/translations/en.json b/custom_components/trem/translations/en.json index 36e4a53..96a5d35 100644 --- a/custom_components/trem/translations/en.json +++ b/custom_components/trem/translations/en.json @@ -26,7 +26,7 @@ "description": "This plan data is updated every 5 second.\nPlease read the following Terms of Service (https://exptech.com.tw/tos) carefully." }, "cloud": { - "title": "WebSocket (Subscribe plan)", + "title": "Websocket (Subscribe plan)", "data": { "region": "Monitoring region", "token": "FCM Token", @@ -63,7 +63,7 @@ "description": "This plan data is updated every 5 second.\nPlease read the following Terms of Service (https://exptech.com.tw/tos) carefully." }, "cloud": { - "title": "WebSocket (Subscribe plan)", + "title": "Websocket (Subscribe plan)", "data": { "region": "Monitoring region", "email": "Exptech email", diff --git a/custom_components/trem/translations/zh-Hant.json b/custom_components/trem/translations/zh-Hant.json index 0dd48d7..6f75d97 100644 --- a/custom_components/trem/translations/zh-Hant.json +++ b/custom_components/trem/translations/zh-Hant.json @@ -35,7 +35,7 @@ "draw_map": "\u7e6a\u88fd\u5730\u5716\u0020\u0028\u6b64\u529f\u80fd\u6703\u5f71\u97ff\u6548\u80fd\u0029" }, "description": "\u6b64\u65b9\u6848\u6bcf\u0031\u79d2\u66f4\u65b0\u4e00\u6b21\u6578\u64da\n\u8acb\u9075\u5b88\u4f7f\u7528\u689d\u6b3e\u0028\u0068\u0074\u0074\u0070\u0073\u003a\u002f\u002f\u0065\u0078\u0070\u0074\u0065\u0063\u0068\u002e\u0063\u006f\u006d\u002e\u0074\u0077\u002f\u0074\u006f\u0073\u0029\n\u524d\u5f80\u0020\u0068\u0074\u0074\u0070\u0073\u003a\u002f\u002f\u0065\u0078\u0070\u0074\u0065\u0063\u0068\u002e\u0063\u006f\u006d\u002e\u0074\u0077\u002f\u0070\u0072\u0069\u0063\u0069\u006e\u0067\u0020\u8a02\u95b1", - "title": "\u0057\u0065\u0062\u0053\u006f\u0063\u006b\u0065\u0074\u0020\u0028\u8a02\u95b1\u65b9\u6848\u0029" + "title": "\u0057\u0065\u0062\u0073\u006f\u0063\u006b\u0065\u0074\u0020\u0028\u8a02\u95b1\u65b9\u6848\u0029" } } }, @@ -72,7 +72,7 @@ "draw_map": "\u7e6a\u88fd\u5730\u5716\u0020\u0028\u6b64\u529f\u80fd\u6703\u5f71\u97ff\u6548\u80fd\u0029" }, "description": "\u6b64\u65b9\u6848\u6bcf\u0031\u79d2\u66f4\u65b0\u4e00\u6b21\u6578\u64da\n\u8acb\u9075\u5b88\u4f7f\u7528\u689d\u6b3e\u0028\u0068\u0074\u0074\u0070\u0073\u003a\u002f\u002f\u0065\u0078\u0070\u0074\u0065\u0063\u0068\u002e\u0063\u006f\u006d\u002e\u0074\u0077\u002f\u0074\u006f\u0073\u0029\n\u524d\u5f80\u0020\u0068\u0074\u0074\u0070\u0073\u003a\u002f\u002f\u0065\u0078\u0070\u0074\u0065\u0063\u0068\u002e\u0063\u006f\u006d\u002e\u0074\u0077\u002f\u0070\u0072\u0069\u0063\u0069\u006e\u0067\u0020\u8a02\u95b1", - "title": "\u0057\u0065\u0062\u0053\u006f\u0063\u006b\u0065\u0074\u0020\u0028\u8a02\u95b1\u65b9\u6848\u0029" + "title": "\u0057\u0065\u0062\u0073\u006f\u0063\u006b\u0065\u0074\u0020\u0028\u8a02\u95b1\u65b9\u6848\u0029" } } } diff --git a/custom_components/trem/update_coordinator.py b/custom_components/trem/update_coordinator.py index e97ef59..c91128a 100644 --- a/custom_components/trem/update_coordinator.py +++ b/custom_components/trem/update_coordinator.py @@ -51,7 +51,7 @@ def __init__( """Initialize the data object.""" self._hass = hass - self._update_interval = update_interval + self._init_update_interval = update_interval self.connection: WebSocketConnection | None = None self.session = async_get_clientsession(hass) @@ -79,47 +79,44 @@ def __init__( else: station, base_url = random.choice(list(BASE_URLS.items())) self.station: str = station + self._tmpStation: str | None = None + self._tmpUrl: str | None = None self._base_url: str = ( - base_url - if self.plan == CUSTOMIZE_PLAN - else f"{base_url}/api/v1/eq/eew?type=cwa" + f"{base_url}/api/v1/eq/eew?type=cwa" if self.plan == FREE_PLAN else base_url ) - self._protocol = "Http(s)" + self.protocol = "Http(s)" self.retry: int = 0 self.earthquakeData: dict | list = {} self.rtsData: dict = {} self.tsunamiData: dict = {} if self.plan == SUBSCRIBE_PLAN: - self._protocol = "Websocket" + self.protocol = "Websocket" super().__init__( hass, _LOGGER, - name=self._protocol, + name=self.protocol, update_method=self._async_update_websocket, - update_interval=self._update_interval, + update_interval=self._init_update_interval, ) else: super().__init__( hass, _LOGGER, - name=self._protocol, + name=self.protocol, update_method=self._async_update_http, - update_interval=self._update_interval, + update_interval=self._init_update_interval, ) _LOGGER.debug( - f"{self._protocol}: Fetching data from {self.station}, EEW(location: {self.region}) is monitoring..." # noqa: G004 + f"{self.protocol}: Fetching data from {self.station}, EEW(location: {self.region}) is monitoring..." # noqa: G004 ) - async def _async_update_http(self): - """Poll earthquake data from Http(s) api.""" + async def _fetch_data(self, url=None) -> ClientResponse: + """Fetch earthquake data from the Http API.""" - if self.retry >= 5: - self.update_interval = timedelta(seconds=86400) - raise UpdateFailed + self.protocol = "Http(s)" - response: ClientResponse | None = None payload = {} headers = { ACCEPT: CONTENT_TYPE_JSON, @@ -127,14 +124,23 @@ async def _async_update_http(self): USER_AGENT: HA_USER_AGENT, } + return await self.session.request( + method=METH_GET, + url=self._base_url if url is None else url, + data=json.dumps(payload), + headers=headers, + timeout=REQUEST_TIMEOUT, + ) + + async def _async_update_http(self): + """Poll earthquake data from Http(s) api.""" + + if self.retry >= 5: + self.update_interval = timedelta(seconds=86400) + raise UpdateFailed + try: - response = await self.session.request( - method=METH_GET, - url=self._base_url, - data=json.dumps(payload), - headers=headers, - timeout=REQUEST_TIMEOUT, - ) + response = await self._fetch_data() except ClientConnectorError as ex: self.retry = self.retry + 1 @@ -164,12 +170,18 @@ async def _async_update_http(self): ) if self.retry == 0: - self.update_interval = self._update_interval + self.update_interval = self._init_update_interval if self.retry > 0: self.update_interval = timedelta(seconds=60) - await self.switch_node() + station, base_url = await self.get_route() + self.station = station + self._base_url = base_url + _LOGGER.warning( + f"Switch Station {self.station} to {station}, Try to fetching data..." + ) + raise UpdateFailed return self @@ -197,6 +209,9 @@ async def _async_update_websocket(self): else: isReady = self.connection.ready() if isReady: + self.retry = 0 + self.protocol = "Websocket" + self.earthquakeData = self.connection.earthquakeData self.rtsData = self.connection.rtsData self.tsunamiData = self.connection.tsunamiData @@ -209,34 +224,68 @@ async def _async_update_websocket(self): "Your VIP membership has expired, Please re-subscribe.", ) else: + self.retry = self.retry + 1 + if not self.connection.is_running: self.connection = None _LOGGER.warning("Reconnecting websocket...") - self.retry = self.retry + 1 - raise UpdateFailed + + if self.retry == 0: + self.update_interval = self._init_update_interval + + if self.retry > 0: + self.update_interval = timedelta(seconds=5) + + if self._tmpUrl is None: + station, url = await self.get_route("Http(s)") + self._tmpStation = station + self._tmpUrl = f"{url}/api/v1/eq/eew?type=cwa" + + try: + _LOGGER.debug( + f"Websocket is unavailable, Fetching data from Http(s) API({self._tmpStation})..." # noqa: G004 + ) + response = await self._fetch_data(self._tmpUrl) + except ClientConnectorError as ex: + _LOGGER.error( + f"Failed fetching data from Http(s) API({self._tmpStation}), {ex.strerror}. Retry {self.retry}/5..." # noqa: G004 + ) + except TimeoutError as ex: + _LOGGER.error( + f"Failed fetching data from Http(s) API({self._tmpStation}), {ex.strerror}. Retry {self.retry}/5..." # noqa: G004 + ) + except Exception: + _LOGGER.exception( + f"An unexpected exception occurred fetching the data from Http(s) API({self._tmpStation})." # noqa: G004 + ) + else: + if response.ok: + self.earthquakeData = await response.json() + return self + + _LOGGER.error( + f"Failed fetching data from Http(s) API({self._tmpStation}), (HTTP Status Code = {response.status}). Retry {self.retry}/5..." # noqa: G004 + ) + + self._tmpUrl = None + raise UpdateFailed return self - async def switch_node(self) -> str | None: - """Switch the Http(s) api node for fetching earthquake data.""" + async def get_route(self, protocol="Websocket"): + """Random the node for fetching data.""" if self.plan == CUSTOMIZE_PLAN: return None - tmpStations: dict = BASE_URLS.items() - if self.plan == SUBSCRIBE_PLAN: + tmpStations = BASE_URLS.items() + if self.plan == SUBSCRIBE_PLAN and protocol == "Websocket": tmpStations = BASE_WS.items() - tmpStations.pop(self.station) - - station, base_url = random.choice(list(tmpStations)) - self.station = station - self._base_url = base_url - - _LOGGER.warning( - f"Switch Station {self.station} to {station}, Try to fetching data..." - ) + tmpStations = { + k: v for k, v in tmpStations if k != self.station + } # tmpStations.pop(self.station) - return station + return random.choice(list(tmpStations.items())) async def _notify_message(