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 fa50f961547..006301da619 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