From 9b7d19b2f86b6d850edaa9090bc701fe82ade37d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20L=27hopital?= Date: Wed, 22 May 2024 12:28:03 +0200 Subject: [PATCH] [French Govt Energy Data] New binding (#16713) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gaël L'hopital Signed-off-by: clinique --- CODEOWNERS | 1 + bom/openhab-addons/pom.xml | 5 + .../NOTICE | 13 ++ .../README.md | 72 +++++++++ .../pom.xml | 17 ++ .../src/main/feature/feature.xml | 9 ++ .../FrenchGovtEnergyDataBindingConstants.java | 47 ++++++ .../FrenchGovtEnergyDataHandlerFactory.java | 53 +++++++ .../internal/dto/BaseTariff.java | 36 +++++ .../internal/dto/HpHcTariff.java | 40 +++++ .../internal/dto/Tariff.java | 62 ++++++++ .../internal/handler/BaseTariffHandler.java | 51 ++++++ .../internal/handler/HpHcTariffHandler.java | 54 +++++++ .../internal/handler/TariffHandler.java | 150 ++++++++++++++++++ .../src/main/resources/OH-INF/addon/addon.xml | 12 ++ .../i18n/frenchgovtenergydata.properties | 48 ++++++ .../resources/OH-INF/thing/thing-types.xml | 117 ++++++++++++++ bundles/pom.xml | 1 + 18 files changed, 788 insertions(+) create mode 100644 bundles/org.openhab.binding.frenchgovtenergydata/NOTICE create mode 100644 bundles/org.openhab.binding.frenchgovtenergydata/README.md create mode 100644 bundles/org.openhab.binding.frenchgovtenergydata/pom.xml create mode 100644 bundles/org.openhab.binding.frenchgovtenergydata/src/main/feature/feature.xml create mode 100644 bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/FrenchGovtEnergyDataBindingConstants.java create mode 100644 bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/FrenchGovtEnergyDataHandlerFactory.java create mode 100644 bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/dto/BaseTariff.java create mode 100644 bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/dto/HpHcTariff.java create mode 100644 bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/dto/Tariff.java create mode 100644 bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/handler/BaseTariffHandler.java create mode 100644 bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/handler/HpHcTariffHandler.java create mode 100644 bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/handler/TariffHandler.java create mode 100644 bundles/org.openhab.binding.frenchgovtenergydata/src/main/resources/OH-INF/addon/addon.xml create mode 100644 bundles/org.openhab.binding.frenchgovtenergydata/src/main/resources/OH-INF/i18n/frenchgovtenergydata.properties create mode 100644 bundles/org.openhab.binding.frenchgovtenergydata/src/main/resources/OH-INF/thing/thing-types.xml diff --git a/CODEOWNERS b/CODEOWNERS index a78c2dfdadb..a82897a8b96 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -119,6 +119,7 @@ /bundles/org.openhab.binding.freebox/ @lolodomo /bundles/org.openhab.binding.freeboxos/ @clinique /bundles/org.openhab.binding.freecurrency/ @J-N-K +/bundles/org.openhab.binding.frenchgovtenergydata/ @clinique /bundles/org.openhab.binding.fronius/ @trokohl /bundles/org.openhab.binding.fsinternetradio/ @paphko /bundles/org.openhab.binding.ftpupload/ @paulianttila diff --git a/bom/openhab-addons/pom.xml b/bom/openhab-addons/pom.xml index a51eeda5148..f0b12695efe 100644 --- a/bom/openhab-addons/pom.xml +++ b/bom/openhab-addons/pom.xml @@ -586,6 +586,11 @@ org.openhab.binding.freecurrency ${project.version} + + org.openhab.addons.bundles + org.openhab.binding.frenchgovtenergydata + ${project.version} + org.openhab.addons.bundles org.openhab.binding.fronius diff --git a/bundles/org.openhab.binding.frenchgovtenergydata/NOTICE b/bundles/org.openhab.binding.frenchgovtenergydata/NOTICE new file mode 100644 index 00000000000..38d625e3492 --- /dev/null +++ b/bundles/org.openhab.binding.frenchgovtenergydata/NOTICE @@ -0,0 +1,13 @@ +This content is produced and maintained by the openHAB project. + +* Project home: https://www.openhab.org + +== Declared Project Licenses + +This program and the accompanying materials are made available under the terms +of the Eclipse Public License 2.0 which is available at +https://www.eclipse.org/legal/epl-2.0/. + +== Source Code + +https://github.com/openhab/openhab-addons diff --git a/bundles/org.openhab.binding.frenchgovtenergydata/README.md b/bundles/org.openhab.binding.frenchgovtenergydata/README.md new file mode 100644 index 00000000000..7543aa37077 --- /dev/null +++ b/bundles/org.openhab.binding.frenchgovtenergydata/README.md @@ -0,0 +1,72 @@ +# French Government Energy Data Binding + +This binding provides regulated electricity prices in France. + +This can be used to plan energy consumption, for example to calculate the cheapest period for running a dishwasher or charging an EV. + +## Supported Things + +The binding offers things for the two usual tariff classes (proposed by example by EDF). + +- `base`: This is the basic subscription with a fixed kWh price. +- `hphc`: Alternative subscription offering variable price in a given hour set (low hours/high hours). + + +## Thing Configuration + +Things (both `base` and `hphc`) only offers the configuration of the power output of the electrical delivery point (Linky terminal). + +| Name | Type | Description | Default | Required | +|-----------------------|---------|---------------------------------------------|---------------|----------| +| puissance | integer | PDL power output (in kVA) | 6 | no | + + +## Channels + +### `base` Tariff Thing + +All channels are read-only. + +| Channel | Type | Description | Advanced | +|--------------|--------------------|-----------------------------------------|----------| +| fixed-ttc | Number:Currency | Yearly fixed price including taxes | No | +| variable-ttc | Number:EnergyPrice | Energy price in €/kWh including taxes | No | +| tariff-start | DateTime | Beginning date for this tariff | Yes | +| fixed-ht | Number:Currency | Yearly fixed price excluding taxes | Yes | +| variable-ht | Number:EnergyPrice | Energy price in €/kWh excluding taxes | Yes | + + +### `hphc` Tariff Thing + +All channels are read-only. + +| Channel | Type | Description | Advanced | +|--------------|--------------------|----------------------------------------------------|----------| +| fixed-ttc | Number:Currency | Yearly fixed price including taxes | No | +| hc-ttc | Number:EnergyPrice | Low hours energy price in €/kWh including taxes | No | +| hp-ttc | Number:EnergyPrice | High hours energy price in €/kWh including taxes | No | +| tariff-start | DateTime | Beginning date for this tariff | Yes | +| fixed-ht | Number:Currency | Yearly fixed price excluding taxes | Yes | +| hc-ht | Number:EnergyPrice | Low hours energy price in €/kWh excluding taxes | Yes | +| hp-ht | Number:EnergyPrice | High hours energy price in €/kWh excluding taxes | Yes | + + +## Full Example + + +### Thing Configuration + +```java +Thing frenchgovtenergydata:hphc:local "Tarification Actuelle HP/HC" [puissance=9] +``` + +### Item Configuration + +```java +DateTime Tarif_Start { channel="frenchgovtenergydata:hphc:local:tariff-start" } +Number:Currency Abonnement_Annuel {channel="frenchgovtenergydata:hphc:local:fixed-ttc"} +Number:EnergyPrice Prix_Heure_Pleine {channel="frenchgovtenergydata:hphc:local:hp-ttc"} +Number:EnergyPrice Prix_Heure_Creuse {channel="frenchgovtenergydata:hphc:local:hc-ttc"} +``` + + diff --git a/bundles/org.openhab.binding.frenchgovtenergydata/pom.xml b/bundles/org.openhab.binding.frenchgovtenergydata/pom.xml new file mode 100644 index 00000000000..b800cca5b49 --- /dev/null +++ b/bundles/org.openhab.binding.frenchgovtenergydata/pom.xml @@ -0,0 +1,17 @@ + + + + 4.0.0 + + + org.openhab.addons.bundles + org.openhab.addons.reactor.bundles + 4.2.0-SNAPSHOT + + + org.openhab.binding.frenchgovtenergydata + + openHAB Add-ons :: Bundles :: French Government Energy Data Binding + + diff --git a/bundles/org.openhab.binding.frenchgovtenergydata/src/main/feature/feature.xml b/bundles/org.openhab.binding.frenchgovtenergydata/src/main/feature/feature.xml new file mode 100644 index 00000000000..b0a7624ecf3 --- /dev/null +++ b/bundles/org.openhab.binding.frenchgovtenergydata/src/main/feature/feature.xml @@ -0,0 +1,9 @@ + + + mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features + + + openhab-runtime-base + mvn:org.openhab.addons.bundles/org.openhab.binding.frenchgovtenergydata/${project.version} + + diff --git a/bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/FrenchGovtEnergyDataBindingConstants.java b/bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/FrenchGovtEnergyDataBindingConstants.java new file mode 100644 index 00000000000..0ac1eedb5bf --- /dev/null +++ b/bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/FrenchGovtEnergyDataBindingConstants.java @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2010-2024 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.frenchgovtenergydata.internal; + +import java.util.Currency; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.thing.ThingTypeUID; + +/** + * The {@link FrenchGovtEnergyDataBindingConstants} class defines common constants, which are + * used across the whole binding. + * + * @author Gaël L'hopital - Initial contribution + */ +@NonNullByDefault +public class FrenchGovtEnergyDataBindingConstants { + + private static final String BINDING_ID = "frenchgovtenergydata"; + + // List of all Thing Type UIDs + public static final ThingTypeUID THING_TYPE_BASE = new ThingTypeUID(BINDING_ID, "base"); + public static final ThingTypeUID THING_TYPE_HPHC = new ThingTypeUID(BINDING_ID, "hphc"); + + // List of all Channel ids + public static final String CHANNEL_TARIFF_START = "tariff-start"; + public static final String CHANNEL_FIXED_HT = "fixed-ht"; + public static final String CHANNEL_FIXED_TTC = "fixed-ttc"; + public static final String CHANNEL_VARIABLE_HT = "variable-ht"; + public static final String CHANNEL_VARIABLE_TTC = "variable-ttc"; + public static final String CHANNEL_HC_HT = "hc-ht"; + public static final String CHANNEL_HC_TTC = "hc-ttc"; + public static final String CHANNEL_HP_HT = "hp-ht"; + public static final String CHANNEL_HP_TTC = "hp-ttc"; + + public static final Currency CURRENCY_EUR = Currency.getInstance("EUR"); +} diff --git a/bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/FrenchGovtEnergyDataHandlerFactory.java b/bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/FrenchGovtEnergyDataHandlerFactory.java new file mode 100644 index 00000000000..ed1adb58fc2 --- /dev/null +++ b/bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/FrenchGovtEnergyDataHandlerFactory.java @@ -0,0 +1,53 @@ +/** + * Copyright (c) 2010-2024 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.frenchgovtenergydata.internal; + +import static org.openhab.binding.frenchgovtenergydata.internal.FrenchGovtEnergyDataBindingConstants.*; + +import java.util.Set; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.frenchgovtenergydata.internal.handler.BaseTariffHandler; +import org.openhab.binding.frenchgovtenergydata.internal.handler.HpHcTariffHandler; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingTypeUID; +import org.openhab.core.thing.binding.BaseThingHandlerFactory; +import org.openhab.core.thing.binding.ThingHandler; +import org.openhab.core.thing.binding.ThingHandlerFactory; +import org.osgi.service.component.annotations.Component; + +/** + * The {@link FrenchGovtEnergyDataHandlerFactory} is responsible for creating things and thing handlers. + * + * @author Gaël L'hopital - Initial contribution + */ +@NonNullByDefault +@Component(configurationPid = "binding.frenchgovtenergydata", service = ThingHandlerFactory.class) +public class FrenchGovtEnergyDataHandlerFactory extends BaseThingHandlerFactory { + + private static final Set SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_BASE, THING_TYPE_HPHC); + + @Override + public boolean supportsThingType(ThingTypeUID thingTypeUID) { + return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID); + } + + @Override + protected @Nullable ThingHandler createHandler(Thing thing) { + ThingTypeUID thingTypeUID = thing.getThingTypeUID(); + + return THING_TYPE_BASE.equals(thingTypeUID) ? new BaseTariffHandler(thing) + : THING_TYPE_HPHC.equals(thingTypeUID) ? new HpHcTariffHandler(thing) : null; + } +} diff --git a/bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/dto/BaseTariff.java b/bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/dto/BaseTariff.java new file mode 100644 index 00000000000..31f20d207bd --- /dev/null +++ b/bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/dto/BaseTariff.java @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2010-2024 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.frenchgovtenergydata.internal.dto; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * The {@link BaseTariff} holds base price informations + * + * @author Gaël L'hopital - Initial contribution + */ +@NonNullByDefault +public class BaseTariff extends Tariff { + public final double variableHT; + public final double variableTTC; + + public BaseTariff(String line) { + super(line, 7); + try { + this.variableHT = Double.parseDouble(values[5]); + this.variableTTC = Double.parseDouble(values[6]); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Incorrect data in '%s'".formatted(line), e); + } + } +} diff --git a/bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/dto/HpHcTariff.java b/bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/dto/HpHcTariff.java new file mode 100644 index 00000000000..ec2964034fc --- /dev/null +++ b/bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/dto/HpHcTariff.java @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2010-2024 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.frenchgovtenergydata.internal.dto; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * The {@link HpHcTariff} holds HP-HC price informations + * + * @author Gaël L'hopital - Initial contribution + */ +@NonNullByDefault +public class HpHcTariff extends Tariff { + public final double hcHT; + public final double hcTTC; + public final double hpHT; + public final double hpTTC; + + public HpHcTariff(String line) { + super(line, 9); + try { + this.hcHT = Double.parseDouble(values[5]); + this.hcTTC = Double.parseDouble(values[6]); + this.hpHT = Double.parseDouble(values[7]); + this.hpTTC = Double.parseDouble(values[8]); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Incorrect data in '%s'".formatted(line), e); + } + } +} diff --git a/bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/dto/Tariff.java b/bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/dto/Tariff.java new file mode 100644 index 00000000000..05af28dc96d --- /dev/null +++ b/bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/dto/Tariff.java @@ -0,0 +1,62 @@ +/** + * Copyright (c) 2010-2024 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.frenchgovtenergydata.internal.dto; + +import java.time.LocalDate; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; + +/** + * The {@link Tariff} is the base class holding common information for Tariffs + * + * @author Gaël L'hopital - Initial contribution + */ +@NonNullByDefault +public class Tariff { + protected static final DateTimeFormatter TARIFF_DATE_FORMAT = DateTimeFormatter.ofPattern("dd/MM/yyyy"); + + protected final String[] values; + public final ZonedDateTime dateDebut; + public final @Nullable ZonedDateTime dateFin; + public final int puissance; + public final double fixeHT; + public final double fixeTTC; + + public Tariff(String line, int lenControl) { + this.values = line.replace(',', '.').split(";"); + if (values.length == lenControl) { + try { + this.dateDebut = LocalDate.parse(values[0], TARIFF_DATE_FORMAT).atStartOfDay(ZoneOffset.UTC); + this.dateFin = !values[1].isEmpty() + ? LocalDate.parse(values[1], TARIFF_DATE_FORMAT).atStartOfDay(ZoneOffset.UTC) + : null; + this.puissance = Integer.parseInt(values[2]); + this.fixeHT = Double.parseDouble(values[3]); + this.fixeTTC = Double.parseDouble(values[4]); + } catch (NumberFormatException | DateTimeParseException e) { + throw new IllegalArgumentException("Incorrect data in '%s'".formatted(line), e); + } + } else { + throw new IllegalArgumentException("Unexpected number of data, %d expected".formatted(lenControl)); + } + } + + public boolean isActive() { + return dateFin == null; + } +} diff --git a/bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/handler/BaseTariffHandler.java b/bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/handler/BaseTariffHandler.java new file mode 100644 index 00000000000..a68070e2bcf --- /dev/null +++ b/bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/handler/BaseTariffHandler.java @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2010-2024 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.frenchgovtenergydata.internal.handler; + +import static org.openhab.binding.frenchgovtenergydata.internal.FrenchGovtEnergyDataBindingConstants.*; + +import java.util.List; +import java.util.stream.Stream; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.frenchgovtenergydata.internal.dto.BaseTariff; +import org.openhab.core.library.types.QuantityType; +import org.openhab.core.library.unit.CurrencyUnits; +import org.openhab.core.thing.Thing; + +/** + * The {@link BaseTariffHandler} is responsible for handling commands, which are + * sent to one of the channels. + * + * @author Gaël L'hopital - Initial contribution + */ +@NonNullByDefault +public class BaseTariffHandler extends TariffHandler { + private static final String DATASET_ID = "c13d05e5-9e55-4d03-bf7e-042a2ade7e49"; + + public BaseTariffHandler(Thing thing) { + super(thing, DATASET_ID); + } + + @Override + protected Stream interpretLines(List lines) { + return lines.stream().map(BaseTariff::new); + } + + @Override + protected void updateChannels(BaseTariff tariff) { + super.updateChannels(tariff); + updateState(CHANNEL_VARIABLE_HT, new QuantityType<>(tariff.variableHT, CurrencyUnits.BASE_ENERGY_PRICE)); + updateState(CHANNEL_VARIABLE_TTC, new QuantityType<>(tariff.variableTTC, CurrencyUnits.BASE_ENERGY_PRICE)); + } +} diff --git a/bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/handler/HpHcTariffHandler.java b/bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/handler/HpHcTariffHandler.java new file mode 100644 index 00000000000..a63fed820be --- /dev/null +++ b/bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/handler/HpHcTariffHandler.java @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2010-2024 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.frenchgovtenergydata.internal.handler; + +import static org.openhab.binding.frenchgovtenergydata.internal.FrenchGovtEnergyDataBindingConstants.*; + +import java.util.List; +import java.util.stream.Stream; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.frenchgovtenergydata.internal.dto.HpHcTariff; +import org.openhab.core.library.types.QuantityType; +import org.openhab.core.library.unit.CurrencyUnits; +import org.openhab.core.thing.Thing; + +/** + * The {@link HpHcTariffHandler} is responsible for handling commands, which are + * sent to one of the channels. + * + * @author Gaël L'hopital - Initial contribution + */ +@NonNullByDefault +public class HpHcTariffHandler extends TariffHandler { + private static final String EMPTY_LINE = ";;;;;;;;"; + private static final String DATASET_ID = "f7303b3a-93c7-4242-813d-84919034c416"; + + public HpHcTariffHandler(Thing thing) { + super(thing, DATASET_ID); + } + + @Override + protected Stream interpretLines(List lines) { + return lines.stream().filter(line -> !line.equals(EMPTY_LINE)).map(HpHcTariff::new); + } + + @Override + protected void updateChannels(HpHcTariff tariff) { + super.updateChannels(tariff); + updateState(CHANNEL_HP_HT, new QuantityType<>(tariff.hpHT, CurrencyUnits.BASE_ENERGY_PRICE)); + updateState(CHANNEL_HP_TTC, new QuantityType<>(tariff.hpTTC, CurrencyUnits.BASE_ENERGY_PRICE)); + updateState(CHANNEL_HC_HT, new QuantityType<>(tariff.hcHT, CurrencyUnits.BASE_ENERGY_PRICE)); + updateState(CHANNEL_HC_TTC, new QuantityType<>(tariff.hcTTC, CurrencyUnits.BASE_ENERGY_PRICE)); + } +} diff --git a/bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/handler/TariffHandler.java b/bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/handler/TariffHandler.java new file mode 100644 index 00000000000..80e84ff014c --- /dev/null +++ b/bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/handler/TariffHandler.java @@ -0,0 +1,150 @@ +/** + * Copyright (c) 2010-2024 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.frenchgovtenergydata.internal.handler; + +import static org.openhab.binding.frenchgovtenergydata.internal.FrenchGovtEnergyDataBindingConstants.*; + +import java.io.IOException; +import java.math.BigDecimal; +import java.time.ZonedDateTime; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import javax.ws.rs.HttpMethod; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.frenchgovtenergydata.internal.dto.Tariff; +import org.openhab.core.io.net.http.HttpUtil; +import org.openhab.core.library.types.DateTimeType; +import org.openhab.core.library.types.QuantityType; +import org.openhab.core.library.unit.CurrencyUnits; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingStatus; +import org.openhab.core.thing.ThingStatusDetail; +import org.openhab.core.thing.ThingUID; +import org.openhab.core.thing.binding.BaseThingHandler; +import org.openhab.core.types.Command; +import org.openhab.core.types.RefreshType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The {@link TariffHandler} is the base class for Tariff Things. It takes care of + * update logic and update scheduling once a day. + * + * @author Gaël L'hopital - Initial contribution + */ +@NonNullByDefault +public abstract class TariffHandler extends BaseThingHandler { + private static final String URL = "https://www.data.gouv.fr/fr/datasets/r/%s"; + private static final int REFRESH_FIRST_HOUR_OF_DAY = 0; + private static final int REFRESH_FIRST_MINUTE_OF_DAY = 1; + + private final Logger logger = LoggerFactory.getLogger(TariffHandler.class); + private final List tariffs = new ArrayList<>(); + private final String url; + + private Optional> refreshJob = Optional.empty(); + private @Nullable String fileCache = null; + private int puissance = 6; + + public TariffHandler(Thing thing, String dataset) { + super(thing); + this.url = URL.formatted(dataset); + } + + @Override + public void initialize() { + updateStatus(ThingStatus.UNKNOWN); + Object confPower = getConfig().get("puissance"); + puissance = confPower != null ? ((BigDecimal) confPower).intValue() : 6; + refreshJob = Optional.of(scheduler.schedule(this::updateData, 1, TimeUnit.SECONDS)); + } + + @Override + public void dispose() { + refreshJob.ifPresent(job -> job.cancel(true)); + refreshJob = Optional.empty(); + super.dispose(); + } + + private @Nullable String readFile() { + @Nullable + String result = null; + try { + result = HttpUtil.executeUrl(HttpMethod.GET, url, 10000); + fileCache = result; + } catch (IOException e) { + // Use the cache if we had an error accessing the cloud resource + result = fileCache; + } + return result; + } + + private void updateData() { + ThingUID thingUID = getThing().getUID(); + logger.debug("Updating {} channels", thingUID); + + @Nullable + String result = readFile(); + if (result != null) { + List lines = new ArrayList<>(Arrays.asList(result.split("\r\n"))); + lines.remove(0); + + List newTariffs = interpretLines(lines).collect(Collectors.toList()); + if (!newTariffs.isEmpty()) { + tariffs.clear(); + tariffs.addAll(newTariffs); + } + + tariffs.stream().filter(t -> t.puissance == puissance).filter(Tariff::isActive).findFirst().ifPresentOrElse( + this::updateChannels, + () -> updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "No active tariff")); + + ZonedDateTime now = ZonedDateTime.now(); + ZonedDateTime nextUpdate = now.plusDays(1).withHour(REFRESH_FIRST_HOUR_OF_DAY) + .withMinute(REFRESH_FIRST_MINUTE_OF_DAY).truncatedTo(ChronoUnit.MINUTES); + long delay = ChronoUnit.MINUTES.between(now, nextUpdate); + logger.debug("Scheduling next {} update in {} minutes", thingUID, delay); + refreshJob = Optional.of(scheduler.schedule(this::updateData, delay, TimeUnit.MINUTES)); + } else { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, + "Unable to access %s".formatted(url)); + } + } + + protected void updateChannels(T tariff) { + updateStatus(ThingStatus.ONLINE); + updateState(CHANNEL_TARIFF_START, new DateTimeType(tariff.dateDebut)); + updateState(CHANNEL_FIXED_HT, new QuantityType<>(tariff.fixeHT, CurrencyUnits.BASE_CURRENCY)); + updateState(CHANNEL_FIXED_TTC, new QuantityType<>(tariff.fixeTTC, CurrencyUnits.BASE_CURRENCY)); + } + + protected abstract Stream interpretLines(List lines); + + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + if (RefreshType.REFRESH.equals(command)) { + updateData(); + } + } +} diff --git a/bundles/org.openhab.binding.frenchgovtenergydata/src/main/resources/OH-INF/addon/addon.xml b/bundles/org.openhab.binding.frenchgovtenergydata/src/main/resources/OH-INF/addon/addon.xml new file mode 100644 index 00000000000..9bad9f758f8 --- /dev/null +++ b/bundles/org.openhab.binding.frenchgovtenergydata/src/main/resources/OH-INF/addon/addon.xml @@ -0,0 +1,12 @@ + + + + binding + French Government Energy Data Binding + This binding provides French regulated electricity tariffs. + cloud + fr + + diff --git a/bundles/org.openhab.binding.frenchgovtenergydata/src/main/resources/OH-INF/i18n/frenchgovtenergydata.properties b/bundles/org.openhab.binding.frenchgovtenergydata/src/main/resources/OH-INF/i18n/frenchgovtenergydata.properties new file mode 100644 index 00000000000..2371f0e70df --- /dev/null +++ b/bundles/org.openhab.binding.frenchgovtenergydata/src/main/resources/OH-INF/i18n/frenchgovtenergydata.properties @@ -0,0 +1,48 @@ +# add-on + +addon.frenchgovtenergydata.name = French Government Energy Data Binding +addon.frenchgovtenergydata.description = This binding provides French regulated electricity tariffs. + +# thing types + +thing-type.frenchgovtenergydata.base.label = Base Tariff +thing-type.frenchgovtenergydata.base.description = Default Tariff Subscription +thing-type.frenchgovtenergydata.base.channel.fixed-ht.label = Fixed Price HT +thing-type.frenchgovtenergydata.base.channel.fixed-ht.description = Yearly fixed price excluding taxes. +thing-type.frenchgovtenergydata.base.channel.fixed-ttc.label = Fixed Price TTC +thing-type.frenchgovtenergydata.base.channel.fixed-ttc.description = Yearly fixed price including taxes. +thing-type.frenchgovtenergydata.base.channel.variable-ht.label = Variable Price HT +thing-type.frenchgovtenergydata.base.channel.variable-ht.description = Energy price in €/kWh excluding taxes. +thing-type.frenchgovtenergydata.base.channel.variable-ttc.label = Variable Price TTC +thing-type.frenchgovtenergydata.base.channel.variable-ttc.description = Energy price in €/kWh including taxes. +thing-type.frenchgovtenergydata.hphc.label = HP-HC Tariff +thing-type.frenchgovtenergydata.hphc.description = High / Low usage Tariff Subscription +thing-type.frenchgovtenergydata.hphc.channel.fixed-ht.label = Fixed Price HT +thing-type.frenchgovtenergydata.hphc.channel.fixed-ht.description = Yearly fixed price excluding taxes. +thing-type.frenchgovtenergydata.hphc.channel.fixed-ttc.label = Fixed Price TTC +thing-type.frenchgovtenergydata.hphc.channel.fixed-ttc.description = Yearly fixed price including taxes. +thing-type.frenchgovtenergydata.hphc.channel.hc-ht.label = Low Hours Price HT +thing-type.frenchgovtenergydata.hphc.channel.hc-ht.description = Low hours energy price in €/kWh excluding taxes. +thing-type.frenchgovtenergydata.hphc.channel.hc-ttc.label = Low Hours Price TTC +thing-type.frenchgovtenergydata.hphc.channel.hc-ttc.description = Low hours energy price in €/kWh including taxes. +thing-type.frenchgovtenergydata.hphc.channel.hp-ht.label = High Hours Price HT +thing-type.frenchgovtenergydata.hphc.channel.hp-ht.description = High hours energy price in €/kWh excluding taxes. +thing-type.frenchgovtenergydata.hphc.channel.hp-ttc.label = High Hours Price TTC +thing-type.frenchgovtenergydata.hphc.channel.hp-ttc.description = High hours energy price in €/kWh including taxes. + +# thing types config + +thing-type.config.frenchgovtenergydata.base.puissance.label = Power output +thing-type.config.frenchgovtenergydata.base.puissance.description = PDL power output (in kVA) +thing-type.config.frenchgovtenergydata.hphc.puissance.label = Power Output +thing-type.config.frenchgovtenergydata.hphc.puissance.description = PDL power output (in kVA) + +# channel types + +channel-type.frenchgovtenergydata.energy-price-ht.label = Variable Price HT +channel-type.frenchgovtenergydata.energy-price-ttc.label = Variable Price TTC +channel-type.frenchgovtenergydata.price-ht.label = Price HT +channel-type.frenchgovtenergydata.price-ttc.label = Price TTC +channel-type.frenchgovtenergydata.timestamp.label = Tariff Start +channel-type.frenchgovtenergydata.timestamp.description = Beginning date for this tariff +channel-type.frenchgovtenergydata.timestamp.state.pattern = %1$tY-%1$tm-%1$td diff --git a/bundles/org.openhab.binding.frenchgovtenergydata/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.frenchgovtenergydata/src/main/resources/OH-INF/thing/thing-types.xml new file mode 100644 index 00000000000..479b16f23ff --- /dev/null +++ b/bundles/org.openhab.binding.frenchgovtenergydata/src/main/resources/OH-INF/thing/thing-types.xml @@ -0,0 +1,117 @@ + + + + + + Default Tariff Subscription + + + + + + Yearly fixed price excluding taxes. + + + + Yearly fixed price including taxes. + + + + Energy price in €/kWh excluding taxes. + + + + Energy price in €/kWh including taxes. + + + + + + 6 + + PDL power output (in kVA) + + + + + + + High / Low usage Tariff Subscription + + + + + + Yearly fixed price excluding taxes. + + + + Yearly fixed price including taxes. + + + + Low hours energy price in €/kWh excluding taxes. + + + + Low hours energy price in €/kWh including taxes. + + + + High hours energy price in €/kWh excluding taxes. + + + + High hours energy price in €/kWh including taxes. + + + + + + 6 + + PDL power output (in kVA) + + + + + + Number:Currency + + Price + + + + + Number:Currency + + Price + + + + + DateTime + + Beginning date for this tariff + Time + + + + + Number:EnergyPrice + + Price + + + + + Number:EnergyPrice + + Price + + + + diff --git a/bundles/pom.xml b/bundles/pom.xml index 4ae522becfb..456712dea36 100644 --- a/bundles/pom.xml +++ b/bundles/pom.xml @@ -151,6 +151,7 @@ org.openhab.binding.freebox org.openhab.binding.freeboxos org.openhab.binding.freecurrency + org.openhab.binding.frenchgovtenergydata org.openhab.binding.fronius org.openhab.binding.fsinternetradio org.openhab.binding.ftpupload