Skip to content
Open
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
2b565eb
start implementing new reading method using index api (will support f…
lo92fr Aug 11, 2025
a5b1bfc
add new channel for idx Fournisseur data
lo92fr Aug 11, 2025
c517d5b
backport fixes from branch linky-fix-2025-09
lo92fr Sep 6, 2025
bce7914
backport fixes from branch linky-fix-2025-09
lo92fr Sep 7, 2025
a6ea2d1
fix error on URL
lo92fr Sep 7, 2025
671729b
move dto to double to simplify code
lo92fr Sep 14, 2025
177694b
spotless:apply
lo92fr Sep 14, 2025
f6ea945
review agregat conversion to simplify code
lo92fr Sep 14, 2025
12d96aa
add support for other distributor and supplier index
lo92fr Sep 17, 2025
916f06f
add channel for Index
lo92fr Sep 18, 2025
302ff65
fix bad indexing for supplier & distributor index
lo92fr Sep 18, 2025
8261bee
fix error on index date provoking bad data alignment
lo92fr Sep 18, 2025
925585e
review data array bound when using index
lo92fr Sep 18, 2025
04a0725
add code to handle missing value in data retrieve
lo92fr Sep 19, 2025
75cde7f
remove Idx channel name from resource, will be handle dynamically by …
lo92fr Sep 19, 2025
14a7460
introduce support for different tarif inside a dataset result:
lo92fr Sep 19, 2025
5ffe047
progress on tarif support
lo92fr Sep 19, 2025
98d0b5f
fix for first index, we don't have the necessary value to calc it, so…
lo92fr Sep 19, 2025
359373d
fix condition location
lo92fr Sep 20, 2025
4015928
code refactoring for simplifications
lo92fr Sep 20, 2025
d478c54
code refactoring to simplify code
lo92fr Sep 20, 2025
fa59f1f
code refactoring to simplify code
lo92fr Sep 21, 2025
9f2287d
Merge branch 'main' into features/linky-index
lo92fr Sep 21, 2025
582f9d5
spotless:apply
lo92fr Sep 21, 2025
b2b3775
mvn spotless:apply
lo92fr Sep 21, 2025
c679e33
fix sat errors
lo92fr Sep 21, 2025
38b58e0
review documentation to add new index Stuff
lo92fr Sep 21, 2025
e376830
fixes for copilot review of 21/09
lo92fr Sep 21, 2025
84c731d
fixes for copilot review of 21/09
lo92fr Sep 21, 2025
0aecb2f
@lolodomo review of 12/10
lo92fr Oct 12, 2025
68f68d4
fixes for @lolodomo review of 18/10/2025
lo92fr Oct 18, 2025
eef3259
fixes for @lolodomo review of 19/10, part 1
lo92fr Oct 19, 2025
b607e88
fix sat errors
lo92fr Oct 19, 2025
a566206
fixes after @lolodomo review of 19/10.
lo92fr Oct 20, 2025
5c20fdb
add a test to prevent error on gateway that use api and don't current…
lo92fr Oct 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
274 changes: 270 additions & 4 deletions bundles/org.openhab.binding.linky/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ Step are:

``` java
Bridge linky:enedis:local "EnedisWebBridge" [
username="laurent@clae.net",
password="Mnbo32tyu123!",
internalAuthId="eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.u_mxXO7_d4I5bLvJzGtc2MARvpkYv0iM0EsO6a24k-tW9493_Myxwg.LVlfephhGTiCBxii8bRIkA.GOf9Ea8PTGshvkfjl62b6w.hSH97IkmBcEAz2udU-FqQg"] {
username="myUserName@myDomain.com",
password="MyPassword",
internalAuthId="zeJhbGciOiJBMTIdaqzerZiLCJlbmMiOiJBMTIcwxdsq..."] {
}
```

Expand Down Expand Up @@ -251,6 +251,40 @@ The retrieved information is available in multiple groups.
| contactMail | The usage point Contact Mail |
| contactPhone | The usage point Contact Phone |

#### Dynamic Thing Channels

#### Dynamic Thing Channels

Add-ons now support reading consumption indexes from the Enedis website.
This makes it possible to view consumption for different tariffs such as *heures pleines / heures creuses* or *tempo*.

To handle this, add-ons will create a new set of channels for daily, weekly, monthly, and yearly groups.

You will have two different sets of indexes:

- **Raw consumption indexes:**
These are the default indexes returned by Enedis. The naming uses base indexes, so there is no direct way to know which tariff each index corresponds to.
Channels will be named as follows:



consumptionSupplierIdx0, consumptionSupplierIdx1, ..., consumptionSupplierIdx9
consumptionDistributorIdx0, consumptionDistributorIdx1, ..., consumptionDistributorIdx3

In France, the distributor is most often Enedis — they are responsible for distributing electricity on your network.
The supplier is the commercial company with which you have a contract (EDF, TotalEnergies, etc.). This is where your specific supplier tariff is defined.

- **Named consumption indexes:**
To make things simpler, the add-ons also expose tariff-named channels.
For example:

daily#heuresPleines, daily#heuresCreuses, daily#bleuHeuresCreuses,
daily#bleuHeuresPleines, daily#redHeuresCreuses, ...

⚠️ **Warning:**
Dynamic channels and indexes are currently only supported with the **EnedisWebBridge**.
Support for other bridges will be introduced later, once Enedis provides an API to access this data.

### Full Example

#### Remote Enedis Web Connection
Expand All @@ -273,7 +307,7 @@ Number:Energy ConsoAnneeDerniere "Conso année dernière [%.0f %unit%]" <energy>

### Displaying Information Graph

Using the timeseries channel, you will be able to easily create a calendar graph to display the Tempo calendar.
Using the timeseries channel, you will be able to easily create a chart to show the consumption graph.
To do this, you need to enable a timeseries persistence framework.
Graph definitions will look like this:

Expand Down Expand Up @@ -354,6 +388,238 @@ slots:
nameLocation: center
```

### Displaying Information Graph / New version with tarif

Using the timeseries channel and new version of the addons, you will be able to easily create a chart to show the consumption graph with tarif differenciation.
To do this, you need to enable a timeseries persistence framework.
Graph definitions will look like this:

![TempoGraph](doc/GraphConsoWithTarif.png)

Sample code:

```java
config:
future: false
label: Linky Melody Conso Monthly 2
order: "9999999"
period: Y
sidebar: true
slots:
dataZoom:
- component: oh-chart-datazoom
config:
type: inside
grid:
- component: oh-chart-grid
config:
containLabel: true
includeLabels: true
show: true
legend:
- component: oh-chart-legend
config:
bottom: 3
orient: horizontal
show: true
type: scroll
series:
- component: oh-time-series
config:
barGap: -100%
gridIndex: 0
item: Linky_Melody_Monthly_Conso_Month
label:
formatter: =v=>Number.parseFloat(v.data[1]).toFixed(2) + " Kwh"
position: top
show: true
name: Consumption
noBoundary: true
noItemState: true
service: inmemory
type: bar
xAxisIndex: 0
yAxisIndex: 0
- component: oh-time-series
config:
color: "#1010ff"
gridIndex: 0
item: Linky_Melody_Monthly_Supplier_Conso_Month_Heures_Pleines_Bleue
label:
formatter: =v=>v.data[1]!="0"?Number.parseFloat(v.data[1]).toFixed(2) + "
Kwh":''
position: inside
show: true
name: Bleue HP
noBoundary: true
noItemState: true
service: inmemory
stack: total
type: bar
xAxisIndex: 0
yAxisIndex: 0
- component: oh-time-series
config:
color: "#f0f0f0"
emphasis:
disabled: true
gridIndex: 0
item: Linky_Melody_Monthly_Supplier_Conso_Month_Heures_Pleines_Blanc
label:
formatter: =v=>v.data[1]!="0"?Number.parseFloat(v.data[1]).toFixed(2) + "
Kwh":''
position: inside
show: true
name: Blanc HP
noBoundary: true
noItemState: true
service: inmemory
stack: total
type: bar
xAxisIndex: 0
yAxisIndex: 0
- component: oh-time-series
config:
color: "#ff7070"
emphasis:
disabled: true
gridIndex: 0
item: Linky_Melody_Monthly_Supplier_Conso_Month_Heures_Creuses_Rouge
label:
formatter: =v=>v.data[1]!="0"?Number.parseFloat(v.data[1]).toFixed(2) + "
Kwh":''
position: inside
show: true
name: Rouge HC
noBoundary: true
noItemState: true
service: inmemory
stack: total
type: bar
xAxisIndex: 0
yAxisIndex: 0
- component: oh-time-series
config:
color: "#d0d0d0"
emphasis:
disabled: true
gridIndex: 0
item: Linky_Melody_Monthly_Supplier_Conso_Month_Heures_Creuses_Blanc
label:
formatter: =v=>v.data[1]!="0"?Number.parseFloat(v.data[1]).toFixed(2) + "
Kwh":''
position: inside
show: true
name: Blanc HC
noBoundary: true
noItemState: true
service: inmemory
stack: total
type: bar
xAxisIndex: 0
yAxisIndex: 0
- component: oh-time-series
config:
color: "#7070ff"
emphasis:
disabled: true
gridIndex: 0
item: Linky_Melody_Monthly_Supplier_Conso_Month_Heures_Creuses_Bleue
label:
formatter: =v=>v.data[1]!="0"?Number.parseFloat(v.data[1]).toFixed(2) + "
Kwh":''
position: inside
show: true
name: Bleue HC
noBoundary: true
noItemState: true
service: inmemory
stack: total
type: bar
xAxisIndex: 0
yAxisIndex: 0
- component: oh-time-series
config:
color: "#ff1010"
emphasis:
disabled: true
gridIndex: 0
item: Linky_Melody_Monthly_Supplier_Conso_Month_Heures_Pleines_Rouge
label:
formatter: =v=>v.data[1]!="0"?Number.parseFloat(v.data[1]).toFixed(2) + "
Kwh":''
position: inside
show: true
name: Rouge HP
noBoundary: true
noItemState: true
service: inmemory
stack: total
type: bar
xAxisIndex: 0
yAxisIndex: 0
- component: oh-time-series
config:
color: "#00ff00"
emphasis:
disabled: true
gridIndex: 0
item: Linky_Melody_Monthly_Supplier_Conso_Month_Heures_Pleines
label:
formatter: =v=>v.data[1]!="0"?Number.parseFloat(v.data[1]).toFixed(2) + "
Kwh":''
position: inside
show: true
name: HP
noBoundary: true
noItemState: true
service: inmemory
stack: total
type: bar
xAxisIndex: 0
yAxisIndex: 0
- component: oh-time-series
config:
color: "#80ff80"
emphasis:
disabled: true
gridIndex: 0
item: Linky_Melody_Monthly_Supplier_Conso_Month_Heures_Creuses
label:
formatter: =v=>v.data[1]!="0"?Number.parseFloat(v.data[1]).toFixed(2) + "
Kwh":''
position: inside
show: true
name: HC
noBoundary: true
noItemState: true
service: inmemory
stack: total
type: bar
xAxisIndex: 0
yAxisIndex: 0
tooltip:
- component: oh-chart-tooltip
config:
confine: true
orient: vertical
show: true
smartFormatter: true
visualMap: []
xAxis:
- component: oh-time-axis
config:
gridIndex: 0
nameLocation: center
splitNumber: 10
yAxis:
- component: oh-value-axis
config:
gridIndex: 0
name: kWh
nameLocation: center
```

## Getting Tempo Calendar Information

### Tempo Thing Channels
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ public Contact getContact(ThingLinkyRemoteHandler handler, String prmId) throws
}

private MeterReading getMeasures(ThingLinkyRemoteHandler handler, String apiUrl, String mps, String prmId,
String segment, LocalDate from, LocalDate to) throws LinkyException {
String segment, LocalDate from, LocalDate to, boolean useIndex) throws LinkyException {
String dtStart = from.format(linkyBridgeHandler.getApiDateFormat());
String dtEnd = to.format(linkyBridgeHandler.getApiDateFormat());

Expand All @@ -270,23 +270,28 @@ private MeterReading getMeasures(ThingLinkyRemoteHandler handler, String apiUrl,
} else {
String url = String.format(apiUrl, mps, prmId, segment, dtStart, dtEnd);
ConsumptionReport consomptionReport = getData(handler, url, ConsumptionReport.class);
return MeterReading.convertFromComsumptionReport(consomptionReport);
return MeterReading.convertFromComsumptionReport(consomptionReport, useIndex);
}
}

public MeterReading getEnergyData(ThingLinkyRemoteHandler handler, String mps, String prmId, String segment,
LocalDate from, LocalDate to) throws LinkyException {
return getMeasures(handler, linkyBridgeHandler.getDailyConsumptionUrl(), mps, prmId, segment, from, to);
return getMeasures(handler, linkyBridgeHandler.getDailyConsumptionUrl(), mps, prmId, segment, from, to, false);
}

public MeterReading getEnergyIndex(ThingLinkyRemoteHandler handler, String mps, String prmId, String segment,
LocalDate from, LocalDate to) throws LinkyException {
return getMeasures(handler, linkyBridgeHandler.getDailyIndexUrl(), mps, prmId, segment, from, to, true);
}

public MeterReading getLoadCurveData(ThingLinkyRemoteHandler handler, String mps, String prmId, String segment,
LocalDate from, LocalDate to) throws LinkyException {
return getMeasures(handler, linkyBridgeHandler.getLoadCurveUrl(), mps, prmId, segment, from, to);
return getMeasures(handler, linkyBridgeHandler.getLoadCurveUrl(), mps, prmId, segment, from, to, false);
}

public MeterReading getPowerData(ThingLinkyRemoteHandler handler, String mps, String prmId, String segment,
LocalDate from, LocalDate to) throws LinkyException {
return getMeasures(handler, linkyBridgeHandler.getMaxPowerUrl(), mps, prmId, segment, from, to);
return getMeasures(handler, linkyBridgeHandler.getMaxPowerUrl(), mps, prmId, segment, from, to, false);
}

public ResponseTempo getTempoData(ThingBaseRemoteHandler handler, LocalDate from, LocalDate to)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ public class LinkyBindingConstants {
public static final String LINKY_TEMPO_CALENDAR_GROUP = "tempo-calendar";
public static final String LINKY_REMOTE_LOAD_CURVE_GROUP = "load-curve";

public static final String CONSUMPTION = "consumption";

// List of all Channel id's
public static final String CHANNEL_CONSUMPTION = "consumption";
public static final String CHANNEL_MAX_POWER = "max-power";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright (c) 2010-2025 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.linky.internal.dto;

/**
* The {@link Calendrier} holds informations about energy consumption
*
* @author Gaël L'hopital - Initial contribution
* @author Laurent Arnal - Rewrite addon to use official dataconect API
*/

public class Calendrier {
public String idCalendrier;
public String libelleCalendrier;
}
Loading