]> git.basschouten.com Git - openhab-addons.git/commitdiff
[French Govt Energy Data] New binding (#16713)
authorGaël L'hopital <gael@lhopital.org>
Wed, 22 May 2024 10:28:03 +0000 (12:28 +0200)
committerGitHub <noreply@github.com>
Wed, 22 May 2024 10:28:03 +0000 (12:28 +0200)
Signed-off-by: Gaël L'hopital <gael@lhopital.org>
Signed-off-by: clinique <gael@lhopital.org>
18 files changed:
CODEOWNERS
bom/openhab-addons/pom.xml
bundles/org.openhab.binding.frenchgovtenergydata/NOTICE [new file with mode: 0644]
bundles/org.openhab.binding.frenchgovtenergydata/README.md [new file with mode: 0644]
bundles/org.openhab.binding.frenchgovtenergydata/pom.xml [new file with mode: 0644]
bundles/org.openhab.binding.frenchgovtenergydata/src/main/feature/feature.xml [new file with mode: 0644]
bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/FrenchGovtEnergyDataBindingConstants.java [new file with mode: 0644]
bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/FrenchGovtEnergyDataHandlerFactory.java [new file with mode: 0644]
bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/dto/BaseTariff.java [new file with mode: 0644]
bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/dto/HpHcTariff.java [new file with mode: 0644]
bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/dto/Tariff.java [new file with mode: 0644]
bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/handler/BaseTariffHandler.java [new file with mode: 0644]
bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/handler/HpHcTariffHandler.java [new file with mode: 0644]
bundles/org.openhab.binding.frenchgovtenergydata/src/main/java/org/openhab/binding/frenchgovtenergydata/internal/handler/TariffHandler.java [new file with mode: 0644]
bundles/org.openhab.binding.frenchgovtenergydata/src/main/resources/OH-INF/addon/addon.xml [new file with mode: 0644]
bundles/org.openhab.binding.frenchgovtenergydata/src/main/resources/OH-INF/i18n/frenchgovtenergydata.properties [new file with mode: 0644]
bundles/org.openhab.binding.frenchgovtenergydata/src/main/resources/OH-INF/thing/thing-types.xml [new file with mode: 0644]
bundles/pom.xml

index a78c2dfdadb8519460bc52a16fdba15bc10b25ff..a82897a8b9633bb4e4796e22a4193c918e29ff77 100644 (file)
 /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
index a51eeda514884ca7ff26646bf61b4013a1c7fd69..f0b12695efedaa55d9a070bebe9215d09457bb49 100644 (file)
       <artifactId>org.openhab.binding.freecurrency</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.openhab.addons.bundles</groupId>
+      <artifactId>org.openhab.binding.frenchgovtenergydata</artifactId>
+      <version>${project.version}</version>
+    </dependency>
     <dependency>
       <groupId>org.openhab.addons.bundles</groupId>
       <artifactId>org.openhab.binding.fronius</artifactId>
diff --git a/bundles/org.openhab.binding.frenchgovtenergydata/NOTICE b/bundles/org.openhab.binding.frenchgovtenergydata/NOTICE
new file mode 100644 (file)
index 0000000..38d625e
--- /dev/null
@@ -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 (file)
index 0000000..7543aa3
--- /dev/null
@@ -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 (file)
index 0000000..b800cca
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.openhab.addons.bundles</groupId>
+    <artifactId>org.openhab.addons.reactor.bundles</artifactId>
+    <version>4.2.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>org.openhab.binding.frenchgovtenergydata</artifactId>
+
+  <name>openHAB Add-ons :: Bundles :: French Government Energy Data Binding</name>
+
+</project>
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 (file)
index 0000000..b0a7624
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<features name="org.openhab.binding.frenchgovtenergydata-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
+       <repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
+
+       <feature name="openhab-binding-frenchgovtenergydata" description="French Government Energy Data Binding" version="${project.version}">
+               <feature>openhab-runtime-base</feature>
+               <bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.frenchgovtenergydata/${project.version}</bundle>
+       </feature>
+</features>
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 (file)
index 0000000..0ac1eed
--- /dev/null
@@ -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 (file)
index 0000000..ed1adb5
--- /dev/null
@@ -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<ThingTypeUID> 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 (file)
index 0000000..31f20d2
--- /dev/null
@@ -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 (file)
index 0000000..ec29640
--- /dev/null
@@ -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 (file)
index 0000000..05af28d
--- /dev/null
@@ -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 (file)
index 0000000..a68070e
--- /dev/null
@@ -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<BaseTariff> {
+    private static final String DATASET_ID = "c13d05e5-9e55-4d03-bf7e-042a2ade7e49";
+
+    public BaseTariffHandler(Thing thing) {
+        super(thing, DATASET_ID);
+    }
+
+    @Override
+    protected Stream<BaseTariff> interpretLines(List<String> 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 (file)
index 0000000..a63fed8
--- /dev/null
@@ -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<HpHcTariff> {
+    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<HpHcTariff> interpretLines(List<String> 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 (file)
index 0000000..80e84ff
--- /dev/null
@@ -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<T extends Tariff> 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<T> tariffs = new ArrayList<>();
+    private final String url;
+
+    private Optional<ScheduledFuture<?>> 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<String> lines = new ArrayList<>(Arrays.asList(result.split("\r\n")));
+            lines.remove(0);
+
+            List<T> 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<T> interpretLines(List<String> 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 (file)
index 0000000..9bad9f7
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<addon:addon id="frenchgovtenergydata" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:addon="https://openhab.org/schemas/addon/v1.0.0"
+       xsi:schemaLocation="https://openhab.org/schemas/addon/v1.0.0 https://openhab.org/schemas/addon-1.0.0.xsd">
+
+       <type>binding</type>
+       <name>French Government Energy Data Binding</name>
+       <description>This binding provides French regulated electricity tariffs.</description>
+       <connection>cloud</connection>
+       <countries>fr</countries>
+
+</addon:addon>
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 (file)
index 0000000..2371f0e
--- /dev/null
@@ -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 (file)
index 0000000..479b16f
--- /dev/null
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<thing:thing-descriptions bindingId="frenchgovtenergydata"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
+       xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
+
+       <thing-type id="base">
+               <label>Base Tariff</label>
+               <description>Default Tariff Subscription</description>
+
+               <channels>
+                       <channel id="tariff-start" typeId="timestamp"/>
+                       <channel id="fixed-ht" typeId="price-ht">
+                               <label>Fixed Price HT</label>
+                               <description>Yearly fixed price excluding taxes.</description>
+                       </channel>
+                       <channel id="fixed-ttc" typeId="price-ttc">
+                               <label>Fixed Price TTC</label>
+                               <description>Yearly fixed price including taxes.</description>
+                       </channel>
+                       <channel id="variable-ht" typeId="energy-price-ht">
+                               <label>Variable Price HT</label>
+                               <description>Energy price in €/kWh excluding taxes.</description>
+                       </channel>
+                       <channel id="variable-ttc" typeId="energy-price-ttc">
+                               <label>Variable Price TTC</label>
+                               <description>Energy price in €/kWh including taxes.</description>
+                       </channel>
+               </channels>
+
+               <config-description>
+                       <parameter name="puissance" type="integer" min="3" max="36">
+                               <default>6</default>
+                               <label>Power output</label>
+                               <description>PDL power output (in kVA)</description>
+                       </parameter>
+               </config-description>
+       </thing-type>
+
+       <thing-type id="hphc">
+               <label>HP-HC Tariff</label>
+               <description>High / Low usage Tariff Subscription</description>
+
+               <channels>
+                       <channel id="tariff-start" typeId="timestamp"/>
+                       <channel id="fixed-ht" typeId="price-ht">
+                               <label>Fixed Price HT</label>
+                               <description>Yearly fixed price excluding taxes.</description>
+                       </channel>
+                       <channel id="fixed-ttc" typeId="price-ttc">
+                               <label>Fixed Price TTC</label>
+                               <description>Yearly fixed price including taxes.</description>
+                       </channel>
+                       <channel id="hc-ht" typeId="energy-price-ht">
+                               <label>Low Hours Price HT</label>
+                               <description>Low hours energy price in €/kWh excluding taxes.</description>
+                       </channel>
+                       <channel id="hc-ttc" typeId="energy-price-ttc">
+                               <label>Low Hours Price TTC</label>
+                               <description>Low hours energy price in €/kWh including taxes.</description>
+                       </channel>
+                       <channel id="hp-ht" typeId="energy-price-ht">
+                               <label>High Hours Price HT</label>
+                               <description>High hours energy price in €/kWh excluding taxes.</description>
+                       </channel>
+                       <channel id="hp-ttc" typeId="energy-price-ttc">
+                               <label>High Hours Price TTC</label>
+                               <description>High hours energy price in €/kWh including taxes.</description>
+                       </channel>
+               </channels>
+
+               <config-description>
+                       <parameter name="puissance" type="integer" min="3" max="36">
+                               <default>6</default>
+                               <label>Power Output</label>
+                               <description>PDL power output (in kVA)</description>
+                       </parameter>
+               </config-description>
+       </thing-type>
+
+       <channel-type id="price-ht" advanced="true">
+               <item-type>Number:Currency</item-type>
+               <label>Price HT</label>
+               <category>Price</category>
+               <state readOnly="true" pattern="%.2f %unit%"></state>
+       </channel-type>
+
+       <channel-type id="price-ttc">
+               <item-type>Number:Currency</item-type>
+               <label>Price TTC</label>
+               <category>Price</category>
+               <state readOnly="true" pattern="%.2f %unit%"></state>
+       </channel-type>
+
+       <channel-type id="timestamp" advanced="true">
+               <item-type>DateTime</item-type>
+               <label>Tariff Start</label>
+               <description>Beginning date for this tariff</description>
+               <category>Time</category>
+               <state readOnly="true" pattern="%1$tY-%1$tm-%1$td"/>
+       </channel-type>
+
+       <channel-type id="energy-price-ht" advanced="true">
+               <item-type>Number:EnergyPrice</item-type>
+               <label>Variable Price HT</label>
+               <category>Price</category>
+               <state readOnly="true" pattern="%.4f %unit%"></state>
+       </channel-type>
+
+       <channel-type id="energy-price-ttc">
+               <item-type>Number:EnergyPrice</item-type>
+               <label>Variable Price TTC</label>
+               <category>Price</category>
+               <state readOnly="true" pattern="%.4f %unit%"></state>
+       </channel-type>
+
+</thing:thing-descriptions>
index 4ae522becfb843870d890ebf66f99b3d4830413b..456712dea36270d6e7371480c9349c9d6351e0e6 100644 (file)
     <module>org.openhab.binding.freebox</module>
     <module>org.openhab.binding.freeboxos</module>
     <module>org.openhab.binding.freecurrency</module>
+    <module>org.openhab.binding.frenchgovtenergydata</module>
     <module>org.openhab.binding.fronius</module>
     <module>org.openhab.binding.fsinternetradio</module>
     <module>org.openhab.binding.ftpupload</module>