diff --git a/custom_components/opencwb/config_flow.py b/custom_components/opencwb/config_flow.py index d9a88f0..c00ea42 100755 --- a/custom_components/opencwb/config_flow.py +++ b/custom_components/opencwb/config_flow.py @@ -21,8 +21,8 @@ DEFAULT_NAME, DOMAIN, FORECAST_MODES, - FORECAST_MODE_ONECALL_HOURLY, - FORECAST_MODE_ONECALL_DAILY +# FORECAST_MODE_ONECALL_HOURLY, +# FORECAST_MODE_ONECALL_DAILY ) from .core.weatherapi12.uris import ONE_CALL_URI @@ -60,9 +60,9 @@ async def async_step_user(self, user_input=None): location_name) + "-" + user_input[CONF_MODE]) self._abort_if_unique_id_configured() - if (location_id != ONE_CALL_URI and - user_input[CONF_MODE] == FORECAST_MODE_ONECALL_DAILY): - user_input[CONF_MODE] = FORECAST_MODE_ONECALL_HOURLY + #if (location_id != ONE_CALL_URI and + # user_input[CONF_MODE] == FORECAST_MODE_ONECALL_DAILY): + # user_input[CONF_MODE] = FORECAST_MODE_ONECALL_HOURLY try: api_online = await _is_ocwb_api_online( @@ -121,9 +121,9 @@ async def async_step_init(self, user_input=None): location_id = _is_supported_city( self.config_entry.data.get(CONF_API_KEY), self.config_entry.data.get(CONF_LOCATION_NAME)) - if (location_id != ONE_CALL_URI and - user_input[CONF_MODE] == FORECAST_MODE_ONECALL_DAILY): - user_input[CONF_MODE] = FORECAST_MODE_ONECALL_HOURLY + #if (location_id != ONE_CALL_URI and + # user_input[CONF_MODE] == FORECAST_MODE_ONECALL_DAILY): + # user_input[CONF_MODE] = FORECAST_MODE_ONECALL_HOURLY return self.async_create_entry(title="", data=user_input) diff --git a/custom_components/opencwb/const.py b/custom_components/opencwb/const.py index 1b4fae7..fe83489 100755 --- a/custom_components/opencwb/const.py +++ b/custom_components/opencwb/const.py @@ -20,7 +20,7 @@ ATTR_FORECAST_PRECIPITATION_PROBABILITY, # ATTR_FORECAST_PRESSURE, ATTR_FORECAST_TEMP, - # ATTR_FORECAST_TEMP_LOW, + ATTR_FORECAST_TEMP_LOW, ATTR_FORECAST_TIME, ATTR_FORECAST_WIND_BEARING, ATTR_FORECAST_WIND_SPEED, @@ -93,7 +93,7 @@ FORECAST_MODE_HOURLY, FORECAST_MODE_DAILY, FORECAST_MODE_ONECALL_HOURLY, -# FORECAST_MODE_ONECALL_DAILY, + FORECAST_MODE_ONECALL_DAILY, ] DEFAULT_FORECAST_MODE = FORECAST_MODE_ONECALL_DAILY @@ -106,7 +106,7 @@ ATTR_API_WIND_BEARING, ATTR_API_HUMIDITY, # ATTR_API_PRESSURE, - ATTR_API_CLOUDS, + # ATTR_API_CLOUDS, # ATTR_API_RAIN, # ATTR_API_SNOW, # ATTR_API_PRECIPITATION_KIND, @@ -120,7 +120,7 @@ ATTR_FORECAST_PRECIPITATION_PROBABILITY, # ATTR_FORECAST_PRESSURE, ATTR_FORECAST_TEMP, - # ATTR_FORECAST_TEMP_LOW, + ATTR_FORECAST_TEMP_LOW, ATTR_FORECAST_TIME, ATTR_FORECAST_WIND_BEARING, ATTR_FORECAST_WIND_SPEED, @@ -182,7 +182,7 @@ # SENSOR_UNIT: PRESSURE_HPA, # SENSOR_DEVICE_CLASS: SensorDeviceClass.PRESSURE, # }, - ATTR_API_CLOUDS: {SENSOR_NAME: "Cloud coverage", SENSOR_UNIT: PERCENTAGE}, + # ATTR_API_CLOUDS: {SENSOR_NAME: "Cloud coverage", SENSOR_UNIT: PERCENTAGE}, # ATTR_API_RAIN: {SENSOR_NAME: "Rain", SENSOR_UNIT: UnitOfLength.MILLIMETERS}, # ATTR_API_SNOW: {SENSOR_NAME: "Snow", SENSOR_UNIT: UnitOfLength.MILLIMETERS}, # ATTR_API_PRECIPITATION_KIND: {SENSOR_NAME: "Precipitation kind"}, @@ -213,11 +213,11 @@ SENSOR_UNIT: UnitOfTemperature.CELSIUS, SENSOR_DEVICE_CLASS: SensorDeviceClass.TEMPERATURE, }, - # ATTR_FORECAST_TEMP_LOW: { - # SENSOR_NAME: "Temperature Low", - # SENSOR_UNIT: UnitOfTemperature.CELSIUS, - # SENSOR_DEVICE_CLASS: SensorDeviceClass.TEMPERATURE, - # }, + ATTR_FORECAST_TEMP_LOW: { + SENSOR_NAME: "Temperature Low", + SENSOR_UNIT: UnitOfTemperature.CELSIUS, + SENSOR_DEVICE_CLASS: SensorDeviceClass.TEMPERATURE, + }, ATTR_FORECAST_TIME: { SENSOR_NAME: "Time", SENSOR_DEVICE_CLASS: SensorDeviceClass.TIMESTAMP, diff --git a/custom_components/opencwb/core/constants.py b/custom_components/opencwb/core/constants.py index 10549d3..5f4291d 100644 --- a/custom_components/opencwb/core/constants.py +++ b/custom_components/opencwb/core/constants.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -OCWB_VERSION = (1, 0, 0) +OCWB_VERSION = (1, 2, 0) AGRO_API_VERSION = (1, 0, 0) AIRPOLLUTION_API_VERSION = (1, 0, 0) ALERT_API_VERSION = (1, 0, 0) diff --git a/custom_components/opencwb/core/utils/opendata_cwb.py b/custom_components/opencwb/core/utils/opendata_cwb.py index 6cb00ff..1201bb9 100755 --- a/custom_components/opencwb/core/utils/opendata_cwb.py +++ b/custom_components/opencwb/core/utils/opendata_cwb.py @@ -50,14 +50,14 @@ def _get_weather(the_dict, index, wx_index, last_pop, mode): if element_value is None: continue - if "WeatherDescription" == i[elementname] or "\u5929\u6c23\u9810\u5831\u7d9c\u5408\u63cf\u8ff0" == i[elementname]: + if i[elementname] in ["WeatherDescription", "\u5929\u6c23\u9810\u5831\u7d9c\u5408\u63cf\u8ff0"]: if value_str in element_value[0]: value["weather"][0]["description"] = element_value[0][value_str] value["weather"][0]["icon"] = "" else: value["weather"][0]["description"] = list(element_value[0].values())[0] value["weather"][0]["icon"] = "" - elif "Wx" == i[elementname] or "\u5929\u6c23\u73fe\u8c61" == i[elementname]: + elif i[elementname] in ["Wx", "\u5929\u6c23\u73fe\u8c61"]: if value_str in element_value[0]: value["weather"][0]["main"] = element_value[0][value_str] value["weather"][0]["id"] = int(element_value[1][value_str]) @@ -75,68 +75,68 @@ def _get_weather(the_dict, index, wx_index, last_pop, mode): pop = "0" value["pop"] = float(int(pop)/100) break - elif "AT" == i[elementname] or "\u9ad4\u611f\u6eab\u5ea6" == i[elementname]: + elif i[elementname]in ["AT", "\u9ad4\u611f\u6eab\u5ea6"]: if value_str in element_value[0]: value["main"]["feels_like"] = int(element_value[0][value_str]) else: value["main"]["feels_like"] = int(list(element_value[0].values())[0]) - elif "MaxAT" == i[elementname] or "\u6700\u9ad8\u9ad4\u611f\u6eab\u5ea6" == i[elementname]: + elif i[elementname] in ["MaxAT", "\u6700\u9ad8\u9ad4\u611f\u6eab\u5ea6"]: if value_str in element_value[0]: value["main"]["feels_like"] = int(element_value[0][value_str]) value["feels_like"]["max"] = int(element_value[0][value_str]) else: - value["main"]["feels_like"] = int(list(element_value[0].vaules())[0]) + value["main"]["feels_like"] = int(list(element_value[0].values())[0]) value["feels_like"]["max"] = int(list(element_value[0].values())[0]) - elif "MinAT" == i[elementname] or "\u6700\u4f4e\u9ad4\u611f\u6eab\u5ea6" == i[elementname]: + elif i[elementname] in ["MinAT", "\u6700\u4f4e\u9ad4\u611f\u6eab\u5ea6"]: if value_str in element_value[0]: value["feels_like"]["min"] = int(element_value[0][value_str]) else: value["feels_like"]["min"] = int(list(element_value[0].values())[0]) - elif "UVI" == i[elementname] or "\u7d2b\u5916\u7dda\u6307\u6578" == i[elementname]: + elif i[elementname] in ["UVI", "\u7d2b\u5916\u7dda\u6307\u6578"]: value["uvi"] = 0 - for j in i["time"]: + for j in i[time_str]: if start_time == j[starttime]: if value_str in element_value[0]: value["uvi"] = int(j[elementvalue][0][value_str]) else: value["uvi"] = int(list(j[elementvalue][0].values())[0]) break - elif "T" == i[elementname] or "\u6eab\u5ea6" == i[elementname]: + elif i[elementname] in ["T", "\u6eab\u5ea6", "\u5e73\u5747\u6eab\u5ea6"]: if value_str in element_value[0]: value["main"]["temp"] = int(element_value[0][value_str]) else: value["main"]["temp"] = int(list(element_value[0].values())[0]) - elif "MaxT" == i[elementname] or "\u6700\u9ad8\u6eab\u5ea6" == i[elementname]: + elif i[elementname] in ["MaxT", "\u6700\u9ad8\u6eab\u5ea6"]: if value_str in element_value[0]: value["main"]["temp_max"] = int(element_value[0][value_str]) else: value["main"]["temp_max"] = int(list(element_value[0].values())[0]) - elif "MinT" == i[elementname] or "\u6700\u4f4e\u6eab\u5ea6" == i[elementname]: + elif i[elementname] in ["MinT", "\u6700\u4f4e\u6eab\u5ea6"]: if value_str in element_value[0]: value["main"]["temp_min"] = int(element_value[0][value_str]) else: value["main"]["temp_min"] = int(list(element_value[0].values())[0]) - elif "Td" == i[elementname] or "\u9732\u9ede\u6eab\u5ea6" == i[elementname]: + elif i[elementname] in ["Td", "\u9732\u9ede\u6eab\u5ea6", "\u5e73\u5747\u9732\u9ede\u6eab\u5ea6"]: if value_str in element_value[0]: value["calc"]["dewpoint"] = int(element_value[0][value_str]) * 100 else: value["calc"]["dewpoint"] = int(list(element_value[0].values())[0]) * 100 - elif "RH" == i[elementname] or "\u76f8\u5c0d\u6fd5\u5ea6" == i[elementname]: + elif i[elementname] in ["RH", "\u76f8\u5c0d\u6fd5\u5ea6"]: if value_str in element_value[0]: value["humidity"] = int(element_value[0][value_str]) else: value["humidity"] = int(list(element_value[0].values())[0]) - elif "MinCI" == i[elementname] or "\u8212\u9069\u5ea6\u6307\u6578" == i[elementname]: + elif i[elementname] in ["MinCI", "\u8212\u9069\u5ea6\u6307\u6578"]: if value_str in element_value[0]: value["calc"]["humidex"] = int(element_value[0][value_str]) else: value["calc"]["humidex"] = int(list(element_value[0].values())[0]) - elif "MaxCI" == i[elementname] or "\u8212\u9069\u5ea6\u6307\u6578" == i[elementname]: + elif i[elementname] in ["MaxCI", "\u8212\u9069\u5ea6\u6307\u6578"]: if value_str in element_value[0]: value["calc"]["heatindex"] = int(element_value[0][value_str]) else: value["calc"]["heatindex"] = int(list(element_value[0].values())[0]) - elif "WS" == i[elementname] or "\u98a8\u901f" == i[elementname]: + elif i[elementname] in ["WS", "\u98a8\u901f"]: if value_str in element_value[0]: value["wind_speed"] = int(''.join( k for k in element_value[0][value_str] if k.isdigit())) @@ -147,7 +147,7 @@ def _get_weather(the_dict, index, wx_index, last_pop, mode): k for k in list(element_value[0].values())[0] if k.isdigit())) value["wind_gust"] = int(''.join( c for c in list(element_value[0].values())[1] if c.isdigit())) - elif "WD" == i[elementname] or "\u98a8\u5411" == i[elementname]: + elif i[elementname] in ["WD", "\u98a8\u5411"]: if value_str in element_value[0]: value["wind_deg"] = element_value[0][value_str] else: diff --git a/custom_components/opencwb/core/weatherapi12/weather_manager.py b/custom_components/opencwb/core/weatherapi12/weather_manager.py index e4d49c3..306ff8b 100755 --- a/custom_components/opencwb/core/weatherapi12/weather_manager.py +++ b/custom_components/opencwb/core/weatherapi12/weather_manager.py @@ -64,8 +64,8 @@ def weather_at_place(self, name, interval): :param name: the location's toponym :type name: str - :param interval: the granularity of the forecast, among `3h` and 'daily' - :type interval: str among `3h` and 'daily' + :param interval: the granularity of the forecast, among `hourly` and 'daily' + :type interval: str among `hourly` and 'daily' :returns: an *Observation* instance or ``None`` if no weather data is available :raises: *ParseResponseException* when OCWB Weather API responses' data @@ -78,7 +78,7 @@ def weather_at_place(self, name, interval): if loc_id is None: raise ValueError("%s is not support location".format(name)) params = {'locationName': name} - if interval == '3h': + if interval == 'hourly': uri = loc_id elif interval == 'daily': uri = loc_id[0:loc_id.rindex("-") + 1] + str( @@ -294,8 +294,8 @@ def forecast_at_place(self, name, interval, limit=None): :param name: the location's toponym :type name: str - :param interval: the granularity of the forecast, among `3h` and 'daily' - :type interval: str among `3h` and 'daily' + :param interval: the granularity of the forecast, among `hourly` and 'daily' + :type interval: str among `hourly` and 'daily' :param limit: the maximum number of *Weather* items to be retrieved (default is ``None``, which stands for any number of items) :type limit: int or ``None`` @@ -317,7 +317,7 @@ def forecast_at_place(self, name, interval, limit=None): params = {'locationName': urllib.parse.quote_plus(name)} if limit is not None: params['cnt'] = limit - if interval == '3h': + if interval == 'hourly': uri = loc_id elif interval == 'daily': uri = loc_id[0:loc_id.rindex("-") + 1] + str( @@ -343,8 +343,8 @@ def forecast_at_coords(self, lat, lon, interval, limit=None): :type lat: int/float :param lon: location's longitude, must be between -180.0 and 180.0 :type lon: int/float - :param interval: the granularity of the forecast, among `3h` and 'daily' - :type interval: str among `3h` and 'daily' + :param interval: the granularity of the forecast, among `hourly` and 'daily' + :type interval: str among `hourly` and 'daily' :param limit: the maximum number of *Weather* items to be retrieved (default is ``None``, which stands for any number of items) :type limit: int or ``None`` @@ -364,7 +364,7 @@ def forecast_at_coords(self, lat, lon, interval, limit=None): params = {'lon': lon, 'lat': lat} if limit is not None: params['cnt'] = limit - if interval == '3h': + if interval == 'hourly': uri = THREE_HOURS_FORECAST_URI elif interval == 'daily': uri = DAILY_FORECAST_URI @@ -387,8 +387,8 @@ def forecast_at_id(self, id, interval, limit=None): :param id: the location's city ID :type id: int - :param interval: the granularity of the forecast, among `3h` and 'daily' - :type interval: str among `3h` and 'daily' + :param interval: the granularity of the forecast, among `hourly` and 'daily' + :type interval: str among `hourly` and 'daily' :param limit: the maximum number of *Weather* items to be retrieved (default is ``None``, which stands for any number of items) :type limit: int or ``None`` @@ -409,7 +409,7 @@ def forecast_at_id(self, id, interval, limit=None): params = {'id': id} if limit is not None: params['cnt'] = limit - if interval == '3h': + if interval == 'hourly': uri = THREE_HOURS_FORECAST_URI elif interval == 'daily': uri = DAILY_FORECAST_URI @@ -536,7 +536,7 @@ def _retrieve_station_history(self, station_ID, limit, interval): return sh def one_call( - self, lat: Union[int, float], lon: Union[int, float], loc: Union[str, None], **kwargs + self, lat: Union[int, float], lon: Union[int, float], loc: Union[str, None], intvl: Union[str, None], **kwargs ) -> one_call.OneCall: """ Queries the OCWB Weather API with one call for current weather information and forecast for the @@ -554,7 +554,7 @@ def one_call( :type lon: int/float :param lon: location's name :type lon: str or None - :param intvl: internal + :param intvl: interval :type intrl: str or None :returns: a *OneCall* instance or ``None`` if the data is not available for the specified location @@ -567,15 +567,16 @@ def one_call( loc_id = self.supported_city(loc) loc = self.remove_city_name(loc) - uri = ONE_CALL_URI - if loc_id != ONE_CALL_URI: + uri = loc_id + if intvl == "daily": uri = uri[0:uri.rindex("-") + 1] + str( int(uri[uri.rindex("-") + 1:]) + 2).zfill(3) params = { 'lon': lon, 'lat': lat, - 'locationId': loc_id, - 'locationName': loc} +# 'locationId': loc_id, + 'locationName': loc, + 'interval': intvl} for key , value in kwargs.items(): if key == 'exclude': params['exclude'] = value diff --git a/custom_components/opencwb/manifest.json b/custom_components/opencwb/manifest.json index 140dc92..5cf24c6 100755 --- a/custom_components/opencwb/manifest.json +++ b/custom_components/opencwb/manifest.json @@ -2,7 +2,7 @@ "domain": "opencwb", "name": "OpenCWA", "config_flow": true, - "version": "1.1.0", + "version": "1.2.0", "documentation": "https://opendata.cwa.gov.tw/devManual/insrtuction", "issue_tracker": "https://github.com/tsunglung/OpenCWB/issues", "requirements": ["geojson"], diff --git a/custom_components/opencwb/weather.py b/custom_components/opencwb/weather.py index f0ad4e1..befb38b 100755 --- a/custom_components/opencwb/weather.py +++ b/custom_components/opencwb/weather.py @@ -7,6 +7,9 @@ from homeassistant.helpers.device_registry import DeviceEntryType from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.entity_platform import AddEntitiesCallback +from homeassistant.const import ( + UnitOfSpeed +) from .const import ( ATTR_API_CLOUDS, @@ -52,6 +55,8 @@ async def async_setup_entry( class OpenCWBWeather(SingleCoordinatorWeatherEntity[WeatherUpdateCoordinator]): """Implementation of an OpenCWB sensor.""" + _attr_attribution = ATTRIBUTION + _attr_native_wind_speed_unit = UnitOfSpeed.METERS_PER_SECOND def __init__( self, @@ -84,11 +89,6 @@ def should_poll(self): """Return the polling requirement of the entity.""" return False - @property - def attribution(self): - """Return the attribution.""" - return ATTRIBUTION - @property def condition(self): """Return the current condition.""" @@ -165,26 +165,3 @@ def _async_forecast_daily(self) -> list[Forecast] | None: def _async_forecast_hourly(self) -> list[Forecast] | None: """Return the hourly forecast in native units.""" return self.forecast - - async def async_update(self): - """Get the latest data from OCWB and updates the states.""" - self._attr_temperature_unit = UnitOfTemperature.CELSIUS - self._attr_wind_speed_unit = self.anws_aoaws_now.wind_speed.units - - self._attr_temperature = self._weather_coordinator.data[ATTR_API_TEMPERATURE] - pressure = self._weather_coordinator.data[ATTR_API_PRESSURE] - - # OpenWeatherMap returns pressure in hPA, so convert to - # inHg if we aren't using metric. - if not self.hass.config.units.is_metric and pressure: - self._attr_pressure = PressureConverter(pressure, UnitOfPressure.HPA, UnitOfPressure.INHG) - self._attr_pressure = pressure - - wind_speed = self._weather_coordinator.data[ATTR_API_WIND_SPEED] - if self.hass.config.units.name == "imperial": - self._attr_wind_speed = round(wind_speed * 2.24, 2) - self._attr_wind_speed = round(wind_speed * 3.6, 2) - self._attr_humidity = self._weather_coordinator.data[ATTR_API_HUMIDITY] - self._attr_wind_bearing = self._weather_coordinator.data[ATTR_API_WIND_BEARING] - - await self._weather_coordinator.async_request_refresh() diff --git a/custom_components/opencwb/weather_update_coordinator.py b/custom_components/opencwb/weather_update_coordinator.py index 6dc3d96..8e25e95 100755 --- a/custom_components/opencwb/weather_update_coordinator.py +++ b/custom_components/opencwb/weather_update_coordinator.py @@ -110,7 +110,8 @@ async def _get_ocwb_weather(self): self._ocwb_client.one_call, self._latitude, self._longitude, - self._location_name + self._location_name, + self.forecast_mode.split("_")[1] ) else: weather = await self.hass.async_add_executor_job( @@ -133,7 +134,7 @@ def _get_forecast_interval(self): """Get the correct forecast interval depending on the forecast mode.""" interval = "daily" if self.forecast_mode == FORECAST_MODE_HOURLY: - interval = "3h" + interval = "hourly" return interval def _convert_weather_response(self, weather_response):