Skip to content

Commit

Permalink
Merge pull request #20 from dvejsada/experimental
Browse files Browse the repository at this point in the history
New stop choice
  • Loading branch information
dvejsada authored Feb 18, 2024
2 parents f3f4591 + 7aa4cb4 commit ff74249
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 16,622 deletions.
53 changes: 35 additions & 18 deletions pid_integration/config_flow.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,34 @@
import voluptuous as vol

import logging
from typing import Any
from typing import Any, Tuple, Dict
from .api_call import ApiCall

from .const import DOMAIN, CONF_DEP_NUM
from .const import DOMAIN, CONF_DEP_NUM, CONF_STOP_SEL
from homeassistant.const import CONF_API_KEY, CONF_ID
from homeassistant import config_entries, exceptions
from homeassistant.core import HomeAssistant

from homeassistant.helpers.selector import selector
from .stop_list import STOP_LIST, ASW_IDS

_LOGGER = logging.getLogger(__name__)


async def validate_input(hass: HomeAssistant, data: dict) -> dict[str, Any]:
async def validate_input(hass: HomeAssistant, data: dict) -> tuple[dict[str, str], dict]:
"""Validate the user input allows us to connect.
Data has the keys from DATA_SCHEMA with values provided by the user.
"""

try:
data[CONF_ID] = ASW_IDS[STOP_LIST.index(data[CONF_STOP_SEL])]
except Exception:
raise StopNotInList
status, reply = await hass.async_add_executor_job(ApiCall.authenticate, data[CONF_API_KEY], data[CONF_ID], data[CONF_DEP_NUM])
if status == 200:
title: str = reply["stops"][0]["stop_name"] + " " + ApiCall.check_not_null(reply["stops"][0]["platform_code"])
if data[CONF_DEP_NUM] == 0:
raise NoDeparturesSelected
else:
return {"title": title}
return {"title": title}, data
elif status == 401:
raise WrongApiKey
elif status == 404:
Expand All @@ -43,37 +47,46 @@ async def async_step_user(self, user_input=None):
# Check for any previous instance of the integration
if DOMAIN in list(self.hass.data.keys()):
# If previous instance exists, set the API key as suggestion to new config
data_schema = vol.Schema(
{vol.Required(CONF_ID): str, vol.Required(CONF_API_KEY, default=self.hass.data[DOMAIN][list(self.hass.data[DOMAIN].keys())[0]].api_key): str,
data_schema = {vol.Required(CONF_API_KEY, default=self.hass.data[DOMAIN][list(self.hass.data[DOMAIN].keys())[0]].api_key): str,
vol.Required(CONF_DEP_NUM, default=1): int}
)
else:
# if no previous instance, show blank form
data_schema = vol.Schema(
{vol.Required(CONF_ID): str, vol.Required(CONF_API_KEY): str,
data_schema = {vol.Required(CONF_API_KEY): str,
vol.Required(CONF_DEP_NUM, default=1): int}
)

data_schema[CONF_STOP_SEL] = selector({
"select": {
"options": STOP_LIST,
"mode": "dropdown",
"sort": True,
"custom_value": True
}
})

# Set dict for errors
errors: dict = {}

# Steps to take if user input is received
if user_input is not None:
try:
info = await validate_input(self.hass, user_input)
return self.async_create_entry(title=info["title"], data=user_input)
info, data = await validate_input(self.hass, user_input)
return self.async_create_entry(title=info["title"], data=data)

except CannotConnect:
_LOGGER.exception("Unknown API connection error")
errors["base"] = "Unknown API connection error"

except WrongApiKey:
_LOGGER.exception("The API key provided in configuration is not correct.")
errors["base"] = "Connection was not authorized. Wrong or no API key provided"
errors[CONF_API_KEY] = "Connection was not authorized. Wrong or no API key provided"

except StopNotFound:
_LOGGER.exception("Stop with provided awsIDs was not found.")
errors["base"] = "Non existent awsIds provided, stop not found."
errors[CONF_STOP_SEL] = "Non existent awsIds provided, stop not found."

except StopNotInList:
_LOGGER.exception("Stop was not found in list.")
errors[CONF_STOP_SEL] = "Stop was not found in list - choose only stop in provided list."

except NoDeparturesSelected:
_LOGGER.exception("Number of departures cannot be 0.")
Expand All @@ -85,7 +98,7 @@ async def async_step_user(self, user_input=None):

# If there is no user input or there were errors, show the form again, including any errors that were found with the input.
return self.async_show_form(
step_id="user", data_schema=data_schema, errors=errors
step_id="user", data_schema=vol.Schema(data_schema), errors=errors
)


Expand All @@ -102,4 +115,8 @@ class StopNotFound(exceptions.HomeAssistantError):


class NoDeparturesSelected(exceptions.HomeAssistantError):
"""Error to indicate wrong stop was provided."""
"""Error to indicate wrong stop was provided."""


class StopNotInList(exceptions.HomeAssistantError):
"""Error to indicate stop not on the list was provided."""
1 change: 1 addition & 0 deletions pid_integration/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@
ICON_UPDATE = "mdi:update"
DOMAIN = "pid_integration"
CONF_DEP_NUM = "departures_number"
CONF_STOP_SEL = "stop_selector"


3 changes: 3 additions & 0 deletions pid_integration/stop_list.py

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion pid_integration/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@
"title": "Add departure board",
"description": "Provide configuration data. See documentation for further info.",
"data": {
"id": "Enter awsIds of the stop",
"stop_selector": "Select the stop",
"api_key": "Enter API key",
"departures_number": "Number of departures to display"
},
"data_description": {
"stop_selector": "Hint - type to search",
"api_key": "API for Golemio API"
}
}
}
Expand Down
8 changes: 6 additions & 2 deletions pid_integration/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@
"step": {
"user": {
"title": "Add departure board",
"description": "Some description",
"description": "Provide configuration data. See documentation for further info.",
"data": {
"id": "Enter awsIds of the stop",
"stop_selector": "Select the stop",
"api_key": "Enter API key",
"departures_number": "Number of departures to display"
},
"data_description": {
"stop_selector": "Hint - type first 3 letters to search",
"api_key": "API for Golemio API"
}
}
}
Expand Down
12 changes: 5 additions & 7 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# PID Departure Board integration

