From 0de8557159c91eb35ab892d05441d391eae6d6c3 Mon Sep 17 00:00:00 2001 From: Eyesoft Date: Tue, 13 Sep 2022 17:55:40 +0200 Subject: [PATCH] New improved version Added support for download with HACS and configuration in GUI. --- custom_components/min_renovasjon/__init__.py | 187 ++++++++------- .../min_renovasjon/config_flow.py | 225 +++++++++++++++++- custom_components/min_renovasjon/const.py | 18 ++ .../min_renovasjon/manifest.json | 7 +- custom_components/min_renovasjon/sensor.py | 87 ++++--- custom_components/min_renovasjon/strings.json | 34 +++ .../min_renovasjon/translations/en.json | 34 +++ .../min_renovasjon/translations/no.json | 34 +++ hacs.json | 1 + 9 files changed, 511 insertions(+), 116 deletions(-) create mode 100644 custom_components/min_renovasjon/const.py create mode 100644 custom_components/min_renovasjon/strings.json create mode 100644 custom_components/min_renovasjon/translations/en.json create mode 100644 custom_components/min_renovasjon/translations/no.json diff --git a/custom_components/min_renovasjon/__init__.py b/custom_components/min_renovasjon/__init__.py index 9aa5179..1d21578 100644 --- a/custom_components/min_renovasjon/__init__.py +++ b/custom_components/min_renovasjon/__init__.py @@ -1,30 +1,32 @@ +import aiohttp +import asyncio import urllib.parse import requests import json -from datetime import date -from datetime import datetime import logging import homeassistant.helpers.config_validation as cv import voluptuous as vol -_LOGGER = logging.getLogger(__name__) - -DOMAIN = "min_renovasjon" -DATA_MIN_RENOVASJON = "data_min_renovasjon" - -CONF_STREET_NAME = "street_name" -CONF_STREET_CODE = "street_code" -CONF_HOUSE_NO = "house_no" -CONF_COUNTY_ID = "county_id" -CONF_DATE_FORMAT = "date_format" -DEFAULT_DATE_FORMAT = "%d/%m/%Y" +from datetime import date +from datetime import datetime +from homeassistant.config_entries import ConfigEntry +from homeassistant.core import HomeAssistant +from .const import ( + DOMAIN, + CONF_STREET_NAME, + CONF_STREET_CODE, + CONF_HOUSE_NO, + CONF_COUNTY_ID, + CONF_DATE_FORMAT, + DEFAULT_DATE_FORMAT, + CONST_KOMMUNE_NUMMER, + CONST_APP_KEY, + CONST_URL_FRAKSJONER, + CONST_URL_TOMMEKALENDER, + CONST_APP_KEY_VALUE +) -CONST_KOMMUNE_NUMMER = "Kommunenr" -CONST_APP_KEY = "RenovasjonAppKey" -CONST_URL_FRAKSJONER = 'https://komteksky.norkart.no/komtek.renovasjonwebapi/api/fraksjoner' -CONST_URL_TOMMEKALENDER = 'https://komteksky.norkart.no/komtek.renovasjonwebapi/api/tommekalender?' \ - 'gatenavn=[gatenavn]&gatekode=[gatekode]&husnr=[husnr]' -CONST_APP_KEY_VALUE = "AE13DEEC-804F-4615-A74E-B4FAC11F0A30" +_LOGGER = logging.getLogger(__name__) CONFIG_SCHEMA = vol.Schema({ DOMAIN: vol.Schema({ @@ -36,29 +38,53 @@ }) }, extra=vol.ALLOW_EXTRA) - -def setup(hass, config): - """Set up the MinRenovasjon component.""" +async def async_setup(hass: HomeAssistant, config: dict): + if DOMAIN not in config: + return True + + hass.data.setdefault(DOMAIN, {}) + hass.data[DOMAIN]["calendar_list"] = None + street_name = config[DOMAIN][CONF_STREET_NAME] street_code = config[DOMAIN][CONF_STREET_CODE] house_no = config[DOMAIN][CONF_HOUSE_NO] county_id = config[DOMAIN][CONF_COUNTY_ID] - date_format = config[DOMAIN][CONF_DATE_FORMAT] + #date_format = config[DOMAIN][CONF_DATE_FORMAT] + date_format = None + min_renovasjon = MinRenovasjon(hass, street_name, street_code, house_no, county_id, date_format) + + hass.data[DOMAIN]["data"] = min_renovasjon + + return True + +async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool: + + hass.data.setdefault(DOMAIN, {}) + hass.data[DOMAIN]["calendar_list"] = None + street_name = config_entry.data.get(CONF_STREET_NAME, "") + street_code = config_entry.data.get(CONF_STREET_CODE, "") + house_no = config_entry.data.get(CONF_HOUSE_NO, "") + county_id = config_entry.data.get(CONF_COUNTY_ID, "") + #date_format = config_entry.data.get(CONF_DATE_FORMAT, "") + date_format = None + min_renovasjon = MinRenovasjon(hass, street_name, street_code, house_no, county_id, date_format) - min_renovasjon = MinRenovasjon(street_name, street_code, house_no, county_id, date_format) - hass.data[DATA_MIN_RENOVASJON] = min_renovasjon + hass.data[DOMAIN]["data"] = min_renovasjon + hass.config_entries.async_setup_platforms(config_entry, ["sensor"]) return True +async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool: + return True class MinRenovasjon: - def __init__(self, gatenavn, gatekode, husnr, kommunenr, date_format): + def __init__(self, hass, gatenavn, gatekode, husnr, kommunenr, date_format): + self._hass = hass self.gatenavn = self._url_encode(gatenavn) self.gatekode = gatekode self.husnr = husnr self._kommunenr = kommunenr - self._date_format = date_format - self._kalender_list = self._get_calendar_list() + #self._date_format = date_format @staticmethod def _url_encode(string): @@ -67,62 +93,54 @@ def _url_encode(string): string = string_decoded_encoded return string - def refresh_calendar(self): - do_refresh = self._check_for_refresh_of_data(self._kalender_list) - if do_refresh: - self._kalender_list = self._get_calendar_list() - - def _get_tommekalender_from_web_api(self): + async def _get_tommekalender_from_web_api(self): + _LOGGER.debug("_get_tommekalender_from_web_api") + header = {CONST_KOMMUNE_NUMMER: self._kommunenr, CONST_APP_KEY: CONST_APP_KEY_VALUE} - url = CONST_URL_TOMMEKALENDER url = url.replace('[gatenavn]', self.gatenavn) url = url.replace('[gatekode]', self.gatekode) url = url.replace('[husnr]', self.husnr) - response = requests.get(url, headers=header) - if response.status_code == requests.codes.ok: - data = response.text - if data == "true": - _LOGGER.error("Calendar is empty") - return None - - return data - else: - _LOGGER.error("GET Tommekalender returned: %s", response.status_code) - return None + async with aiohttp.ClientSession(headers=header) as session: + async with session.get(url) as resp: + data = await resp.read() + + if resp.ok: + return data.decode("UTF-8") + else: + _LOGGER.error("GET Tommekalender returned: %s", resp) + return None - def _get_fraksjoner_from_web_api(self): + async def _get_fraksjoner_from_web_api(self): + _LOGGER.debug("_get_fraksjoner_from_web_api") + header = {CONST_KOMMUNE_NUMMER: self._kommunenr, CONST_APP_KEY: CONST_APP_KEY_VALUE} url = CONST_URL_FRAKSJONER - response = requests.get(url, headers=header) - if response.status_code == requests.codes.ok: - data = response.text - return data - else: - _LOGGER.error("GET Fraksjoner returned: %s", response.status_code) - return None - - def _get_from_web_api(self): - tommekalender = self._get_tommekalender_from_web_api() - fraksjoner = self._get_fraksjoner_from_web_api() + async with aiohttp.ClientSession(headers=header) as session: + async with session.get(url) as resp: + data = await resp.read() - _LOGGER.debug(f"Tommekalender: {tommekalender}") - _LOGGER.debug(f"Fraksjoner: {fraksjoner}") + if resp.ok: + return data.decode("UTF-8") + else: + _LOGGER.error("GET Fraksjoner returned: %s", resp) + return None + async def _get_from_web_api(self): + tommekalender = await self._get_tommekalender_from_web_api() + fraksjoner = await self._get_fraksjoner_from_web_api() return tommekalender, fraksjoner - def _get_calendar_list(self, refresh=False): - data = None - + async def _get_calendar_list(self, refresh=False): + data = self._hass.data[DOMAIN]["calendar_list"] + if refresh or data is None: - _LOGGER.debug("Refresh or no data. Fetching from API.") - tommekalender, fraksjoner = self._get_from_web_api() + tommekalender, fraksjoner = await self._get_from_web_api() + kalender_list = self._parse_calendar_list(tommekalender, fraksjoner) else: - tommekalender, fraksjoner = data - - kalender_list = self._parse_calendar_list(tommekalender, fraksjoner) + kalender_list = data if kalender_list is None: return None @@ -132,9 +150,10 @@ def _get_calendar_list(self, refresh=False): check_for_refresh = self._check_for_refresh_of_data(kalender_list) if check_for_refresh: - kalender_list = self._get_calendar_list(refresh=True) + kalender_list = await self._get_calendar_list(refresh=True) - _LOGGER.debug("Returning calendar list") + self._hass.data[DOMAIN]["calendar_list"] = kalender_list + return kalender_list @staticmethod @@ -145,8 +164,6 @@ def _parse_calendar_list(tommekalender, fraksjoner): _LOGGER.error("Could not fetch calendar. Check configuration parameters.") return None - _LOGGER.debug(tommekalender) - tommekalender_json = json.loads(tommekalender) fraksjoner_json = json.loads(fraksjoner) @@ -166,7 +183,7 @@ def _parse_calendar_list(tommekalender, fraksjoner): tommedato_neste = datetime.strptime(tommedato_neste, "%Y-%m-%dT%H:%M:%S") for fraksjon in fraksjoner_json: - if fraksjon['Id'] == fraksjon_id: + if int(fraksjon['Id']) == int(fraksjon_id): fraksjon_navn = fraksjon['Navn'] fraksjon_ikon = fraksjon['Ikon'] @@ -194,20 +211,24 @@ def _check_for_refresh_of_data(kalender_list): return False - def get_calender_for_fraction(self, fraksjon_id): - if self._kalender_list is None: - return None - - for entry in self._kalender_list: + async def get_calender_for_fraction(self, fraksjon_id): + calendar_list = self._hass.data[DOMAIN]["calendar_list"] + + if calendar_list is None: + calendar_list = await self._get_calendar_list() + self._hass.data[DOMAIN]["calendar_list"] = calendar_list + + for entry in calendar_list: entry_fraksjon_id, _, _, _, _= entry - if fraksjon_id == entry_fraksjon_id: + if int(fraksjon_id) == int(entry_fraksjon_id): return entry @property def calender_list(self): - return self._kalender_list + return self._hass.data[DOMAIN]["calendar_list"] def format_date(self, date): - if self._date_format == "None": - return date - return date.strftime(self._date_format) + return date + #if self._date_format == "None": + # return date + #return date.strftime(self._date_format) diff --git a/custom_components/min_renovasjon/config_flow.py b/custom_components/min_renovasjon/config_flow.py index a1a3153..930a055 100644 --- a/custom_components/min_renovasjon/config_flow.py +++ b/custom_components/min_renovasjon/config_flow.py @@ -1,6 +1,223 @@ -from homeassistant import config_entries -from .const import DOMAIN +import aiohttp +import asyncio +import json +from collections import namedtuple +from typing import Dict, List, Tuple +import requests +import re + +import logging +import voluptuous as vol + +from homeassistant import config_entries, exceptions +from homeassistant.core import HomeAssistant +from homeassistant.core import callback +import homeassistant.helpers.config_validation as cv + +from .const import ( + DOMAIN, + CONF_STREET_NAME, + CONF_STREET_CODE, + CONF_HOUSE_NO, + CONF_COUNTY_ID, + CONF_DATE_FORMAT, + DEFAULT_DATE_FORMAT, + CONF_FRACTION_IDS, + ADDRESS_LOOKUP_URL, + APP_CUSTOMERS_URL, + CONST_APP_KEY_VALUE, + KOMTEK_API_BASE_URL, + CONST_URL_FRAKSJONER +) + +_LOGGER = logging.getLogger(__name__) + +class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): + + VERSION = 1 + CONNECTION_CLASS = config_entries.CONN_CLASS_CLOUD_POLL + + async def async_step_user(self, user_input=None): + """Handle the initial step.""" + errors = {} + address = None + + if user_input is not None: + try: + address = user_input["address"] + error, address_info = await self._get_address_info(address) + + if error is not None: + errors["base"] = error + + if address_info is not None: + return self.async_create_entry(title="Min Renovasjon", data=address_info) + + except Exception: + _LOGGER.exception("Unexpected exception") + errors["base"] = "unknown" + + #errors substitution in language file + return self.async_show_form( + step_id="user", + + data_schema=vol.Schema({ + vol.Required("address", default=address): str + }), + errors=errors + ) + + async def _get_address_info(self, address_search_string): + error, address_info = await self._address_lookup(address_search_string) + + if error is not None: + return error, None + + if address_info is not None: + ( + self.street, + self.street_code, + self.number, + self.municipality, + self.municipality_code, + self.postal_code, + self.postal, + ) = address_info + + if await self.municipality_is_app_customer: + text = "self.fractions = self._get_fractions()" + else: + return "municipality_not_customer", None + + address = { + "street_name": self.street, + "street_code": str(self.street_code), + "house_no": str(self.number), + "county_id": str(self.municipality_code) + } + + return None, address + + async def _address_lookup(self, s: str) -> Tuple: + """ + Makes an API call to geonorge.no, the official resource for open geo data in Norway. + This function is used to get deterministic address properties that is needed for + further API calls with regards to Min Renovasjon, mainly municipality, municipality code, + street name and street code. + :param s: Search string for which address to search + :return: Tuple of address fields + """ + error = None + data = None + + regex = r"(.*ve)(i|g)(.*)" + subst = "\\1*\\3" + search_string = re.sub(regex, subst, s, 0, re.MULTILINE) + + params={ + "sok": search_string, + # Only get the relevant address fields + "filtrer": "adresser.kommunenummer," + "adresser.adressenavn," + "adresser.adressekode," + "adresser.nummer," + "adresser.kommunenavn," + "adresser.postnummer," + "adresser.poststed", + } + + async with aiohttp.ClientSession() as session: + async with session.get(url=ADDRESS_LOOKUP_URL, params=params) as resp: + response = await resp.read() + if resp.ok: + data = json.loads(response.decode("UTF-8")) + + if not data["adresser"]: + return "no_address_found", None + + if len(data["adresser"]) > 1: + return "multiple_addresses_found", None + + return None, ( + data["adresser"][0]["adressenavn"], + data["adresser"][0]["adressekode"], + data["adresser"][0]["nummer"], + data["adresser"][0]["kommunenavn"], + data["adresser"][0]["kommunenummer"], + data["adresser"][0]["postnummer"], + data["adresser"][0]["poststed"], + ) + + @property + async def municipality_is_app_customer(self) -> bool: + """ + Make an API call to get all customers of the NorkartRenovasjon service which + supports the Min Renovasjon app. Then check if this municipality is actually + a customer or not. + :return: Boolean indicating if this municipality is a customer or not. + """ + customers = None + + async with aiohttp.ClientSession() as session: + async with session.get(url=APP_CUSTOMERS_URL, params={"Appid": "MobilOS-NorkartRenovasjon"}) as resp: + response = await resp.read() + if resp.ok: + customers = json.loads(response.decode("UTF-8")) + + return any( + customer["Number"] == self.municipality_code for customer in customers + ) + + @staticmethod + @callback + def async_get_options_flow(config_entry): + """Get options flow.""" + return OptionsFlowHandler(config_entry) + +class OptionsFlowHandler(config_entries.OptionsFlow): + """Options flow handler.""" + + def __init__(self, config_entry): + """Initialize options flow.""" + self.config_entry = config_entry + self.options = dict(config_entry.options) + + async def async_step_init(self, user_input=None): + """Manage the options.""" + + if user_input is not None: + self.options.update(user_input) + return self.async_create_entry(title=DOMAIN, data=self.options) + + options = self.config_entry.options + fraction_ids = options.get(CONF_FRACTION_IDS, []) + + municipality_code = self.config_entry.data.get(CONF_COUNTY_ID, "") + fraction_list = await self._get_fractions(municipality_code) + fractions = {} + + for fraction in fraction_list: + fractions[str(fraction["Id"])] = fraction["Navn"] + + return self.async_show_form( + step_id="init", + data_schema=vol.Schema( + { + vol.Required(CONF_FRACTION_IDS, default=fraction_ids): cv.multi_select(fractions) + } + ) + ) + + async def _get_fractions(self, municipality_code) -> Dict: + headers = {"RenovasjonAppKey": CONST_APP_KEY_VALUE, "Kommunenr": municipality_code} + params = {"server": CONST_URL_FRAKSJONER} + + async with aiohttp.ClientSession(headers=headers) as session: + async with session.get(url=KOMTEK_API_BASE_URL, params=params) as resp: + response = await resp.read() + if resp.ok: + return json.loads(response.decode("UTF-8")) + + return None -class ExampleConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): - """Example config flow.""" diff --git a/custom_components/min_renovasjon/const.py b/custom_components/min_renovasjon/const.py new file mode 100644 index 0000000..c41fc2d --- /dev/null +++ b/custom_components/min_renovasjon/const.py @@ -0,0 +1,18 @@ +DOMAIN = "min_renovasjon" +CONF_STREET_NAME = "street_name" +CONF_STREET_CODE = "street_code" +CONF_HOUSE_NO = "house_no" +CONF_COUNTY_ID = "county_id" +CONF_DATE_FORMAT = "date_format" +DEFAULT_DATE_FORMAT = "%d/%m/%Y" +CONST_KOMMUNE_NUMMER = "Kommunenr" +CONST_APP_KEY = "RenovasjonAppKey" +CONST_URL_FRAKSJONER = "https://komteksky.norkart.no/komtek.renovasjonwebapi/api/fraksjoner" +CONST_URL_TOMMEKALENDER = "https://komteksky.norkart.no/komtek.renovasjonwebapi/api/tommekalender?gatenavn=[gatenavn]&gatekode=[gatekode]&husnr=[husnr]" +CONST_APP_KEY_VALUE = "AE13DEEC-804F-4615-A74E-B4FAC11F0A30" +CONF_FRACTION_IDS = "fraction_ids" +CONF_FRACTION_ID = "fraction_id" +ADDRESS_LOOKUP_URL = "https://ws.geonorge.no/adresser/v1/sok?" +APP_CUSTOMERS_URL = "https://www.webatlas.no/wacloud/servicerepository/CatalogueService.svc/json/GetRegisteredAppCustomers" +KOMTEK_API_BASE_URL = "https://norkartrenovasjon.azurewebsites.net/proxyserver.ashx" + diff --git a/custom_components/min_renovasjon/manifest.json b/custom_components/min_renovasjon/manifest.json index e585e18..688c8c5 100644 --- a/custom_components/min_renovasjon/manifest.json +++ b/custom_components/min_renovasjon/manifest.json @@ -1,12 +1,15 @@ { "domain": "min_renovasjon", "name": "Min renovasjon", - "config_flow": false, + "config_flow": true, "documentation": "https://github.com/eyesoft/home_assistant_min_renovasjon", "issue_tracker": "https://github.com/eyesoft/home_assistant_min_renovasjon/issues", "codeowners": ["@eyesoft"], "dependencies": [], "requirements": [], - "version": "1.0.0", + "ssdp": [], + "zeroconf": [], + "homekit": {}, + "version": "0.0.5", "iot_class": "local_polling" } diff --git a/custom_components/min_renovasjon/sensor.py b/custom_components/min_renovasjon/sensor.py index 03cc1d7..1441672 100644 --- a/custom_components/min_renovasjon/sensor.py +++ b/custom_components/min_renovasjon/sensor.py @@ -1,42 +1,59 @@ import logging +import json +import homeassistant.helpers.config_validation as cv +import voluptuous as vol +from homeassistant.helpers.restore_state import RestoreEntity from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.helpers.entity import Entity -import homeassistant.helpers.config_validation as cv -import voluptuous as vol -from ..min_renovasjon import DATA_MIN_RENOVASJON from datetime import date +from datetime import timedelta +from .const import ( + DOMAIN, + CONF_FRACTION_IDS, + CONF_FRACTION_ID +) _LOGGER = logging.getLogger(__name__) - -CONF_FRACTION_ID = "fraction_id" +SCAN_INTERVAL = timedelta(hours=1) PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_FRACTION_ID): vol.All(cv.ensure_list), }) -def setup_platform(hass, config, add_entities, discovery_info=None): +async def async_setup_platform(hass, config, add_entities, discovery_info=None): + min_renovasjon = hass.data[DOMAIN]["data"] + calendar_list = await min_renovasjon._get_calendar_list() fraction_ids = config.get(CONF_FRACTION_ID) - min_renovasjon = hass.data[DATA_MIN_RENOVASJON] - add_entities(MinRenovasjonSensor(min_renovasjon, fraction_id) for fraction_id in fraction_ids) + add_entities(MinRenovasjonSensor(min_renovasjon, fraction_id, calendar_list) for fraction_id in fraction_ids) +async def async_setup_entry(hass, config_entry, async_add_entities): + min_renovasjon = hass.data[DOMAIN]["data"] + calendar_list = await min_renovasjon._get_calendar_list() + entities = [] + fraction_ids = config_entry.options.get(CONF_FRACTION_IDS, []) + + for fraction_id in fraction_ids: + entities.append(MinRenovasjonSensor(min_renovasjon, fraction_id, calendar_list)) + + async_add_entities(entities) class MinRenovasjonSensor(Entity): - def __init__(self, min_renovasjon, fraction_id): + def __init__(self, min_renovasjon, fraction_id, calendar_list): """Initialize with API object, device id.""" + self._state = None + self._calendar_list = calendar_list self._min_renovasjon = min_renovasjon - self._fraction_id = fraction_id + self._fraction_id = int(fraction_id) self._available = True self._attributes = {} - + self._attr_unique_id = self.get_name() + @property - def name(self): - """Return the name of the fraction if any.""" - fraction = self._min_renovasjon.get_calender_for_fraction(self._fraction_id) - if fraction is not None: - return fraction[1] + def should_poll(self): + return True @property def device_class(self): @@ -48,29 +65,39 @@ def available(self): """Could the device be accessed during the last update call.""" return self._available - @property - def state(self): - """Return the state/date of the fraction.""" - fraction = self._min_renovasjon.get_calender_for_fraction(self._fraction_id) - if fraction is not None: - return fraction[3] - @property def entity_picture(self): """Return entity specific state attributes.""" path = "/local/min_renovasjon/" return "{0}{1}.png".format(path, self._fraction_id) - + @property def extra_state_attributes(self): """Return entity specific state attributes.""" return self._attributes + + @property + def name(self): + """Return the name.""" + return self.get_name() + + def get_name(self): + if self._calendar_list is not None: + for fraction in self._calendar_list: + if int(fraction[0]) == self._fraction_id: + return fraction[1] + return None - def update(self): + @property + def state(self): + """Return the state/date of the fraction.""" + return self._state + + async def async_update(self): """Update calendar.""" - self._min_renovasjon.refresh_calendar() + + fraction = await self._min_renovasjon.get_calender_for_fraction(self._fraction_id) - fraction = self._min_renovasjon.get_calender_for_fraction(self._fraction_id) if fraction is not None: if fraction[3] is not None: pickupDate = fraction[3].date() @@ -82,3 +109,9 @@ def update(self): self._attributes['fraction_id'] = self._fraction_id self._attributes['fraction_name'] = fraction[1] self._attributes['fraction_icon'] = fraction[2] + + self._state = fraction[3] + + async def async_added_to_hass(self): + await self.async_update() + diff --git a/custom_components/min_renovasjon/strings.json b/custom_components/min_renovasjon/strings.json new file mode 100644 index 0000000..79da461 --- /dev/null +++ b/custom_components/min_renovasjon/strings.json @@ -0,0 +1,34 @@ +{ + "config": { + "step": { + "user": { + "title": "Min Renovasjon address information", + "description": "Enter your address information.", + "data": { + "street_name": "Street name", + "street_code": "Street code", + "house_no": "House no", + "county_id": "County Id", + "date_format": "Date format" + } + } + }, + "error": { + "unknown": "Unknown error occured.", + "municipality_not_customer": "Selected municipality is not a customer of Min Renovasjon!", + "no_address_found": "No address found.", + "multiple_addresses_found": "More than one addresses found. Only one address should be returned. Please narrow your search." + } + }, + "options": { + "step": { + "init": { + "title": "Min Renovasjon fractions", + "description": "Select fractions from which sensors are to be made.", + "data": { + "fraction_ids": "Fractions" + } + } + } + } +} diff --git a/custom_components/min_renovasjon/translations/en.json b/custom_components/min_renovasjon/translations/en.json new file mode 100644 index 0000000..79da461 --- /dev/null +++ b/custom_components/min_renovasjon/translations/en.json @@ -0,0 +1,34 @@ +{ + "config": { + "step": { + "user": { + "title": "Min Renovasjon address information", + "description": "Enter your address information.", + "data": { + "street_name": "Street name", + "street_code": "Street code", + "house_no": "House no", + "county_id": "County Id", + "date_format": "Date format" + } + } + }, + "error": { + "unknown": "Unknown error occured.", + "municipality_not_customer": "Selected municipality is not a customer of Min Renovasjon!", + "no_address_found": "No address found.", + "multiple_addresses_found": "More than one addresses found. Only one address should be returned. Please narrow your search." + } + }, + "options": { + "step": { + "init": { + "title": "Min Renovasjon fractions", + "description": "Select fractions from which sensors are to be made.", + "data": { + "fraction_ids": "Fractions" + } + } + } + } +} diff --git a/custom_components/min_renovasjon/translations/no.json b/custom_components/min_renovasjon/translations/no.json new file mode 100644 index 0000000..e93b4f2 --- /dev/null +++ b/custom_components/min_renovasjon/translations/no.json @@ -0,0 +1,34 @@ +{ + "config": { + "step": { + "user": { + "title": "Min Renovasjon adresseinformasjon", + "description": "Tast inn din adresse.", + "data": { + "street_name": "Gatenavn", + "street_code": "Gatekode", + "house_no": "Husnummer", + "county_id": "FylkeId", + "date_format": "Datoformat" + } + } + }, + "error": { + "unknown": "Ukjent feil oppstod.", + "municipality_not_customer": "Valgt kommune er ikke en kunde av Min Renovasjon!", + "no_address_found": "Ingen adresse funnet.", + "multiple_addresses_found": "Mer enn en adresse funnet. Vennligst begrens søket." + } + }, + "options": { + "step": { + "init": { + "title": "Min Renovasjon avfallstyper", + "description": "Velg de avfallstypene det skal lages sensor av.", + "data": { + "fraction_ids": "Avfallstyper" + } + } + } + } +} diff --git a/hacs.json b/hacs.json index 8d8f5cc..18207c7 100644 --- a/hacs.json +++ b/hacs.json @@ -1,5 +1,6 @@ { "name": "Min renovasjon", "render_readme": true, + "domains": ["sensor"], "country": ["NO"] }