Skip to content

Commit

Permalink
Possibility of integration adding using Station ID added. Support for…
Browse files Browse the repository at this point in the history
… more errors added.
  • Loading branch information
pawkakol1 committed Jun 6, 2022
1 parent aab2d62 commit 84349f0
Show file tree
Hide file tree
Showing 4 changed files with 195 additions and 46 deletions.
158 changes: 129 additions & 29 deletions custom_components/worlds_air_quality_index/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -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."""
Expand All @@ -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,
)
5 changes: 4 additions & 1 deletion custom_components/worlds_air_quality_index/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
32 changes: 24 additions & 8 deletions custom_components/worlds_air_quality_index/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@
CONF_NAME,
CONF_LATITUDE,
CONF_LONGITUDE,
CONF_TOKEN
CONF_TOKEN,
CONF_ID,
CONF_METHOD
)

from .const import (
Expand Down Expand Up @@ -67,29 +69,43 @@ async def async_setup_platform(
)
)


async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
"""Set up the world_air_quality_index sensor 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))
Expand Down
46 changes: 38 additions & 8 deletions custom_components/worlds_air_quality_index/waqi_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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):
Expand Down

0 comments on commit 84349f0

Please sign in to comment.