diff --git a/README-en.md b/README-en.md new file mode 100644 index 0000000..83f6bd7 --- /dev/null +++ b/README-en.md @@ -0,0 +1,81 @@ +([Ver en español](README.md)) + +# Net Balance Component for Home Assistant + +## What is net balance? + +In Spain and other countries, users of photovoltaic panels with surplus compensation have net balance, which calculates the final result of import and export every hour and bills accordingly. + +To put it simply: If you export 3 kWh and import 1 kWh in one hour, it will simply be considered that you have exported 2 kWh. + +Since exporting is always cheaper than importing, this represents significant savings for the user. + +### Example: + +Let's assume that importing costs €0.15/kWh, and exporting gives a discount of €0.11/kWh. In the first case, we export 3 kWh and import 1 kWh, and in the second case, it's the opposite. + +#### Without Balance +`1 * €0.15 - 3 * €0.11 = -€0.18` + +`3 * €0.15 - 1 * €0.11 = €0.34` + +#### With Balance +`1 - 3 = -2 => -2 * €0.11 = -€0.22` + +`3 - 1 = 2 => 2 * €0.15 = €0.30` + +As we can see, in both cases, net balance benefits the user. + +## What does this component do? + +This component calculates your current hourly balance as well as the result at the end of the hour. + +To do this, you need to provide the total imported and exported kWh from your inverter, and the component will create three new entities: + +- Net Import +- Net Export +- Current Net Balance + +You can then use Net Import and Net Export in the Energy panel for Home Assistant to perform calculations correctly. + +### Without net metering + +![Without Balance](img/sin%20balance.png) + +### With Balance + +![With Balance](img/balance.png) + +## Installation + +You can install the component using HACS. To do this, simply add this repository to your custom repositories and search for "balance neto". + +## Configuration + +Once installed, go to _Devices and Services -> Add Integration_ and search for _Balance_. + +The assistant will ask for 2 entities: total import from grid kWh and total exported to grid kWh. + + +Additionally, it will request the time period, which can be hourly (as is the case in Spain) or every quarter of an hour. + +Finally, you can select a safety offset since Home Assistant may take a moment to perform the calculations; it will carry them out 5 seconds before the end of the period, but this can be modified if necessary. + +## Usage + +Once the component is configured, use "Net Import" as the sensor for _network consumption_ and "Net Export" for _network feed_. + +>#### :warning: If you already have historical data in HA, changing the sensors will stop displaying old data. If you want to keep the data, you will need to connect to the database and copy/update the old import/export records to the net import and net export records. + +## Activating Devices When There Are Surpluses + +Thanks to the Current Hourly Balance entity, you can activate and deactivate high-consumption devices, such as electric water heaters, to make the most of the surpluses. + +Instead of using power regulators to adjust consumption to your current production, you can turn the device on and off based on the balance value. For example, turn on the water heater/AC when the net balance is greater than 0.2 kWh and turn it off when it's less than -0.05 kWh. + +This way, we can avoid reducing power when a cloud passes by temporarily or never turning on a 1500W device if our surpluses are 750W when we could have it on for half an hour without any issues. + + +## Videotutorial + +[![Videotutorial](https://img.youtube.com/vi/tG9T1NYv2Cs/0.jpg)](https://www.youtube.com/watch?v=tG9T1NYv2Cs "Videotutorial") \ No newline at end of file diff --git a/README-es.md b/README-es.md deleted file mode 100644 index 92559f6..0000000 --- a/README-es.md +++ /dev/null @@ -1,83 +0,0 @@ -# Componente Balance Neto para Home Assistant - - -## ¿Qué es el balance neto? - -En España, los usuarios de placas fotovoltáicas con compensación de excedentes disponen del balance neto horario, el cual -calcula el resultado final de importación y exportación cada hora y en base a este se le factura. - -Dicho más sencillo: Si en una hora exportas 3kWh e importas 1kWh, simplemente se considerará que has exportado 2kWh. - -Dado que la exportación siempre será más barata que la importación, esto supone un ahorro importante para el usuario. - -### Ejemplo: - -Supongamos que importar cuesta 0.15€/kWh y exportar nos descuenta 0.11€/kWh, en el primer caso exportamos 3 e importamos 1, en el segundo al revés. - -#### Sin Balance -`1 * 0.15 - 3 * 0.11 = -0.18` - -`3 * 0.15 - 1 * 0.11 = 0.34` - -#### Con balance -`1 - 3 = -2 => -2 * 0.11 = -0.22` - -`3 - 1 = 2 => 2 * 0.15 = 0.30` - - -Como vemos, en ambos casos el balance neto beneficia al usuario. - - -## ¿Qué hace este componente? - -Este componente va calculando tu balance horario actual así como el resultado al final de la hora. - -Para ello, debes indicar los kWh totales importados y exportados de tu inversor y el componente creará tres entidades nuevas: - -- Importación Neta -- Exportación Neta -- Balance Horario Actual - -Después podrás usar Importación Neta y Exportación Neta en el panel de Energía para que Home Assistant haga los calculos correctamente. - - -### Sin balance neto - -![Sin Balance](img/sin%20balance.png) - -### Con Balance - -![Con Balance](img/balance.png) - - - -## Instalación -Puedes instalar el componente usando HACS, para ello basta con añadir este repositorio a los repositorios personalizados y buscarlo escribiendo «balance». - -## Configuración - -Una vez instalado, ve a _Dispositivos y Servicios -> Añadir Integración_ y busca _Balance_. - -El asistente te solicitará 2 entidades: kWh totales importados de la red y kWh totales exportados a la red. - - - -## Uso -Una vez configurado el componente, usa como sensor de _consumo de red_ «Importación Neta» y _volcar a la red_ «Expotación Neta». - ->#### :warning: Si ya tienes histórico de datos en HA, al cambiar los sensores los datos antiguos dejarán de mostrarse. Si quieres mantener los datos tendrás que conectarse a la base de datos y copiar/actualizar los registros antiguos de importación/exportación a los de importación neta y exportación neta. - - -## Activar dispositivos cuando hay excedentes - -Gracias a la entidad de Balance Horario Actual podrás activar y desactivar dispositivos de alto consumo, como termos eléctricos, para aprovechar al máximo los excedentes. - -En vez de usar reguladores de potencia para adaptar el consumo a tu producción actual, puedes encender y apagar el dispositivo según el valor -del balance. Por ejemplo encender el termo/AC cuando el balance neto sea superior a 0.2kWh y apagarlo cuando sea inferior a -0.05kWh. - -De esta forma evitamos bajar la potencia al pasar una nube de forma puntual o no encender nunca un dispositivo de 1500W si nuestros excedentes son de 750W cuando podríamos tenerlo media hora encendido sin problema. - - -## Videotutorial - -[![Videotutorial](https://img.youtube.com/vi/tG9T1NYv2Cs/0.jpg)](https://www.youtube.com/watch?v=tG9T1NYv2Cs "Videotutorial") \ No newline at end of file diff --git a/README.md b/README.md index fd1ecfd..06a2011 100644 --- a/README.md +++ b/README.md @@ -1,74 +1,86 @@ -([Ver en español](README-es.md)) +# Componente Balance Neto para Home Assistant -# Net Balance Component for Home Assistant +([English version](README-en.md)) -## What is net balance? +## ¿Qué es el balance neto? -In Spain and other countries, users of photovoltaic panels with surplus compensation have hourly net balance, which calculates the final result of import and export every hour and bills accordingly. +En España, los usuarios de placas fotovoltáicas con compensación de excedentes disponen del balance neto horario en España (en otros paises es puede ser cada 15 min), el cual +calcula el resultado final de importación y exportación cada hora y en base a este se le factura. -To put it simply: If you export 3 kWh and import 1 kWh in one hour, it will simply be considered that you have exported 2 kWh. +Dicho más sencillo: Si en una hora exportas 3kWh e importas 1kWh, simplemente se considerará que has exportado 2kWh. -Since exporting is always cheaper than importing, this represents significant savings for the user. +Dado que la exportación siempre será más barata que la importación, esto supone un ahorro importante para el usuario. -### Example: +### Ejemplo: -Let's assume that importing costs €0.15/kWh, and exporting gives a discount of €0.11/kWh. In the first case, we export 3 kWh and import 1 kWh, and in the second case, it's the opposite. +Supongamos que importar cuesta 0.15€/kWh y exportar nos descuenta 0.11€/kWh, en el primer caso exportamos 3 e importamos 1, en el segundo al revés. -#### Without Balance -`1 * €0.15 - 3 * €0.11 = -€0.18` +#### Sin Balance +`1 * 0.15 - 3 * 0.11 = -0.18` -`3 * €0.15 - 1 * €0.11 = €0.34` +`3 * 0.15 - 1 * 0.11 = 0.34` -#### With Balance -`1 - 3 = -2 => -2 * €0.11 = -€0.22` +#### Con balance +`1 - 3 = -2 => -2 * 0.11 = -0.22` -`3 - 1 = 2 => 2 * €0.15 = €0.30` +`3 - 1 = 2 => 2 * 0.15 = 0.30` -As we can see, in both cases, net balance benefits the user. -## What does this component do? +Como vemos, en ambos casos el balance neto beneficia al usuario. -This component calculates your current hourly balance as well as the result at the end of the hour. -To do this, you need to provide the total imported and exported kWh from your inverter, and the component will create three new entities: +## ¿Qué hace este componente? -- Net Import -- Net Export -- Current Hourly Balance +Este componente va calculando tu balance net actual así como el resultado al final del periodo. -You can then use Net Import and Net Export in the Energy panel for Home Assistant to perform calculations correctly. +Para ello, debes indicar los kWh totales importados y exportados de tu inversor y el componente creará tres entidades nuevas: -### Without net metering +- Importación Neta +- Exportación Neta +- Balance Neto Actual -![Without Balance](img/sin%20balance.png) +Después podrás usar Importación Neta y Exportación Neta en el panel de Energía para que Home Assistant haga los calculos correctamente. -### With Balance -![With Balance](img/balance.png) +### Sin balance neto -## Installation +![Sin Balance](img/sin%20balance.png) -You can install the component using HACS. To do this, simply add this repository to your custom repositories and search for "balance neto". +### Con Balance -## Configuration +![Con Balance](img/balance.png) -Once installed, go to _Devices and Services -> Add Integration_ and search for _Balance_. -The assistant will ask for 2 entities: total import from grid kWh and total exported to grid kWh. -## Usage +## Instalación +Puedes instalar el componente usando HACS, para ello basta con añadir este repositorio a los repositorios personalizados y buscarlo escribiendo «balance». -Once the component is configured, use "Net Import" as the sensor for _network consumption_ and "Net Export" for _network feed_. +## Configuración ->#### :warning: If you already have historical data in HA, changing the sensors will stop displaying old data. If you want to keep the data, you will need to connect to the database and copy/update the old import/export records to the net import and net export records. +Una vez instalado, ve a _Dispositivos y Servicios -> Añadir Integración_ y busca _Balance_. -## Activating Devices When There Are Surpluses +El asistente te solicitará 2 entidades: kWh totales importados de la red y kWh totales exportados a la red. -Thanks to the Current Hourly Balance entity, you can activate and deactivate high-consumption devices, such as electric water heaters, to make the most of the surpluses. +Adicionalmente solicitará el periodo, que puede ser Horario (como es el caso de España) o cada cuarto de hora. -Instead of using power regulators to adjust consumption to your current production, you can turn the device on and off based on the balance value. For example, turn on the water heater/AC when the net balance is greater than 0.2 kWh and turn it off when it's less than -0.05 kWh. +Finalmente, puedes seleccionar un desfase de seguridad puesto que Home Assistant puede tardar un poco en realizar los cálculos, los realizará 5 segundos +antes de terminar el periodo, pero puede ser modificado si fuese necesario. -This way, we can avoid reducing power when a cloud passes by temporarily or never turning on a 1500W device if our surpluses are 750W when we could have it on for half an hour without any issues. + +## Uso +Una vez configurado el componente, usa como sensor de _consumo de red_ «Importación Neta» y _volcar a la red_ «Expotación Neta». + +>#### :warning: Si ya tienes histórico de datos en HA, al cambiar los sensores los datos antiguos dejarán de mostrarse. Si quieres mantener los datos tendrás que conectarse a la base de datos y copiar/actualizar los registros antiguos de importación/exportación a los de importación neta y exportación neta. + + +## Activar dispositivos cuando hay excedentes + +Gracias a la entidad de Balance Horario Actual podrás activar y desactivar dispositivos de alto consumo, como termos eléctricos, para aprovechar al máximo los excedentes. + +En vez de usar reguladores de potencia para adaptar el consumo a tu producción actual, puedes encender y apagar el dispositivo según el valor +del balance. Por ejemplo encender el termo/AC cuando el balance neto sea superior a 0.2kWh y apagarlo cuando sea inferior a -0.05kWh. + +De esta forma evitamos bajar la potencia al pasar una nube de forma puntual o no encender nunca un dispositivo de 1500W si nuestros excedentes son de 750W cuando podríamos tenerlo media hora encendido sin problema. ## Videotutorial diff --git a/custom_components/balance_neto/__init__.py b/custom_components/balance_neto/__init__.py index 5cfecb7..9fdc997 100644 --- a/custom_components/balance_neto/__init__.py +++ b/custom_components/balance_neto/__init__.py @@ -9,19 +9,27 @@ _LOGGER = logging.getLogger(__name__) -from .const import DOMAIN +from .const import DOMAIN, PERIOD, HOURLY, OFFSET PLATFORMS: list[Platform] = [Platform.SENSOR] async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) + entry.async_on_unload(entry.add_update_listener(_async_update_options)) return True -async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: - return True +async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool: + return await hass.config_entries.async_unload_platforms(config_entry, PLATFORMS) + + +async def _async_update_options(hass: HomeAssistant, config_entry: ConfigEntry) -> None: + """Handle options update.""" + # update entry replacing data with new options + hass.config_entries.async_update_entry(config_entry, data={**config_entry.data, **config_entry.options}) + await hass.config_entries.async_reload(config_entry.entry_id) async def async_migrate_entry(hass: HomeAssistant, config_entry): @@ -45,4 +53,16 @@ def _async_migrator(entity_entry: er.RegistryEntry): await er.async_migrate_entries(hass, config_entry.entry_id, _async_migrator) config_entry.version = 2 + if version == 2: + + data = { + **config_entry.data, + PERIOD: HOURLY, + OFFSET: 5, + } + + hass.config_entries.async_update_entry(config_entry, data=data) + + config_entry.version = 3 + return True diff --git a/custom_components/balance_neto/config_flow.py b/custom_components/balance_neto/config_flow.py index 202a32b..809fedc 100644 --- a/custom_components/balance_neto/config_flow.py +++ b/custom_components/balance_neto/config_flow.py @@ -8,29 +8,21 @@ from homeassistant import config_entries from homeassistant.components.sensor import SensorDeviceClass +from homeassistant.core import callback from homeassistant.data_entry_flow import FlowResult from homeassistant.helpers.selector import ( EntitySelector, - EntitySelectorConfig + EntitySelectorConfig, + SelectSelector, + SelectOptionDict, + SelectSelectorMode, + SelectSelectorConfig, NumberSelector, NumberSelectorConfig, ) - - -from .const import DOMAIN +from .const import DOMAIN, HOURLY, QUARTER, GRID_IMPORT, GRID_EXPORT, PERIOD, OFFSET _LOGGER = logging.getLogger(__name__) -STEP_USER_DATA_SCHEMA = vol.Schema( - { - vol.Required("grid_import"): EntitySelector( - EntitySelectorConfig(multiple=False, device_class=SensorDeviceClass.ENERGY) - ), - vol.Required("grid_export"): EntitySelector( - EntitySelectorConfig(multiple=False, device_class=SensorDeviceClass.ENERGY) - ) - } -) - class PlaceholderHub: def __init__(self, grid_import: str, grid_export: str) -> None: @@ -40,16 +32,81 @@ def __init__(self, grid_import: str, grid_export: str) -> None: class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): - VERSION = 2 + VERSION = 3 + + @staticmethod + @callback + def async_get_options_flow(config_entry): + return OptionFlowHandler(config_entry) async def async_step_user( self, user_input: dict[str, Any] | None = None ) -> FlowResult: + + schema = vol.Schema({ + vol.Required(GRID_IMPORT): EntitySelector( + EntitySelectorConfig(multiple=False, device_class=SensorDeviceClass.ENERGY) + ), + vol.Required(GRID_EXPORT): EntitySelector( + EntitySelectorConfig(multiple=False, device_class=SensorDeviceClass.ENERGY) + ), + vol.Required(PERIOD, default=HOURLY): SelectSelector( + SelectSelectorConfig(multiple=False, mode=SelectSelectorMode.DROPDOWN, + translation_key="periods", + options=[ + SelectOptionDict(label="Hourly", value=HOURLY), + SelectOptionDict(label="Quarter of an hour", value=QUARTER), + ]) + ), + vol.Required(OFFSET, default=5): NumberSelector( + NumberSelectorConfig(min=0, max=300, unit_of_measurement="s") + ), + }) + """Handle the initial step.""" if user_input is None: return self.async_show_form( - step_id="user", data_schema=STEP_USER_DATA_SCHEMA + step_id="user", data_schema=schema ) else: return self.async_create_entry(title="", data=user_input) + + +class OptionFlowHandler(config_entries.OptionsFlow): + def __init__(self, config_entry): + self.config_entry = config_entry + + async def async_step_init(self, user_input=None): + grid_import = self.config_entry.options.get(GRID_IMPORT, self.config_entry.data[GRID_IMPORT]) + grid_export = self.config_entry.options.get(GRID_EXPORT, self.config_entry.data[GRID_EXPORT]) + period = self.config_entry.options.get(PERIOD, self.config_entry.data[PERIOD]) + offset = self.config_entry.options.get(OFFSET, self.config_entry.data[OFFSET]) + + schema = vol.Schema({ + vol.Required(GRID_IMPORT, default=grid_import): EntitySelector( + EntitySelectorConfig(multiple=False, device_class=SensorDeviceClass.ENERGY) + ), + vol.Required(GRID_EXPORT, default=grid_export): EntitySelector( + EntitySelectorConfig(multiple=False, device_class=SensorDeviceClass.ENERGY) + ), + vol.Required(PERIOD, default=period): SelectSelector( + SelectSelectorConfig(multiple=False, mode=SelectSelectorMode.DROPDOWN, + translation_key="periods", + options=[ + SelectOptionDict(label="Hourly", value=HOURLY), + SelectOptionDict(label="Quarter of an hour", value=QUARTER), + ]) + ), + vol.Required(OFFSET, default=offset): NumberSelector( + NumberSelectorConfig(min=0, max=300, unit_of_measurement="s") + ), + }) + + """Handle the initial step.""" + if user_input is None: + return self.async_show_form( + step_id="init", data_schema=schema + ) + else: + return self.async_create_entry(title="", data=user_input) diff --git a/custom_components/balance_neto/const.py b/custom_components/balance_neto/const.py index a55dabc..fa46210 100644 --- a/custom_components/balance_neto/const.py +++ b/custom_components/balance_neto/const.py @@ -2,3 +2,12 @@ DOMAIN = "balance_neto" MAX_DIFF = 100.0 + +HOURLY = "hourly" +QUARTER = "quarter" + +PERIOD = "period" +OFFSET = "offset" +GRID_EXPORT = "grid_export" +GRID_IMPORT = "grid_import" + diff --git a/custom_components/balance_neto/sensor.py b/custom_components/balance_neto/sensor.py index de6f9a5..0fde43d 100644 --- a/custom_components/balance_neto/sensor.py +++ b/custom_components/balance_neto/sensor.py @@ -17,7 +17,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.event import async_track_point_in_time from homeassistant.helpers.event import async_track_state_change -from .const import MAX_DIFF +from .const import MAX_DIFF, GRID_IMPORT, GRID_EXPORT, OFFSET, PERIOD, HOURLY, QUARTER EXPORT_DESCRIPTION = SensorEntityDescription( key="net_exported", @@ -59,9 +59,10 @@ async def async_setup_entry( hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback ) -> None: - import_id = entry.data['grid_import'] - export_id = entry.data['grid_export'] - + offset = entry.data[OFFSET] + period = entry.data[PERIOD] + import_id = entry.data[GRID_IMPORT] + export_id = entry.data[GRID_EXPORT] grid_import = GridSensor(IMPORT_DESCRIPTION, f"{entry.entry_id}-import") grid_export = GridSensor(EXPORT_DESCRIPTION, f"{entry.entry_id}-export") @@ -69,6 +70,8 @@ async def async_setup_entry( async_add_entities([grid_import, grid_export, grid_balance]) + minutes = 60 if period == HOURLY else 15 + def update_values(changed_entity: str, old_state: State | None, new_state: State | None): grid_balance.update_values() @@ -79,14 +82,18 @@ def update_values(changed_entity: str, old_state: State | None, new_state: State async def update_totals_and_schedule(now): grid_balance.update_totals() - async_track_point_in_time(hass, update_totals_and_schedule, now + timedelta(hours=1)) + async_track_point_in_time(hass, update_totals_and_schedule, now + timedelta(minutes=minutes)) async def first_after_reboot(now): grid_export.after_reboot() grid_import.after_reboot() - next = datetime.now().replace(minute=59, second=55, microsecond=0) - async_track_point_in_time(hass, update_totals_and_schedule, next) + now = datetime.now().replace(second=0, microsecond=0) + + next_minutes = minutes - now.minute % minutes + next_reset = now.replace(second=0) + timedelta(minutes=next_minutes) - timedelta(seconds=offset) + + async_track_point_in_time(hass, update_totals_and_schedule, next_reset) hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STARTED, first_after_reboot) @@ -146,7 +153,6 @@ def __init__(self, description: SensorEntityDescription, self._attr_unique_id = unique_id self.entity_description = description - self._last_reset = None async def async_added_to_hass(self): await super().async_added_to_hass() @@ -156,7 +162,6 @@ async def async_added_to_hass(self): self._export = last_sensor_data.attributes.get('Export', 0) self._import_offset = last_sensor_data.attributes.get('Import Offset', 0) self._export_offset = last_sensor_data.attributes.get('Export Offset', 0) - self._last_reset = last_sensor_data.attributes.get('Last Reset') self.async_write_ha_state() @@ -171,7 +176,6 @@ def extra_state_attributes(self): 'Export': self._export, 'Import Offset': self._import_offset, 'Export Offset': self._export_offset, - 'Last Reset': self._last_reset } def _update_value(self): @@ -204,7 +208,7 @@ def update_values(self): self._export_offset = export_state _LOGGER.debug("Updating Balance Neto. Actual Import %f, Export %f. Import offset %f, Export offset %f", - import_state, export_state, self._import_offset, self._export_offset) + import_state, export_state, self._import_offset, self._export_offset) self._import = import_state self._export = export_state @@ -212,12 +216,12 @@ def update_values(self): self._update_value() except ValueError as e: _LOGGER.error(e) + _LOGGER.error("Errors values, Import %s and Export %s", self.hass.states.get(self._import_id).state, self.hass.states.get(self._export_id).state) return def update_totals(self): value = float(self._state) _LOGGER.debug("Updating net values. Balance %f") - self._last_reset = (datetime.utcnow() + timedelta(hours=1)).strftime("%Y-%m-%d %H:00:00") self._import_offset = self._import self._export_offset = self._export if value > 0: diff --git a/custom_components/balance_neto/translations/es.json b/custom_components/balance_neto/translations/es.json index e9ed005..a8b50be 100644 --- a/custom_components/balance_neto/translations/es.json +++ b/custom_components/balance_neto/translations/es.json @@ -7,11 +7,30 @@ "user": { "data": { "grid_import": "kWh totales importados", - "grid_export": "kWh totales exportados" + "grid_export": "kWh totales exportados", + "period": "Periodo", + "offset": "Desfase de seguridad." } } } }, + + "options": { + "error": { + "unknown": "Error inesperado" + }, + "step": { + "init": { + "data": { + "grid_import": "kWh totales importados", + "grid_export": "kWh totales exportados", + "period": "Periodo", + "offset": "Desfase de seguridad." + } + } + } + }, + "entity": { "sensor": { "net_exported": { @@ -24,5 +43,13 @@ "name": "Balance neto" } } + }, + "selector": { + "periods": { + "options": { + "hourly": "Horario", + "quarter": "Cuarto de hora" + } + } } } \ No newline at end of file