diff --git a/custom_components/worlds_air_quality_index/config_flow.py b/custom_components/worlds_air_quality_index/config_flow.py index daefe29..d34bf1b 100644 --- a/custom_components/worlds_air_quality_index/config_flow.py +++ b/custom_components/worlds_air_quality_index/config_flow.py @@ -15,27 +15,23 @@ CONF_NAME, CONF_LATITUDE, CONF_LONGITUDE, - CONF_TOKEN + CONF_TOKEN, + CONF_LOCATION, + CONF_METHOD, + CONF_ID ) from .const import ( DOMAIN, - DEFAULT_NAME -) - -DATA_SCHEMA = vol.Schema( - { - vol.Required(CONF_TOKEN): cv.string, - vol.Optional(CONF_NAME): cv.string, - vol.Optional(CONF_LATITUDE): cv.string, - vol.Optional(CONF_LONGITUDE): cv.string, - } + DEFAULT_NAME, + GEOGRAPHIC_LOCALIZATION, + STATION_ID ) class WorldsAirQualityIndexConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): """Handle a config flow for worlds_air_quality_index integration.""" - VERSION = 1 + VERSION = 2 async def async_step_import(self, config: dict[str, Any]) -> FlowResult: """Import a configuration from config.yaml.""" @@ -45,47 +41,151 @@ async def async_step_import(self, config: dict[str, Any]) -> FlowResult: config[CONF_NAME] = name return await self.async_step_user(user_input=config) - async def async_step_user( - self, user_input: dict[str, Any] | None = None - ) -> FlowResult: + async def async_step_user(self, user_input: dict[str, Any] | None = None) -> FlowResult: """Handle the initial step.""" + data_schema = vol.Schema( + { + vol.Required(CONF_METHOD, default=GEOGRAPHIC_LOCALIZATION): vol.In( + ( + GEOGRAPHIC_LOCALIZATION, + STATION_ID + ) + ) + } + ) + + if user_input is None: + return self.async_show_form( + step_id="user", + data_schema=data_schema, + ) + + if user_input[CONF_METHOD] == GEOGRAPHIC_LOCALIZATION: + return await self.async_step_geographic_localization() + return await self.async_step_station_id() + + async def async_step_geographic_localization(self, user_input=None) -> FlowResult: + """Handle the geographic localization step.""" errors = {} - if user_input: + data_schema = vol.Schema( + { + vol.Required(CONF_TOKEN): cv.string, + vol.Required(CONF_LATITUDE, default=self.hass.config.latitude): cv.latitude, + vol.Required(CONF_LONGITUDE, default=self.hass.config.longitude): cv.longitude, + vol.Optional(CONF_NAME): cv.string + } + ) + if user_input: token = user_input[CONF_TOKEN] - latitude = user_input.get(CONF_LATITUDE, self.hass.config.latitude) - longitude = user_input.get(CONF_LONGITUDE, self.hass.config.longitude) - requester = WaqiDataRequester(latitude, longitude, token) + latitude = user_input[CONF_LATITUDE] + longitude = user_input[CONF_LONGITUDE] + method = CONF_LOCATION + requester = WaqiDataRequester(latitude, longitude, token, None, method) await self.hass.async_add_executor_job(requester.update) - testData = requester.GetData() + validateData = requester.GetData() + if validateData: + if validateData["status"] == "ok": + if "status" in validateData["data"]: + if validateData["data"]["status"] == "error": + if validateData["data"]["msg"] == "Unknown ID": + errors["base"] = "unknow_station_id" + else: + errors["base"] = "server_error" + elif validateData["status"] == "error": + if validateData["data"] == "Invalid key": + errors["base"] = "invalid_token" + else: + errors["base"] = "server_error" + else: + errors["base"] = "server_error" + else: + errors["base"] = "server_not_available" + stationName = requester.GetStationName() name = user_input.get(CONF_NAME, stationName) - if testData is None: - errors["base"] = "invalid_token" - elif stationName is None: - errors["base"] = "invalid_station_name" - else: + if not errors: await self.async_set_unique_id(name) self._abort_if_unique_id_configured() return self.async_create_entry( title=name, data={ - CONF_NAME: name, CONF_TOKEN: token, CONF_LATITUDE: latitude, CONF_LONGITUDE: longitude, + CONF_NAME: name, + CONF_METHOD: method, }, ) return self.async_show_form( - step_id="user", - data_schema=DATA_SCHEMA, + step_id="geographic_localization", + data_schema=data_schema, errors=errors, ) - + async def async_step_station_id(self, user_input=None) -> FlowResult: + errors = {} + + data_schema = vol.Schema( + { + vol.Required(CONF_TOKEN): cv.string, + vol.Required(CONF_ID): cv.string, + vol.Optional(CONF_NAME): cv.string + } + ) + + if user_input: + + token = user_input[CONF_TOKEN] + id = user_input[CONF_ID] + method = CONF_ID + requester = WaqiDataRequester(None, None, token, id, method) + await self.hass.async_add_executor_job(requester.update) + + validateData = requester.GetData() + if validateData: + if validateData["status"] == "ok": + if "status" in validateData["data"]: + if validateData["data"]["status"] == "error": + if validateData["data"]["msg"] == "Unknown ID": + errors["base"] = "unknow_station_id" + else: + errors["base"] = "server_error" + elif validateData["status"] == "error": + if validateData["data"] == "Invalid key": + errors["base"] = "invalid_token" + else: + errors["base"] = "server_error" + else: + errors["base"] = "server_error" + else: + errors["base"] = "server_not_available" + + stationName = requester.GetStationName() + name = user_input.get(CONF_NAME, stationName) + + if not errors: + await self.async_set_unique_id(name) + self._abort_if_unique_id_configured() + + return self.async_create_entry( + title=name, + data={ + CONF_TOKEN: token, + CONF_ID: id, + CONF_NAME: name, + CONF_METHOD: method, + }, + ) + + return self.async_show_form( + step_id="station_id", + data_schema=data_schema, + errors=errors, + ) diff --git a/custom_components/worlds_air_quality_index/const.py b/custom_components/worlds_air_quality_index/const.py index d71d4f4..25a857f 100644 --- a/custom_components/worlds_air_quality_index/const.py +++ b/custom_components/worlds_air_quality_index/const.py @@ -15,10 +15,13 @@ DOMAIN = "worlds_air_quality_index" PLATFORMS = [Platform.SENSOR] -SW_VERSION = "0.2.0" +SW_VERSION = "0.3.0" SCAN_INTERVAL = timedelta(minutes=30) +DISCOVERY_TYPE = "discovery_type" +GEOGRAPHIC_LOCALIZATION = "Geographic localization" +STATION_ID = "Station ID" DEFAULT_NAME = 'waqi1' SENSORS = { diff --git a/custom_components/worlds_air_quality_index/sensor.py b/custom_components/worlds_air_quality_index/sensor.py index 8505f7d..b38117d 100644 --- a/custom_components/worlds_air_quality_index/sensor.py +++ b/custom_components/worlds_air_quality_index/sensor.py @@ -24,7 +24,9 @@ CONF_NAME, CONF_LATITUDE, CONF_LONGITUDE, - CONF_TOKEN + CONF_TOKEN, + CONF_ID, + CONF_METHOD ) from .const import ( @@ -67,7 +69,6 @@ async def async_setup_platform( ) ) - async def async_setup_entry( hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback ) -> None: @@ -75,21 +76,36 @@ async def async_setup_entry( _LOGGER.debug("config token:") _LOGGER.debug(entry.data[CONF_TOKEN]) - _LOGGER.debug(entry.data[CONF_LATITUDE]) - _LOGGER.debug(entry.data[CONF_LONGITUDE]) + _LOGGER.debug("config method:") + _LOGGER.debug(entry.data[CONF_METHOD]) + _LOGGER.debug("config name:") + _LOGGER.debug(entry.data[CONF_NAME]) name = entry.data[CONF_NAME] token = entry.data[CONF_TOKEN] - latitude = entry.data[CONF_LATITUDE] - longitude = entry.data[CONF_LONGITUDE] - requester = WaqiDataRequester(latitude, longitude, token) + method = entry.data[CONF_METHOD] + + if method == CONF_ID: + _LOGGER.debug("config ID:") + _LOGGER.debug(entry.data[CONF_ID]) + id = entry.data[CONF_ID] + requester = WaqiDataRequester(None, None, token, id, method) + else: + _LOGGER.debug("config latitude:") + _LOGGER.debug(entry.data[CONF_LATITUDE]) + _LOGGER.debug("config longitude:") + _LOGGER.debug(entry.data[CONF_LONGITUDE]) + latitude = entry.data[CONF_LATITUDE] + longitude = entry.data[CONF_LONGITUDE] + requester = WaqiDataRequester(latitude, longitude, token, None, method) + await hass.async_add_executor_job(requester.update) scannedData = requester.GetData() scannedData = scannedData["data"]["iaqi"] entities = [] - #entities.append(WorldsAirQualityIndexAqiSensor(requester)) + for res in SENSORS: if res == "aqi" or res in scannedData: entities.append(WorldsAirQualityIndexSensor(res, requester)) diff --git a/custom_components/worlds_air_quality_index/waqi_api.py b/custom_components/worlds_air_quality_index/waqi_api.py index eab4730..1cc88a9 100644 --- a/custom_components/worlds_air_quality_index/waqi_api.py +++ b/custom_components/worlds_air_quality_index/waqi_api.py @@ -2,16 +2,22 @@ import requests import logging from homeassistant.util import Throttle +from homeassistant.const import ( + CONF_ID, + CONF_LOCATION +) from .const import SCAN_INTERVAL _LOGGER = logging.getLogger(__name__) class WaqiDataRequester(object): - def __init__(self, lat, lng, token): + def __init__(self, lat, lng, token, idx, method): self._lat = lat self._lng = lng self._token = token + self._idx = idx + self._method = method self._data = None self._stationName = None self._stationIdx = None @@ -20,18 +26,42 @@ def __init__(self, lat, lng, token): @Throttle(SCAN_INTERVAL) def update(self): _LOGGER.debug("Updating WAQI sensors") - try: - _dat = requests.get(f"https://api.waqi.info/feed/geo:{self._lat};{self._lng}/?token={self._token}").text - self._data = json.loads(_dat) - self._stationName = self._data["data"]["city"]["name"] - self._stationName = self._stationName.replace(", ", "_").replace(" ", "_").replace("(", "").replace(")","").lower() - self._stationIdx = self._data["data"]["idx"] - self._updateLastTime = self._data["data"]["time"]["iso"] + if self._method == CONF_LOCATION: + _dat = requests.get(f"https://api.waqi.info/feed/geo:{self._lat};{self._lng}/?token={self._token}").text + elif self._method == CONF_ID: + _dat = requests.get(f"https://api.waqi.info/feed/@{self._idx}/?token={self._token}").text + else: + _LOGGER.debug("No choosen method") + + if _dat: + self._data = json.loads(_dat) + if self._data: + if "data" in self._data: + if "idx" in self._data["data"]: + if self._method == CONF_LOCATION: + self._stationIdx = self._data["data"]["idx"] + elif self._method == CONF_ID: + self._stationIdx = self._idx + + if "city" in self._data["data"]: + if "name" in self._data["data"]["city"]: + self._stationName = self._data["data"]["city"]["name"] + + if self._stationName: + self._stationName = self._stationName.replace(", ", "_").replace(" ", "_").replace("(", "").replace(")","").lower() + else: + self._stationName = "UnknownName_" + self._stationIdx + + if "time" in self._data["data"]: + if "iso" in self._data["data"]["time"]: + self._updateLastTime = self._data["data"]["time"]["iso"] + except requests.exceptions.RequestException as exc: _LOGGER.error("Error occurred while fetching data: %r", exc) self._data = None self._stationName = None + self._stationIdx = None return False def GetData(self):