The custom component is current in BETA. **Beware of using it in your production instance** (may cause unexpected behaviour or crashes).
The custom component is currently in BETA. **Beware of using it in your production instance** (may cause unexpected behaviour or crashes).

This custom component provides a departures board information for the selected stops.

Expand Down Expand Up @@ -29,13 +29,11 @@ From the Home Assistant front page go to **Configuration** and then select **Int
Use the "plus" button in the bottom right to add a new integration called **PID Departure boards**.

Fill in:

- stop aswIds from the [stops_list.txt](stops_list.txt) file in the repository (e.g. "4_2" for stop Arbesovo náměstí platform B)
- API key (if you don't have the API key, you can obtain it here: https://api.golemio.cz/api-keys/auth/sign-up) and
- number of departures to be displayed.
- API key (if you don't have the API key, you can obtain it here: https://api.golemio.cz/api-keys/auth/sign-up),
- number of departures to be displayed, and
- choose a stop from the list.

It is only required to fill in API key once - for additional departure boards it should be prefilled in the config dialogue.

AswIds may be also obtained directly or from stops.txt file in GTFS files here: https://opendata.praha.eu/datasets/https%3A%2F%2Fapi.opendata.praha.eu%2Flod%2Fcatalog%2F9a6a1d8e-45b9-41de-b9ae-0bcec7126876 (asw_zone_id and asw_stop_id must be joined using "_" to get aswIds).

The success dialog will appear or an error will be displayed in the popup.
Loading

0 comments on commit ff74249

Please sign in to comment.