[teleinfo] Add support for Standard tic mode (#11375)

* Add a ticMode parameter to serial controller

Signed-off-by: Olivier Marceau <hollysaiqs@marceau.ovh>

* Improve checksum verification

Signed-off-by: Olivier Marceau <hollysaiqs@marceau.ovh>

* Add parameter to deactivate checksum verification

Signed-off-by: Olivier Marceau <hollysaiqs@marceau.ovh>

* Add standard field labels

Signed-off-by: Olivier Marceau <hollysaiqs@marceau.ovh>

* Add things and channels for standard tic mode

Signed-off-by: Olivier Marceau <hollysaiqs@marceau.ovh>

* Add standard tic mode timestamp

Signed-off-by: Olivier Marceau <hollysaiqs@marceau.ovh>

* Fix typo

Signed-off-by: Olivier Marceau <hollysaiqs@marceau.ovh>

* Add some required null annotation

Signed-off-by: Olivier Marceau <hollysaiqs@marceau.ovh>

* Add parser for relais states

Signed-off-by: Olivier Marceau <hollysaiqs@marceau.ovh>

* Add relais channels and refactor standard mode channels

Signed-off-by: Olivier Marceau <hollysaiqs@marceau.ovh>

* Add @NonNullByDefault on enum

Signed-off-by: Olivier Marceau <hollysaiqs@marceau.ovh>

* Update documentation

Signed-off-by: Olivier Marceau <hollysaiqs@marceau.ovh>

* Fix formula in documentation

Signed-off-by: Olivier Marceau <hollysaiqs@marceau.ovh>

* Fix code issues

Signed-off-by: Olivier Marceau <hollysaiqs@marceau.ovh>

* Move channel type description in same file than channel group type description

Signed-off-by: Olivier Marceau <hollysaiqs@marceau.ovh>

* Add pattern specification to dateTime channel type

Signed-off-by: Olivier Marceau <hollysaiqs@marceau.ovh>

* Add missing channelGroup id in channel UID

Signed-off-by: Olivier Marceau <hollysaiqs@marceau.ovh>

* Add trace log

Signed-off-by: Olivier Marceau <hollysaiqs@marceau.ovh>

* Fix group labels

Signed-off-by: Olivier Marceau <hollysaiqs@marceau.ovh>

* Make labels uppercase

Signed-off-by: Olivier Marceau <hollysaiqs@marceau.ovh>

* Make options lowercase

Signed-off-by: Olivier Marceau <hollysaiqs@marceau.ovh>

* Simplify group label

Signed-off-by: Olivier Marceau <hollysaiqs@marceau.ovh>
This commit is contained in:
olivierkeke 2021-12-12 22:58:36 +01:00 committed by GitHub
parent f8a6522100
commit 5d52435dea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 1765 additions and 90 deletions

108
bundles/org.openhab.binding.teleinfo/README.md Normal file → Executable file
View File

@ -12,6 +12,10 @@ These values can be used to
## Supported Things
### Historical TIC mode
Historical TIC mode is the only mode of all telemeters before Linky models and the default mode for Linky telemeters.
The Teleinfo binding provides support for both single-phase and three-phase connection, ICC evolution and the following pricing modes:
- HCHP mode
@ -34,6 +38,19 @@ The Teleinfo binding provides support for both single-phase and three-phase conn
| cbetm_hc_electricitymeter | three-phase | HCHP | |
| cbetm_tempo_electricitymeter | three-phase | Tempo | |
### Standard TIC mode
Linky telemeters add a new `Standard` mode with more detailed information but still provide information on the legacy format under the `Historical` denomination.
Standard mode doesn't depend on the pricing options, but it adds some useful information for electricity producers.
| Thing type | Connection | Producer mode |
|--------------------------------------------|--------------|--------------|
| lsmm_electricitymeter | single-phase | |
| lsmm_prod_electricitymeter | single-phase | [x] |
| lstm_electricitymeter | three-phase | |
| lstm_prod_electricitymeter | three-phase | [x] |
## Discovery
Before the binding can be used, a serial controller must be added. This needs to be done manually. Select __Teleinfo Serial Controller__ and enter the serial port.
@ -49,30 +66,33 @@ Once the serial controller added, electricity meters will automatically appear a
|----------------------|--------------|---------------------------------------|---------------------------------|
| `serialcontroller` | `serialport` | Path to the serial controller | /dev/ttyXXXX, rfc2217://ip:port |
| `*_electricitymeter` | `adco` | Electricity meter identifier | 12 digits number |
| | `ticMode` | TIC mode | `STANDARD`, `HISTORICAL` (default) |
## Channels
### Historical TIC mode
Channel availability depends on the electricity connection (single or three-phase) and on the pricing mode (Base, HCHP, EJP or Tempo).
| Channel | Type | Description | Phase | Mode |
| Channel | Type | Description | Connection | Mode |
|----------|---------------------------|----------------------------------------------------------|--------|-------|
| isousc | `Number:ElectricCurrent` | Subscribed electric current | All | All |
| ptec | `String` | Current pricing period | All | All |
| imax | `Number:ElectricCurrent` | Maximum consumed electric current | Single | All |
| imax1 | `Number:ElectricCurrent` | Maximum consumed electric current on phase 1 | Three | All |
| imax2 | `Number:ElectricCurrent` | Maximum consumed electric current on phase 2 | Three | All |
| imax3 | `Number:ElectricCurrent` | Maximum consumed electric current on phase 3 | Three | All |
| adps | `Number:ElectricCurrent` | Excess electric current warning | Single | All |
| adir1 | `Number:ElectricCurrent` | Excess electric current on phase 1 warning | Three | All |
| adir2 | `Number:ElectricCurrent` | Excess electric current on phase 2 warning | Three | All |
| adir3 | `Number:ElectricCurrent` | Excess electric current on phase 3 warning | Three | All |
| iinst | `Number:ElectricCurrent` | Instantaneous electric current | Single | All |
| iinst1 | `Number:ElectricCurrent` | Instantaneous electric current on phase 1 | Three | All |
| iinst2 | `Number:ElectricCurrent` | Instantaneous electric current on phase 2 | Three | All |
| iinst3 | `Number:ElectricCurrent` | Instantaneous electric current on phase 3 | Three | All |
| ppot | `String` | Electrical potential presence | Three | All |
| pmax | `Number:Energy` | Maximum consumed electric power on all phases | Three | All |
| papp | `Number:Power` | Instantaneous apparent power | Three, single (ICC evolution only) | All |
| imax | `Number:ElectricCurrent` | Maximum consumed electric current | Single-phase | All |
| imax1 | `Number:ElectricCurrent` | Maximum consumed electric current on phase 1 | Three-phase | All |
| imax2 | `Number:ElectricCurrent` | Maximum consumed electric current on phase 2 | Three-phase | All |
| imax3 | `Number:ElectricCurrent` | Maximum consumed electric current on phase 3 | Three-phase | All |
| adps | `Number:ElectricCurrent` | Excess electric current warning | Single-phase | All |
| adir1 | `Number:ElectricCurrent` | Excess electric current on phase 1 warning | Three-phase | All |
| adir2 | `Number:ElectricCurrent` | Excess electric current on phase 2 warning | Three-phase | All |
| adir3 | `Number:ElectricCurrent` | Excess electric current on phase 3 warning | Three-phase | All |
| iinst | `Number:ElectricCurrent` | Instantaneous electric current | Single-phase | All |
| iinst1 | `Number:ElectricCurrent` | Instantaneous electric current on phase 1 | Three-phase | All |
| iinst2 | `Number:ElectricCurrent` | Instantaneous electric current on phase 2 | Three-phase | All |
| iinst3 | `Number:ElectricCurrent` | Instantaneous electric current on phase 3 | Three-phase | All |
| ppot | `String` | Electrical potential presence | Three-phase | All |
| pmax | `Number:Energy` | Maximum consumed electric power on all phases | Three-phase | All |
| papp | `Number:Power` | Instantaneous apparent power | Three-phase, single-phase (ICC evolution only) | All |
| hhphc | `String` | Pricing schedule group | All | HCHP |
| hchc | `Number:Energy` | Total consumed energy at low rate pricing | All | HCHP |
| hchp | `Number:Energy` | Total consumed energy at high rate pricing | All | HCHP |
@ -88,8 +108,64 @@ Channel availability depends on the electricity connection (single or three-phas
| pejp | `Number:Duration` | Prior notice to EJP start | All | EJP |
| demain | `String` | Following day color | All | Tempo |
### Standard TIC mode
| Channel | Type | Description | Connection | Mode |
|----------|---------------------------|----------------------------------------------------------|--------|-------|
| ngtf | `String` | Provider schedule name | All | All |
| ltarf | `String` | Current pricing label | All | All |
| east | `Number:Energy` | Total active energy withdrawn | All | All |
| easf*XX* | `Number:Energy` | Active energy withdrawn from provider on index <img src="https://render.githubusercontent.com/render/math?math=XX \in \{01,\dots,10\}"/> | All | All |
| easd*XX* | `Number:Energy` | Active energy withdrawn from distributor on index <img src="https://render.githubusercontent.com/render/math?math=XX \in \{01,\dots,04\}"/> | All | All |
| irms*X* | `Number:ElectricCurrent` | RMS Current on phase *X* | All for <img src="https://render.githubusercontent.com/render/math?math=X=1"/>, Three-phase for <img src="https://render.githubusercontent.com/render/math?math=X\in \{2,3\}"/> | All |
| urms*X* | `Number:Potential` | RMS Voltage on phase *X* | All for <img src="https://render.githubusercontent.com/render/math?math=X=1"/>, Three-phase for <img src="https://render.githubusercontent.com/render/math?math=X\in \{2,3\}"/> | All |
| pref | `Number:Power` | Reference apparent power | All | All |
| pcoup | `Number:Power` | Apparent power rupture capacity | All | All |
| sinsts | `Number:Power` | Instantaneous withdrawn apparent power | Single-phase | All |
| smaxsn | `Number:Power` | Maximum withdrawn apparent power of the day | Single-phase | All |
| smaxsnMinus1 | `Number:Power` | Maximum withdrawn apparent power of the previous day | Single-phase | All |
| ccasn | `Number:Power` | Active charge point N | All | All |
| ccasnMinus1 | `Number:Power` | Active charge point N-1 | All | All |
| umoy*X* | `Number:Potential` | Mean Voltage on phase *X* | All for <img src="https://render.githubusercontent.com/render/math?math=X=1"/>, Three-phase for <img src="https://render.githubusercontent.com/render/math?math=X\in \{2,3\}"/> | All |
| dpm*X* | `String` | Start of mobile peak period <img src="https://render.githubusercontent.com/render/math?math=X\in \{1,\dots,3\}"/> | All | All |
| fpm*X* | `String` | End of mobile peak period <img src="https://render.githubusercontent.com/render/math?math=X\in \{1,\dots,3\}"/> | All | All |
| msg1 | `String` | Short message | All | All |
| msg2 | `String` | Very short message | All | All |
| ntarf | `String` | Index of current pricing | All | All |
| njourf | `String` | Number of current provider schedule | All | All |
| njourfPlus1 | `String` | Number of next day provider schedule | All | All |
| pjourfPlus1 | `String` | Profile of next day provider schedule | All | All |
| ppointe | `String` | Profile of next rush day | All | All |
| date | `DateTime` | Date and Time | All | All |
| smaxsnDate | `DateTime` | Timestamp of SMAXSN value | All | All |
| smaxsnMinus1Date | `DateTime` | Timestamp of SMAXSN-1 value | All | All |
| ccasnDate | `DateTime` | Timestamp of CCASN value | All | All |
| ccasnMinus1Date | `DateTime` | Timestamp of CCASN-1 value | All | All |
| umoy*X*Date | `DateTime` | Timestamp of UMOY*X* value | All for <img src="https://render.githubusercontent.com/render/math?math=X=1"/>, Three-phase for <img src="https://render.githubusercontent.com/render/math?math=X\in \{2,3\}"/> | All |
| dpm*X*Date | `DateTime` | Date of DPM*X* | All | All |
| fpm*X*Date | `DateTime` | Date of FPM*X* | All | All |
| relais*X* | `Switch` | relais status (<img src="https://render.githubusercontent.com/render/math?math=X\in {1,\dots,8}"/> ) | All | All |
| sinsts*X* | `Number:Power` | Instantaneous withdrawn apparent power on phase *X* | Three-phase | All |
| smaxsn*X* | `Number:Power` | Maximum withdrawn apparent power of the day on phase *X* | Three-phase | All |
| smaxsn*X*Minus1 | `Number:Power` | Maximum withdrawn apparent power on the previous day on phase *X* | Three-phase | All |
| smaxs*X*nDate | `DateTime` | Timestamp of SMAXSN*X* value | Three-phase | All |
| smaxsn*X*Minus1Date | `DateTime` | Timestamp of SMAXSN*X*-1 value | Three-phase | All |
| eait | `Number:Energy` | Total active energy withdrawn | All | All |
| erq*X* | `Number:Energy` | Active energy withdrawn from provider on index <img src="https://render.githubusercontent.com/render/math?math=XX \in \{01,\dots,10\}"/> | All | All |
| sinsti | `Number:Energy` | Active energy withdrawn from distributor on index <img src="https://render.githubusercontent.com/render/math?math=XX \in \{01,\dots,04\}"/> | All | All |
| smaxin | `Number:Power` | Maximum injected apparent power of the day | All for <img src="https://render.githubusercontent.com/render/math?math=X=1"/>, Three-phase for <img src="https://render.githubusercontent.com/render/math?math=X\in \{2,3\}"/> | All |
| smaxinMinus1 | `Number:Power` | Maximum injected apparent power of the previous day | All for <img src="https://render.githubusercontent.com/render/math?math=X=1"/>, Three-phase for <img src="https://render.githubusercontent.com/render/math?math=X\in \{2,3\}"/> | All |
| ccain | `Number:Power` | Injected active charge point N | All | Producer |
| ccainMinus1 | `Number:Power` | Injected active charge point N-1 | All | Producer |
| smaxinDate | `DateTime` | Timestamp of SMAXIN value | All | Producer |
| smaxinMinus1Date | `DateTime` | Timestamp of SMAXIN-1 value | All | Producer |
| ccainDate | `DateTime` | Timestamp of CCAIN value | All | Producer |
| ccainMinus1Date | `DateTime` | Timestamp of CCAIN-1 value | All | Producer |
## Full Example
### Historical TIC mode
The following `things` file declare a serial USB controller on `/dev/ttyUSB0` for a Single-phase Electricity meter with HC/HP option - CBEMM Evolution ICC and adco `031528042289` :
```

View File

@ -12,6 +12,8 @@
*/
package org.openhab.binding.teleinfo.internal;
import java.util.stream.IntStream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ThingTypeUID;
@ -68,7 +70,6 @@ public class TeleinfoBindingConstants {
public static final String CHANNEL_CBETM_IINST1 = "iinst1";
public static final String CHANNEL_CBETM_IINST2 = "iinst2";
public static final String CHANNEL_CBETM_IINST3 = "iinst3";
public static final String CHANNEL_CBETM_FRAME_TYPE = "frameType";
public static final String CHANNEL_CBETM_LONG_IMAX1 = "imax1";
public static final String CHANNEL_CBETM_LONG_IMAX2 = "imax2";
public static final String CHANNEL_CBETM_LONG_IMAX3 = "imax3";
@ -77,6 +78,105 @@ public class TeleinfoBindingConstants {
public static final String CHANNEL_CBETM_SHORT_ADIR1 = "adir1";
public static final String CHANNEL_CBETM_SHORT_ADIR2 = "adir2";
public static final String CHANNEL_CBETM_SHORT_ADIR3 = "adir3";
// List of Linky standard mode channel ids
public static final String CHANNEL_LSM_NGTF = "commonLSMGroup#ngtf";
public static final String CHANNEL_LSM_LTARF = "commonLSMGroup#ltarf";
public static final String CHANNEL_LSM_EAST = "commonLSMGroup#east";
public static final String CHANNEL_LSM_EASF01 = "commonLSMGroup#easf01";
public static final String CHANNEL_LSM_EASF02 = "commonLSMGroup#easf02";
public static final String CHANNEL_LSM_EASF03 = "commonLSMGroup#easf03";
public static final String CHANNEL_LSM_EASF04 = "commonLSMGroup#easf04";
public static final String CHANNEL_LSM_EASF05 = "commonLSMGroup#easf05";
public static final String CHANNEL_LSM_EASF06 = "commonLSMGroup#easf06";
public static final String CHANNEL_LSM_EASF07 = "commonLSMGroup#easf07";
public static final String CHANNEL_LSM_EASF08 = "commonLSMGroup#easf08";
public static final String CHANNEL_LSM_EASF09 = "commonLSMGroup#easf09";
public static final String CHANNEL_LSM_EASF10 = "commonLSMGroup#easf10";
public static final String CHANNEL_LSM_EASD01 = "commonLSMGroup#easd01";
public static final String CHANNEL_LSM_EASD02 = "commonLSMGroup#easd02";
public static final String CHANNEL_LSM_EASD03 = "commonLSMGroup#easd03";
public static final String CHANNEL_LSM_EASD04 = "commonLSMGroup#easd04";
public static final String CHANNEL_LSM_IRMS1 = "commonLSMGroup#irms1";
public static final String CHANNEL_LSM_URMS1 = "commonLSMGroup#urms1";
public static final String CHANNEL_LSM_PREF = "commonLSMGroup#pref";
public static final String CHANNEL_LSM_PCOUP = "commonLSMGroup#pcoup";
public static final String CHANNEL_LSM_SINSTS = "commonLSMGroup#sinsts";
public static final String CHANNEL_LSM_SMAXSN = "commonLSMGroup#smaxsn";
public static final String CHANNEL_LSM_SMAXSN_MINUS_1 = "commonLSMGroup#smaxsnMinus1";
public static final String CHANNEL_LSM_CCASN = "commonLSMGroup#ccasn";
public static final String CHANNEL_LSM_CCASN_MINUS_1 = "commonLSMGroup#ccasnMinus1";
public static final String CHANNEL_LSM_UMOY1 = "commonLSMGroup#umoy1";
public static final String CHANNEL_LSM_STGE = "commonLSMGroup#stge";
public static final String CHANNEL_LSM_DPM1 = "commonLSMGroup#dpm1";
public static final String CHANNEL_LSM_FPM1 = "commonLSMGroup#fpm1";
public static final String CHANNEL_LSM_DPM2 = "commonLSMGroup#dpm2";
public static final String CHANNEL_LSM_FPM2 = "commonLSMGroup#fpm2";
public static final String CHANNEL_LSM_DPM3 = "commonLSMGroup#dpm3";
public static final String CHANNEL_LSM_FPM3 = "commonLSMGroup#fpm3";
public static final String CHANNEL_LSM_MSG1 = "commonLSMGroup#msg1";
public static final String CHANNEL_LSM_MSG2 = "commonLSMGroup#msg2";
public static final String CHANNEL_LSM_PRM = "commonLSMGroup#prm";
public static final String[] CHANNELS_LSM_RELAIS = IntStream.range(1, 9).mapToObj(i -> "commonLSMGroup#relais" + i)
.toArray(String[]::new);
public static final String CHANNEL_LSM_NTARF = "commonLSMGroup#ntarf";
public static final String CHANNEL_LSM_NJOURF = "commonLSMGroup#njourf";
public static final String CHANNEL_LSM_NJOURF_PLUS_1 = "commonLSMGroup#njourfPlus1";
public static final String CHANNEL_LSM_PJOURF_PLUS_1 = "commonLSMGroup#pjourfPlus1";
public static final String CHANNEL_LSM_PPOINTE = "commonLSMGroup#ppointe";
public static final String CHANNEL_LSM_IRMS2 = "threePhasedLSMGroup#irms2";
public static final String CHANNEL_LSM_IRMS3 = "threePhasedLSMGroup#irms3";
public static final String CHANNEL_LSM_URMS2 = "threePhasedLSMGroup#urms2";
public static final String CHANNEL_LSM_URMS3 = "threePhasedLSMGroup#urms3";
public static final String CHANNEL_LSM_SINSTS1 = "threePhasedLSMGroup#sinsts1";
public static final String CHANNEL_LSM_SINSTS2 = "threePhasedLSMGroup#sinsts2";
public static final String CHANNEL_LSM_SINSTS3 = "threePhasedLSMGroup#sinsts3";
public static final String CHANNEL_LSM_SMAXSN1 = "threePhasedLSMGroup#smaxsn1";
public static final String CHANNEL_LSM_SMAXSN2 = "threePhasedLSMGroup#smaxsn2";
public static final String CHANNEL_LSM_SMAXSN3 = "threePhasedLSMGroup#smaxsn3";
public static final String CHANNEL_LSM_SMAXSN1_MINUS_1 = "threePhasedLSMGroup#smaxsn1Minus1";
public static final String CHANNEL_LSM_SMAXSN2_MINUS_1 = "threePhasedLSMGroup#smaxsn2Minus1";
public static final String CHANNEL_LSM_SMAXSN3_MINUS_1 = "threePhasedLSMGroup#smaxsn3Minus1";
public static final String CHANNEL_LSM_UMOY2 = "threePhasedLSMGroup#umoy2";
public static final String CHANNEL_LSM_UMOY3 = "threePhasedLSMGroup#umoy3";
public static final String CHANNEL_LSM_EAIT = "producerLSMGroup#eait";
public static final String CHANNEL_LSM_ERQ1 = "producerLSMGroup#erq1";
public static final String CHANNEL_LSM_ERQ2 = "producerLSMGroup#erq2";
public static final String CHANNEL_LSM_ERQ3 = "producerLSMGroup#erq3";
public static final String CHANNEL_LSM_ERQ4 = "producerLSMGroup#erq4";
public static final String CHANNEL_LSM_SINSTI = "producerLSMGroup#sinsti";
public static final String CHANNEL_LSM_SMAXIN = "producerLSMGroup#smaxin";
public static final String CHANNEL_LSM_SMAXIN_MINUS_1 = "producerLSMGroup#smaxinMinus1";
public static final String CHANNEL_LSM_CCAIN = "producerLSMGroup#ccain";
public static final String CHANNEL_LSM_CCAIN_MINUS_1 = "producerLSMGroup#ccainMinus1";
public static final String CHANNEL_LSM_DATE = "commonLSMGroup#date";
public static final String CHANNEL_LSM_SMAXSN_DATE = "commonLSMGroup#smaxsnDate";
public static final String CHANNEL_LSM_SMAXSN_MINUS_1_DATE = "commonLSMGroup#smaxsnMinus1Date";
public static final String CHANNEL_LSM_CCASN_DATE = "commonLSMGroup#ccasnDate";
public static final String CHANNEL_LSM_CCASN_MINUS_1_DATE = "commonLSMGroup#ccasnMinus1Date";
public static final String CHANNEL_LSM_UMOY1_DATE = "commonLSMGroup#umoy1Date";
public static final String CHANNEL_LSM_DPM1_DATE = "commonLSMGroup#dpm1Date";
public static final String CHANNEL_LSM_FPM1_DATE = "commonLSMGroup#fpm1Date";
public static final String CHANNEL_LSM_DPM2_DATE = "commonLSMGroup#dpm2Date";
public static final String CHANNEL_LSM_FPM2_DATE = "commonLSMGroup#fpm2Date";
public static final String CHANNEL_LSM_DPM3_DATE = "commonLSMGroup#dpm3Date";
public static final String CHANNEL_LSM_FPM3_DATE = "commonLSMGroup#fpm3Date";
public static final String CHANNEL_LSM_SMAXIN_DATE = "producerLSMGroup#smaxinDate";
public static final String CHANNEL_LSM_SMAXIN_MINUS_1_DATE = "producerLSMGroup#smaxinMinus1Date";
public static final String CHANNEL_LSM_CCAIN_DATE = "producerLSMGroup#ccainDate";
public static final String CHANNEL_LSM_CCAIN_MINUS_1_DATE = "producerLSMGroup#ccainMinus1Date";
public static final String CHANNEL_LSM_SMAXSN1_DATE = "threePhasedLSMGroup#smaxsn1Date";
public static final String CHANNEL_LSM_SMAXSN2_DATE = "threePhasedLSMGroup#smaxsn2Date";
public static final String CHANNEL_LSM_SMAXSN3_DATE = "threePhasedLSMGroup#smaxsn3Date";
public static final String CHANNEL_LSM_SMAXSN1_MINUS_1_DATE = "threePhasedLSMGroup#smaxsn1Minus1Date";
public static final String CHANNEL_LSM_SMAXSN2_MINUS_1_DATE = "threePhasedLSMGroup#smaxsn2Minus1Date";
public static final String CHANNEL_LSM_SMAXSN3_MINUS_1_DATE = "threePhasedLSMGroup#smaxsn3Minus1Date";
public static final String CHANNEL_LSM_UMOY2_DATE = "threePhasedLSMGroup#umoy2Date";
public static final String CHANNEL_LSM_UMOY3_DATE = "threePhasedLSMGroup#umoy3Date";
public static final String NOT_A_CHANNEL = "";
@ -118,6 +218,18 @@ public class TeleinfoBindingConstants {
public static final ThingTypeUID THING_TEMPO_CBETM_ELECTRICITY_METER_TYPE_UID = new ThingTypeUID(BINDING_ID,
"cbetm_tempo_electricitymeter");
public static final ThingTypeUID THING_LSMT_PROD_ELECTRICITY_METER_TYPE_UID = new ThingTypeUID(BINDING_ID,
"lsmt_prod_electricitymeter");
public static final ThingTypeUID THING_LSMM_PROD_ELECTRICITY_METER_TYPE_UID = new ThingTypeUID(BINDING_ID,
"lsmm_prod_electricitymeter");
public static final ThingTypeUID THING_LSMT_ELECTRICITY_METER_TYPE_UID = new ThingTypeUID(BINDING_ID,
"lsmt_electricitymeter");
public static final ThingTypeUID THING_LSMM_ELECTRICITY_METER_TYPE_UID = new ThingTypeUID(BINDING_ID,
"lsmm_electricitymeter");
public static final String ERROR_OFFLINE_SERIAL_NOT_FOUND = "@text/teleinfo.thingstate.serial_notfound";
public static final String ERROR_OFFLINE_SERIAL_INUSE = "@text/teleinfo.thingstate.serial_inuse";
public static final String ERROR_OFFLINE_SERIAL_UNSUPPORTED = "@text/teleinfo.thingstate.serial_unsupported";

View File

@ -17,8 +17,6 @@ import static org.openhab.binding.teleinfo.internal.TeleinfoBindingConstants.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
@ -47,13 +45,15 @@ import org.slf4j.LoggerFactory;
public class TeleinfoDiscoveryService extends AbstractDiscoveryService
implements TeleinfoControllerHandlerListener, ThingHandlerService, DiscoveryService {
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Stream.of(THING_HC_CBEMM_ELECTRICITY_METER_TYPE_UID,
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Set.of(THING_HC_CBEMM_ELECTRICITY_METER_TYPE_UID,
THING_BASE_CBEMM_ELECTRICITY_METER_TYPE_UID, THING_TEMPO_CBEMM_ELECTRICITY_METER_TYPE_UID,
THING_EJP_CBEMM_ELECTRICITY_METER_TYPE_UID, THING_HC_CBEMM_EVO_ICC_ELECTRICITY_METER_TYPE_UID,
THING_BASE_CBEMM_EVO_ICC_ELECTRICITY_METER_TYPE_UID, THING_TEMPO_CBEMM_EVO_ICC_ELECTRICITY_METER_TYPE_UID,
THING_EJP_CBEMM_EVO_ICC_ELECTRICITY_METER_TYPE_UID, THING_HC_CBETM_ELECTRICITY_METER_TYPE_UID,
THING_BASE_CBETM_ELECTRICITY_METER_TYPE_UID, THING_TEMPO_CBETM_ELECTRICITY_METER_TYPE_UID,
THING_EJP_CBETM_ELECTRICITY_METER_TYPE_UID).collect(Collectors.toSet());
THING_EJP_CBETM_ELECTRICITY_METER_TYPE_UID, THING_LSMT_PROD_ELECTRICITY_METER_TYPE_UID,
THING_LSMT_ELECTRICITY_METER_TYPE_UID, THING_LSMM_PROD_ELECTRICITY_METER_TYPE_UID,
THING_LSMM_ELECTRICITY_METER_TYPE_UID);
private static final int SCAN_DURATION_IN_S = 60;
@ -140,11 +140,12 @@ public class TeleinfoDiscoveryService extends AbstractDiscoveryService
TeleinfoAbstractControllerHandler controllerHandlerRef = controllerHandler;
if (controllerHandlerRef != null) {
logger.debug("New eletricity meter detection from frame {}", frameSample);
if (frameSample.get(Label.ADCO) == null) {
throw new IllegalStateException("Missing ADCO key");
if (frameSample.get(Label.ADCO) == null && frameSample.get(Label.ADSC) == null) {
throw new IllegalStateException("Missing ADCO or ADSC key");
}
String adco = frameSample.get(Label.ADCO);
String adco = frameSample.get(Label.ADCO) != null ? frameSample.get(Label.ADCO)
: frameSample.get(Label.ADSC);
if (adco != null) {
ThingUID thingUID = new ThingUID(getThingTypeUID(frameSample), adco,
controllerHandlerRef.getThing().getUID().getId());
@ -152,7 +153,7 @@ public class TeleinfoDiscoveryService extends AbstractDiscoveryService
final Map<String, Object> properties = getThingProperties(adco);
final String representationProperty = THING_ELECTRICITY_METER_PROPERTY_ADCO;
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withProperties(properties)
.withLabel("Teleinfo ADCO " + adco).withThingType(getThingTypeUID(frameSample))
.withLabel("Teleinfo ADCO/ADSC " + adco).withThingType(getThingTypeUID(frameSample))
.withBridge(controllerHandlerRef.getThing().getUID())
.withRepresentationProperty(representationProperty).build();

View File

@ -12,12 +12,15 @@
*/
package org.openhab.binding.teleinfo.internal.data;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* Define the evolution option values
*
* @author Olivier MARCEAU - Initial contribution
*
*/
@NonNullByDefault
public enum Evolution {
ICC,
NONE

View File

@ -20,6 +20,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.teleinfo.internal.reader.io.serialport.InvalidFrameException;
import org.openhab.binding.teleinfo.internal.reader.io.serialport.Label;
import org.openhab.binding.teleinfo.internal.serial.TeleinfoTicMode;
/**
* The {@link Frame} class defines common attributes for any Teleinfo frames.
@ -32,11 +33,16 @@ public class Frame implements Serializable {
private static final long serialVersionUID = -1934715078822532494L;
private Map<Label, String> labelToValues = new EnumMap<>(Label.class);
private Map<Label, String> labelToTimestamp = new EnumMap<>(Label.class);
public void put(Label label, String value) {
labelToValues.put(label, value);
}
public void putTimestamp(Label label, String timestamp) {
labelToTimestamp.put(label, timestamp);
}
public @Nullable String get(Label label) {
return labelToValues.get(label);
}
@ -49,11 +55,33 @@ public class Frame implements Serializable {
return null;
}
public String getAsDateTime(Label label) {
String timestamp = labelToTimestamp.get(label);
if (timestamp == null) {
return "";
}
return "20" + timestamp.substring(1, 3) + "-" + timestamp.substring(3, 5) + "-" + timestamp.substring(5, 7)
+ "T" + timestamp.substring(7, 9) + ":" + timestamp.substring(9, 11) + ":"
+ timestamp.substring(11, 13);
}
public Frame() {
// default constructor
}
public FrameType getType() throws InvalidFrameException {
TeleinfoTicMode ticMode = getTicMode();
switch (ticMode) {
case HISTORICAL:
return getHistoricalType();
case STANDARD:
return getStandardType();
default:
throw new InvalidFrameException();
}
}
public FrameType getHistoricalType() throws InvalidFrameException {
Phase phase = getPhase();
Pricing pricing = getPricing();
Evolution evolution = getEvolution();
@ -152,14 +180,43 @@ public class Frame implements Serializable {
}
}
public TeleinfoTicMode getTicMode() throws InvalidFrameException {
if (labelToValues.containsKey(Label.ADCO)) {
return TeleinfoTicMode.HISTORICAL;
} else if (labelToValues.containsKey(Label.ADSC)) {
return TeleinfoTicMode.STANDARD;
}
throw new InvalidFrameException();
}
public FrameType getStandardType() throws InvalidFrameException {
boolean isProd = labelToValues.containsKey(Label.EAIT);
boolean isThreePhase = labelToValues.containsKey(Label.IRMS2);
if (isProd && isThreePhase) {
return FrameType.LSMT_PROD;
}
if (isProd) {
return FrameType.LSMM_PROD;
}
if (isThreePhase) {
return FrameType.LSMT;
}
return FrameType.LSMM;
}
public void clear() {
labelToValues.clear();
labelToTimestamp.clear();
}
public Map<Label, String> getLabelToValues() {
return labelToValues;
}
public Map<Label, String> getLabelToTimestamp() {
return labelToTimestamp;
}
private char getProgrammeChar() {
String optarif = labelToValues.get(Label.OPTARIF);
if (optarif == null) {

View File

@ -14,6 +14,8 @@ package org.openhab.binding.teleinfo.internal.data;
import static org.openhab.binding.teleinfo.internal.TeleinfoBindingConstants.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.thing.ThingTypeUID;
/**
@ -22,6 +24,7 @@ import org.openhab.core.thing.ThingTypeUID;
* @author Olivier MARCEAU - Initial contribution
*
*/
@NonNullByDefault
public enum FrameType {
CBETM_SHORT(null),
CBETM_LONG_BASE(THING_BASE_CBETM_ELECTRICITY_METER_TYPE_UID),
@ -36,15 +39,19 @@ public enum FrameType {
CBEMM_ICC_EJP(THING_EJP_CBEMM_EVO_ICC_ELECTRICITY_METER_TYPE_UID),
CBEMM_ICC_TEMPO(THING_TEMPO_CBEMM_EVO_ICC_ELECTRICITY_METER_TYPE_UID),
CBEMM_ICC_HC(THING_HC_CBEMM_EVO_ICC_ELECTRICITY_METER_TYPE_UID),
LSMT_PROD(THING_LSMT_PROD_ELECTRICITY_METER_TYPE_UID),
LSMM_PROD(THING_LSMM_PROD_ELECTRICITY_METER_TYPE_UID),
LSMM(THING_LSMM_ELECTRICITY_METER_TYPE_UID),
LSMT(THING_LSMT_ELECTRICITY_METER_TYPE_UID),
UNKNOWN(null);
private ThingTypeUID thingTypeUid;
private @Nullable ThingTypeUID thingTypeUid;
FrameType(ThingTypeUID thingTypeUid) {
FrameType(@Nullable ThingTypeUID thingTypeUid) {
this.thingTypeUid = thingTypeUid;
}
public ThingTypeUID getThingTypeUid() {
public @Nullable ThingTypeUID getThingTypeUid() {
return thingTypeUid;
}
}

View File

@ -12,12 +12,15 @@
*/
package org.openhab.binding.teleinfo.internal.data;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* Define all the phase values
*
* @author Olivier MARCEAU - Initial contribution
*
*/
@NonNullByDefault
public enum Phase {
ONE_PHASED,
THREE_PHASED

View File

@ -12,12 +12,15 @@
*/
package org.openhab.binding.teleinfo.internal.data;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* Define all the pricing option values
*
* @author Olivier MARCEAU - Initial contribution
*
*/
@NonNullByDefault
public enum Pricing {
BASE,
TEMPO,

View File

@ -21,10 +21,13 @@ import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.teleinfo.internal.data.Frame;
import org.openhab.binding.teleinfo.internal.data.Phase;
import org.openhab.binding.teleinfo.internal.data.Pricing;
import org.openhab.binding.teleinfo.internal.reader.io.serialport.FrameUtil;
import org.openhab.binding.teleinfo.internal.reader.io.serialport.InvalidFrameException;
import org.openhab.binding.teleinfo.internal.reader.io.serialport.Label;
import org.openhab.binding.teleinfo.internal.reader.io.serialport.ValueType;
import org.openhab.binding.teleinfo.internal.serial.TeleinfoTicMode;
import org.openhab.core.library.types.DateTimeType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.thing.Bridge;
@ -130,7 +133,7 @@ public class TeleinfoElectricityMeterHandler extends BaseThingHandler implements
@Override
public void onFrameReceived(Frame frame) {
String adco = configuration.getAdco();
if (adco.equalsIgnoreCase(frame.get(Label.ADCO))) {
if (adco.equalsIgnoreCase(frame.get(Label.ADCO)) || adco.equalsIgnoreCase(frame.get(Label.ADSC))) {
updateStatesForChannels(frame);
}
}
@ -139,39 +142,65 @@ public class TeleinfoElectricityMeterHandler extends BaseThingHandler implements
for (Entry<Label, String> entry : frame.getLabelToValues().entrySet()) {
Label label = entry.getKey();
if (!label.getChannelName().equals(NOT_A_CHANNEL)) {
logger.trace("Update channel {} to value {}", label.getChannelName(), entry.getValue());
if (label == Label.PTEC) {
updateState(label.getChannelName(), StringType.valueOf(entry.getValue().replace(".", "")));
} else if (label.getType() == ValueType.STRING) {
updateState(label.getChannelName(), StringType.valueOf(entry.getValue()));
} else if (label.getType() == ValueType.INTEGER) {
updateState(label.getChannelName(),
QuantityType.valueOf(Integer.parseInt(entry.getValue()), label.getUnit()));
updateState(label.getChannelName(), QuantityType
.valueOf(label.getFactor() * Integer.parseInt(entry.getValue()), label.getUnit()));
}
}
if (!label.getTimestampChannelName().equals(NOT_A_CHANNEL)) {
String timestamp = frame.getAsDateTime(label);
if (!timestamp.isEmpty()) {
logger.trace("Update channel {} to value {}", label.getTimestampChannelName(), timestamp);
updateState(label.getTimestampChannelName(), DateTimeType.valueOf(timestamp));
}
}
}
try {
if (frame.getPricing() == Pricing.TEMPO) {
updateState(CHANNEL_TEMPO_FRAME_PROGRAMME_CIRCUIT_1, StringType.valueOf(frame.getProgrammeCircuit1()));
updateState(CHANNEL_TEMPO_FRAME_PROGRAMME_CIRCUIT_2, StringType.valueOf(frame.getProgrammeCircuit2()));
}
} catch (InvalidFrameException e) {
logger.warn("Can not find pricing option.");
}
if (frame.getTicMode() == TeleinfoTicMode.HISTORICAL) {
try {
if (frame.getPricing() == Pricing.TEMPO) {
updateState(CHANNEL_TEMPO_FRAME_PROGRAMME_CIRCUIT_1,
StringType.valueOf(frame.getProgrammeCircuit1()));
updateState(CHANNEL_TEMPO_FRAME_PROGRAMME_CIRCUIT_2,
StringType.valueOf(frame.getProgrammeCircuit2()));
}
} catch (InvalidFrameException e) {
logger.warn("Can not find pricing option.");
}
try {
Phase phase = frame.getPhase();
if (phase == Phase.ONE_PHASED) {
updateStateForMissingAlert(frame, Label.ADPS);
} else if (phase == Phase.THREE_PHASED) {
if (!wasLastFrameShort) {
updateStateForMissingAlert(frame, Label.ADIR1);
updateStateForMissingAlert(frame, Label.ADIR2);
updateStateForMissingAlert(frame, Label.ADIR3);
try {
Phase phase = frame.getPhase();
if (phase == Phase.ONE_PHASED) {
updateStateForMissingAlert(frame, Label.ADPS);
} else if (phase == Phase.THREE_PHASED) {
if (!wasLastFrameShort) {
updateStateForMissingAlert(frame, Label.ADIR1);
updateStateForMissingAlert(frame, Label.ADIR2);
updateStateForMissingAlert(frame, Label.ADIR3);
}
wasLastFrameShort = frame.isShortFrame();
}
} catch (InvalidFrameException e) {
logger.warn("Can not find phase.");
}
} else {
if (frame.getLabelToValues().containsKey(Label.RELAIS)) {
String relaisString = frame.get(Label.RELAIS);
if (relaisString != null) {
boolean[] relaisStates = FrameUtil.parseRelaisStates(relaisString);
for (int i = 0; i <= 7; i++) {
updateState(CHANNELS_LSM_RELAIS[i], OnOffType.from(relaisStates[i]));
}
}
}
wasLastFrameShort = frame.isShortFrame();
}
} catch (InvalidFrameException e) {
logger.warn("Can not find phase.");
logger.warn("Can not find TIC mode.");
}
updateState(CHANNEL_LAST_UPDATE, new DateTimeType());

View File

@ -48,7 +48,9 @@ public class TeleinfoThingHandlerFactory extends BaseThingHandlerFactory {
THING_HC_CBEMM_EVO_ICC_ELECTRICITY_METER_TYPE_UID, THING_BASE_CBEMM_EVO_ICC_ELECTRICITY_METER_TYPE_UID,
THING_TEMPO_CBEMM_EVO_ICC_ELECTRICITY_METER_TYPE_UID, THING_EJP_CBEMM_EVO_ICC_ELECTRICITY_METER_TYPE_UID,
THING_HC_CBETM_ELECTRICITY_METER_TYPE_UID, THING_BASE_CBETM_ELECTRICITY_METER_TYPE_UID,
THING_TEMPO_CBETM_ELECTRICITY_METER_TYPE_UID, THING_EJP_CBETM_ELECTRICITY_METER_TYPE_UID)
THING_TEMPO_CBETM_ELECTRICITY_METER_TYPE_UID, THING_EJP_CBETM_ELECTRICITY_METER_TYPE_UID,
THING_LSMM_ELECTRICITY_METER_TYPE_UID, THING_LSMM_PROD_ELECTRICITY_METER_TYPE_UID,
THING_LSMT_ELECTRICITY_METER_TYPE_UID, THING_LSMT_PROD_ELECTRICITY_METER_TYPE_UID)
.collect(Collectors.toSet());
private final SerialPortManager serialPortManager;

View File

@ -24,6 +24,7 @@ import org.openhab.binding.teleinfo.internal.data.Frame;
import org.openhab.binding.teleinfo.internal.reader.io.serialport.FrameUtil;
import org.openhab.binding.teleinfo.internal.reader.io.serialport.InvalidFrameException;
import org.openhab.binding.teleinfo.internal.reader.io.serialport.Label;
import org.openhab.binding.teleinfo.internal.serial.TeleinfoTicMode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -43,19 +44,32 @@ public class TeleinfoInputStream extends InputStream {
private BufferedReader bufferedReader;
private @Nullable String groupLine;
private boolean autoRepairInvalidADPSgroupLine;
private final TeleinfoTicMode ticMode;
private final boolean verifyChecksum;
private final Frame frame = new Frame();
public TeleinfoInputStream(final InputStream teleinfoInputStream) {
this(teleinfoInputStream, false);
public TeleinfoInputStream(final InputStream teleinfoInputStream, TeleinfoTicMode ticMode) {
this(teleinfoInputStream, false, ticMode, true);
}
public TeleinfoInputStream(final @Nullable InputStream teleinfoInputStream,
boolean autoRepairInvalidADPSgroupLine) {
public TeleinfoInputStream(final InputStream teleinfoInputStream, boolean autoRepairInvalidADPSgroupLine,
TeleinfoTicMode ticMode) {
this(teleinfoInputStream, autoRepairInvalidADPSgroupLine, ticMode, true);
}
public TeleinfoInputStream(final InputStream teleinfoInputStream, TeleinfoTicMode ticMode, boolean verifyChecksum) {
this(teleinfoInputStream, false, ticMode, verifyChecksum);
}
public TeleinfoInputStream(final @Nullable InputStream teleinfoInputStream, boolean autoRepairInvalidADPSgroupLine,
TeleinfoTicMode ticMode, boolean verifyChecksum) {
if (teleinfoInputStream == null) {
throw new IllegalArgumentException("Teleinfo inputStream is null");
}
this.autoRepairInvalidADPSgroupLine = autoRepairInvalidADPSgroupLine;
this.ticMode = ticMode;
this.verifyChecksum = verifyChecksum;
this.bufferedReader = new BufferedReader(new InputStreamReader(teleinfoInputStream, StandardCharsets.US_ASCII));
groupLine = null;
@ -96,29 +110,48 @@ public class TeleinfoInputStream extends InputStream {
logger.trace("groupLine = {}", groupLine);
String groupLineRef = groupLine;
if (groupLineRef != null) {
String[] groupLineTokens = groupLineRef.split("\\s");
if (groupLineTokens.length != 2 && groupLineTokens.length != 3) {
String[] groupLineTokens = groupLineRef.split(ticMode.getSeparator());
if (ticMode == TeleinfoTicMode.HISTORICAL && groupLineTokens.length != 2 && groupLineTokens.length != 3
|| ticMode == TeleinfoTicMode.STANDARD && groupLineTokens.length != 3
&& groupLineTokens.length != 4) {
final String error = String.format("The groupLine '%1$s' is incomplete", groupLineRef);
throw new InvalidFrameException(error);
}
String labelStr = groupLineTokens[0];
String valueString = groupLineTokens[1];
String valueString;
String timestampString = null;
switch (ticMode) {
default:
valueString = groupLineTokens[1];
break;
case STANDARD:
if (groupLineTokens.length == 3) {
valueString = groupLineTokens[1];
} else {
timestampString = groupLineTokens[1];
valueString = groupLineTokens[2];
}
break;
}
// verify integrity (through checksum)
char checksum = (groupLineTokens.length == 3 ? groupLineTokens[2].charAt(0) : ' ');
char computedChecksum = FrameUtil.computeGroupLineChecksum(labelStr, valueString);
if (computedChecksum != checksum) {
logger.trace("computedChecksum = {}", computedChecksum);
logger.trace("checksum = {}", checksum);
final String error = String.format(
"The groupLine '%s' is corrupted (integrity not checked). Actual checksum: '%s' / Expected checksum: '%s'",
groupLineRef, checksum, computedChecksum);
throw new InvalidFrameException(error);
if (verifyChecksum) {
char checksum = groupLineRef.charAt(groupLineRef.length() - 1);
char computedChecksum = FrameUtil
.computeGroupLineChecksum(groupLineRef.substring(0, groupLineRef.length() - 2), ticMode);
if (computedChecksum != checksum) {
logger.trace("computedChecksum = {}", computedChecksum);
logger.trace("checksum = {}", checksum);
final String error = String.format(
"The groupLine '%s' is corrupted (integrity not checked). Actual checksum: '%s' / Expected checksum: '%s'",
groupLineRef, checksum, computedChecksum);
throw new InvalidFrameException(error);
}
}
Label label;
try {
label = Label.valueOf(labelStr);
label = Label.getEnum(labelStr);
} catch (IllegalArgumentException e) {
if (autoRepairInvalidADPSgroupLine && labelStr.startsWith(Label.ADPS.name())) {
// in this hardware issue, label variable is composed by label name and value. E.g:
@ -133,6 +166,9 @@ public class TeleinfoInputStream extends InputStream {
}
frame.put(label, valueString);
if (timestampString != null) {
frame.putTimestamp(label, timestampString);
}
}
}
@ -152,7 +188,7 @@ public class TeleinfoInputStream extends InputStream {
throw new UnsupportedOperationException("The 'read()' is not supported");
}
private boolean isHeaderFrame(final @Nullable String line) {
public static boolean isHeaderFrame(final @Nullable String line) {
// A new teleinfo trame begin with '3' and '2' bytes (END OF TEXT et START OF TEXT)
return (line != null && line.length() > 1 && line.codePointAt(0) == 3 && line.codePointAt(1) == 2);
}

View File

@ -13,6 +13,7 @@
package org.openhab.binding.teleinfo.internal.reader.io.serialport;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.teleinfo.internal.serial.TeleinfoTicMode;
/**
* The {@link FrameUtil} class defines a utility class for {@link FrameCbetmLong}.
@ -33,14 +34,31 @@ public class FrameUtil {
* must not include in checksum computation.
* @return the checksum of the given group line.
*/
public static char computeGroupLineChecksum(final String label, final String value) {
final String groupLine = label + " " + value;
public static char computeGroupLineChecksum(final String groupLine, TeleinfoTicMode ticMode) {
int sum = 0;
for (int i = 0; i < groupLine.length(); i++) {
sum = sum + groupLine.codePointAt(i);
sum += groupLine.codePointAt(i);
}
if (ticMode == TeleinfoTicMode.STANDARD) {
sum += 0x09;
}
sum = (sum & 0x3F) + 0x20;
return (char) sum;
}
/**
* Parse relais states.
*
* @param relais integer string
* @return State of each relais
*/
public static boolean[] parseRelaisStates(String relais) {
boolean[] relaisState = new boolean[8];
int value = Integer.parseInt(relais);
for (int i = 0; i <= 7; i++) {
relaisState[i] = (value & 1) == 1;
value >>= 1;
}
return relaisState;
}
}

View File

@ -27,13 +27,14 @@ import org.openhab.core.library.unit.Units;
@NonNullByDefault
public enum Label {
// Historical labels
ADCO(ValueType.STRING, NOT_A_CHANNEL, Units.ONE),
OPTARIF(ValueType.STRING, NOT_A_CHANNEL, Units.ONE),
BASE(ValueType.INTEGER, CHANNEL_BASE_FRAME_BASE, Units.WATT_HOUR),
HCHC(ValueType.INTEGER, CHANNEL_HC_FRAME_HCHC, Units.WATT_HOUR),
HCHP(ValueType.INTEGER, CHANNEL_HC_FRAME_HCHP, Units.WATT_HOUR),
EJPHN(ValueType.INTEGER, CHANNEL_EJP_FRAME_EJPHN, Units.WATT_HOUR),
EJPHPM(ValueType.INTEGER, CHANNEL_EJP_FRAME_EJPHN, Units.WATT_HOUR),
EJPHPM(ValueType.INTEGER, CHANNEL_EJP_FRAME_EJPHPM, Units.WATT_HOUR),
PTEC(ValueType.STRING, CHANNEL_PTEC, Units.ONE),
MOTDETAT(ValueType.STRING, CHANNEL_MOTDETAT, Units.AMPERE),
ISOUSC(ValueType.INTEGER, CHANNEL_ISOUSC, Units.AMPERE),
@ -60,16 +61,108 @@ public enum Label {
BBRHCJR(ValueType.INTEGER, CHANNEL_TEMPO_FRAME_BBRHCJR, Units.WATT_HOUR),
BBRHPJR(ValueType.INTEGER, CHANNEL_TEMPO_FRAME_BBRHPJR, Units.WATT_HOUR),
PEJP(ValueType.INTEGER, CHANNEL_EJP_FRAME_PEJP, Units.MINUTE),
DEMAIN(ValueType.STRING, CHANNEL_TEMPO_FRAME_DEMAIN, Units.ONE);
DEMAIN(ValueType.STRING, CHANNEL_TEMPO_FRAME_DEMAIN, Units.ONE),
private ValueType type;
private String channelName;
private Unit<?> unit;
// Standard TIC mode labels
ADSC(ValueType.STRING, NOT_A_CHANNEL, Units.ONE),
VTIC(ValueType.INTEGER, NOT_A_CHANNEL, Units.ONE),
DATE(ValueType.STRING, NOT_A_CHANNEL, CHANNEL_LSM_DATE, Units.ONE),
NGTF(ValueType.STRING, CHANNEL_LSM_NGTF, Units.ONE),
LTARF(ValueType.STRING, CHANNEL_LSM_LTARF, Units.ONE),
EAST(ValueType.INTEGER, CHANNEL_LSM_EAST, Units.WATT_HOUR),
EASF01(ValueType.INTEGER, CHANNEL_LSM_EASF01, Units.WATT_HOUR),
EASF02(ValueType.INTEGER, CHANNEL_LSM_EASF02, Units.WATT_HOUR),
EASF03(ValueType.INTEGER, CHANNEL_LSM_EASF03, Units.WATT_HOUR),
EASF04(ValueType.INTEGER, CHANNEL_LSM_EASF04, Units.WATT_HOUR),
EASF05(ValueType.INTEGER, CHANNEL_LSM_EASF05, Units.WATT_HOUR),
EASF06(ValueType.INTEGER, CHANNEL_LSM_EASF06, Units.WATT_HOUR),
EASF07(ValueType.INTEGER, CHANNEL_LSM_EASF07, Units.WATT_HOUR),
EASF08(ValueType.INTEGER, CHANNEL_LSM_EASF08, Units.WATT_HOUR),
EASF09(ValueType.INTEGER, CHANNEL_LSM_EASF09, Units.WATT_HOUR),
EASF10(ValueType.INTEGER, CHANNEL_LSM_EASF10, Units.WATT_HOUR),
EASD01(ValueType.INTEGER, CHANNEL_LSM_EASD01, Units.WATT_HOUR),
EASD02(ValueType.INTEGER, CHANNEL_LSM_EASD02, Units.WATT_HOUR),
EASD03(ValueType.INTEGER, CHANNEL_LSM_EASD03, Units.WATT_HOUR),
EASD04(ValueType.INTEGER, CHANNEL_LSM_EASD04, Units.WATT_HOUR),
EAIT(ValueType.INTEGER, CHANNEL_LSM_EAIT, Units.WATT_HOUR),
ERQ1(ValueType.INTEGER, CHANNEL_LSM_ERQ1, Units.VOLT_AMPERE_HOUR),
ERQ2(ValueType.INTEGER, CHANNEL_LSM_ERQ2, Units.VOLT_AMPERE_HOUR),
ERQ3(ValueType.INTEGER, CHANNEL_LSM_ERQ3, Units.VOLT_AMPERE_HOUR),
ERQ4(ValueType.INTEGER, CHANNEL_LSM_ERQ4, Units.VOLT_AMPERE_HOUR),
IRMS1(ValueType.INTEGER, CHANNEL_LSM_IRMS1, Units.AMPERE),
IRMS2(ValueType.INTEGER, CHANNEL_LSM_IRMS2, Units.AMPERE),
IRMS3(ValueType.INTEGER, CHANNEL_LSM_IRMS3, Units.AMPERE),
URMS1(ValueType.INTEGER, CHANNEL_LSM_URMS1, Units.VOLT),
URMS2(ValueType.INTEGER, CHANNEL_LSM_URMS2, Units.VOLT),
URMS3(ValueType.INTEGER, CHANNEL_LSM_URMS3, Units.VOLT),
PREF(ValueType.INTEGER, CHANNEL_LSM_PREF, Units.VOLT_AMPERE, 1000),
PCOUP(ValueType.INTEGER, CHANNEL_LSM_PCOUP, Units.VOLT_AMPERE, 1000),
SINSTS(ValueType.INTEGER, CHANNEL_LSM_SINSTS, Units.VOLT_AMPERE),
SINSTS1(ValueType.INTEGER, CHANNEL_LSM_SINSTS1, Units.VOLT_AMPERE),
SINSTS2(ValueType.INTEGER, CHANNEL_LSM_SINSTS2, Units.VOLT_AMPERE),
SINSTS3(ValueType.INTEGER, CHANNEL_LSM_SINSTS3, Units.VOLT_AMPERE),
SMAXSN(ValueType.INTEGER, CHANNEL_LSM_SMAXSN, CHANNEL_LSM_SMAXSN_DATE, Units.VOLT_AMPERE),
SMAXSN1(ValueType.INTEGER, CHANNEL_LSM_SMAXSN1, CHANNEL_LSM_SMAXSN1_DATE, Units.VOLT_AMPERE),
SMAXSN2(ValueType.INTEGER, CHANNEL_LSM_SMAXSN2, CHANNEL_LSM_SMAXSN2_DATE, Units.VOLT_AMPERE),
SMAXSN3(ValueType.INTEGER, CHANNEL_LSM_SMAXSN3, CHANNEL_LSM_SMAXSN3_DATE, Units.VOLT_AMPERE),
SMAXSN_MINUS_1(ValueType.INTEGER, CHANNEL_LSM_SMAXSN_MINUS_1, CHANNEL_LSM_SMAXSN_MINUS_1_DATE, Units.VOLT_AMPERE),
SMAXSN1_MINUS_1(ValueType.INTEGER, CHANNEL_LSM_SMAXSN1_MINUS_1, CHANNEL_LSM_SMAXSN1_MINUS_1_DATE,
Units.VOLT_AMPERE),
SMAXSN2_MINUS_1(ValueType.INTEGER, CHANNEL_LSM_SMAXSN2_MINUS_1, CHANNEL_LSM_SMAXSN2_MINUS_1_DATE,
Units.VOLT_AMPERE),
SMAXSN3_MINUS_1(ValueType.INTEGER, CHANNEL_LSM_SMAXSN3_MINUS_1, CHANNEL_LSM_SMAXSN3_MINUS_1_DATE,
Units.VOLT_AMPERE),
SINSTI(ValueType.INTEGER, CHANNEL_LSM_SINSTI, Units.VOLT_AMPERE),
SMAXIN(ValueType.INTEGER, CHANNEL_LSM_SMAXIN, CHANNEL_LSM_SMAXIN_DATE, Units.VOLT_AMPERE),
SMAXIN_MINUS_1(ValueType.INTEGER, CHANNEL_LSM_SMAXIN_MINUS_1, CHANNEL_LSM_SMAXIN_MINUS_1_DATE, Units.VOLT_AMPERE),
CCASN(ValueType.INTEGER, CHANNEL_LSM_CCASN, CHANNEL_LSM_CCASN_DATE, Units.WATT),
CCASN_MINUS_1(ValueType.INTEGER, CHANNEL_LSM_CCASN_MINUS_1, CHANNEL_LSM_CCASN_MINUS_1_DATE, Units.WATT),
CCAIN(ValueType.INTEGER, CHANNEL_LSM_CCAIN, CHANNEL_LSM_CCAIN_DATE, Units.WATT),
CCAIN_MINUS_1(ValueType.INTEGER, CHANNEL_LSM_CCAIN_MINUS_1, CHANNEL_LSM_CCAIN_MINUS_1_DATE, Units.WATT),
UMOY1(ValueType.INTEGER, CHANNEL_LSM_UMOY1, CHANNEL_LSM_UMOY1_DATE, Units.VOLT),
UMOY2(ValueType.INTEGER, CHANNEL_LSM_UMOY2, CHANNEL_LSM_UMOY2_DATE, Units.VOLT),
UMOY3(ValueType.INTEGER, CHANNEL_LSM_UMOY3, CHANNEL_LSM_UMOY3_DATE, Units.VOLT),
STGE(ValueType.STRING, CHANNEL_LSM_STGE, Units.ONE),
DPM1(ValueType.STRING, CHANNEL_LSM_DPM1, CHANNEL_LSM_DPM1_DATE, Units.ONE),
FPM1(ValueType.STRING, CHANNEL_LSM_FPM1, CHANNEL_LSM_FPM1_DATE, Units.ONE),
DPM2(ValueType.STRING, CHANNEL_LSM_DPM2, CHANNEL_LSM_DPM2_DATE, Units.ONE),
FPM2(ValueType.STRING, CHANNEL_LSM_FPM2, CHANNEL_LSM_FPM2_DATE, Units.ONE),
DPM3(ValueType.STRING, CHANNEL_LSM_DPM3, CHANNEL_LSM_DPM3_DATE, Units.ONE),
FPM3(ValueType.STRING, CHANNEL_LSM_FPM3, CHANNEL_LSM_FPM3_DATE, Units.ONE),
MSG1(ValueType.STRING, CHANNEL_LSM_MSG1, Units.ONE),
MSG2(ValueType.STRING, CHANNEL_LSM_MSG2, Units.ONE),
PRM(ValueType.STRING, CHANNEL_LSM_PRM, Units.ONE),
RELAIS(ValueType.STRING, NOT_A_CHANNEL, Units.ONE),
NTARF(ValueType.STRING, CHANNEL_LSM_NTARF, Units.ONE),
NJOURF(ValueType.STRING, CHANNEL_LSM_NJOURF, Units.ONE),
NJOURF_PLUS_1(ValueType.STRING, CHANNEL_LSM_NJOURF_PLUS_1, Units.ONE),
PJOURF_PLUS_1(ValueType.STRING, CHANNEL_LSM_PJOURF_PLUS_1, Units.ONE),
PPOINTE(ValueType.STRING, CHANNEL_LSM_PPOINTE, Units.ONE);
private final ValueType type;
private final String channelName;
private final String timestampChannelName;
private final Unit<?> unit;
private final int factor;
Label(ValueType type, String channelName, Unit<?> unit) {
this(type, channelName, NOT_A_CHANNEL, unit, 1);
}
Label(ValueType type, String channelName, String timestampChannelName, Unit<?> unit) {
this(type, channelName, timestampChannelName, unit, 1);
}
Label(ValueType type, String channelName, Unit<?> unit, int factor) {
this(type, channelName, NOT_A_CHANNEL, unit, factor);
}
Label(ValueType type, String channelName, String timestampChannelName, Unit<?> unit, int factor) {
this.type = type;
this.channelName = channelName;
this.timestampChannelName = timestampChannelName;
this.unit = unit;
this.factor = factor;
}
public ValueType getType() {
@ -80,7 +173,21 @@ public enum Label {
return channelName;
}
public String getTimestampChannelName() {
return timestampChannelName;
}
public Unit<?> getUnit() {
return unit;
}
public int getFactor() {
return factor;
}
public static Label getEnum(String label) {
String modifiedLabel = label.replace("-", "_MINUS_");
modifiedLabel = modifiedLabel.replace("+", "_PLUS_");
return valueOf(modifiedLabel);
}
}

View File

@ -12,12 +12,15 @@
*/
package org.openhab.binding.teleinfo.internal.reader.io.serialport;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* Defines all the type of values
*
* @author Olivier MARCEAU - Initial contribution
*
*/
@NonNullByDefault
public enum ValueType {
INTEGER,
STRING

View File

@ -36,20 +36,24 @@ public class TeleinfoReceiveThread extends Thread {
private SerialPort serialPort;
private @Nullable TeleinfoReceiveThreadListener listener;
private boolean autoRepairInvalidADPSgroupLine;
private final TeleinfoTicMode ticMode;
private final boolean verifyChecksum;
public TeleinfoReceiveThread(SerialPort serialPort, final TeleinfoSerialControllerHandler listener,
boolean autoRepairInvalidADPSgroupLine) {
boolean autoRepairInvalidADPSgroupLine, TeleinfoTicMode ticMode, boolean verifyChecksum) {
super("OH-binding-TeleinfoReceiveThread-" + listener.getThing().getUID().getId());
setDaemon(true);
this.serialPort = serialPort;
this.listener = listener;
this.autoRepairInvalidADPSgroupLine = autoRepairInvalidADPSgroupLine;
this.ticMode = ticMode;
this.verifyChecksum = verifyChecksum;
}
@Override
public void run() {
try (TeleinfoInputStream teleinfoStream = new TeleinfoInputStream(serialPort.getInputStream(),
autoRepairInvalidADPSgroupLine)) {
autoRepairInvalidADPSgroupLine, ticMode, verifyChecksum)) {
while (!interrupted()) {
TeleinfoReceiveThreadListener listener = this.listener;
if (listener != null) {

View File

@ -23,5 +23,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
public class TeleinfoSerialControllerConfiguration {
public String serialport = "";
public String ticMode = "";
public boolean verifyChecksum = true;
public boolean autoRepairInvalidADPSgroupLine = true;
}

View File

@ -148,7 +148,9 @@ public class TeleinfoSerialControllerHandler extends TeleinfoAbstractControllerH
SerialPort commPort = portIdentifier.open("org.openhab.binding.teleinfo", 5000);
serialPort = commPort;
commPort.setSerialPortParams(1200, SerialPort.DATABITS_7, SerialPort.STOPBITS_1, SerialPort.PARITY_EVEN);
TeleinfoTicMode ticMode = TeleinfoTicMode.valueOf(config.ticMode);
commPort.setSerialPortParams(ticMode.getBitrate(), SerialPort.DATABITS_7, SerialPort.STOPBITS_1,
SerialPort.PARITY_EVEN);
try {
commPort.enableReceiveThreshold(1);
} catch (UnsupportedCommOperationException e) {
@ -161,7 +163,7 @@ public class TeleinfoSerialControllerHandler extends TeleinfoAbstractControllerH
}
logger.debug("Starting receive thread");
TeleinfoReceiveThread receiveThread = new TeleinfoReceiveThread(commPort, this,
config.autoRepairInvalidADPSgroupLine);
config.autoRepairInvalidADPSgroupLine, ticMode, config.verifyChecksum);
this.receiveThread = receiveThread;
receiveThread.start();

View File

@ -0,0 +1,42 @@
/**
* Copyright (c) 2010-2021 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.teleinfo.internal.serial;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* Define an enum for TIC mode of Linky telemeters
*
* @author Olivier MARCEAU - Initial contribution
*/
@NonNullByDefault
public enum TeleinfoTicMode {
HISTORICAL(1200, "\\s"),
STANDARD(9600, "\\t");
private final int bitrate;
private final String separator;
TeleinfoTicMode(int bitrate, String separator) {
this.bitrate = bitrate;
this.separator = separator;
}
public int getBitrate() {
return bitrate;
}
public String getSeparator() {
return separator;
}
}

View File

@ -7,7 +7,7 @@
<config-description uri="thing-type:teleinfo:adco">
<parameter name="adco" type="text" required="true" pattern="^\w{12}$">
<label>ADCO</label>
<label>ADCO/ADSC</label>
<description>Electricity meter identifier (format: 12 characters / e.g: '031528042289')</description>
<limitToOptions>false</limitToOptions>
</parameter>

View File

@ -0,0 +1,362 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="teleinfo"
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">
<channel-group-type id="commonLSMGroupType">
<label>Common</label>
<description>Common channels for Linky telemeter in standard teleinformation mode</description>
<category>Energy</category>
<channels>
<channel id="ngtf" typeId="stringType">
<label>NGTF</label>
<description>Provider schedule name</description>
</channel>
<channel id="ltarf" typeId="stringType">
<label>LTARF</label>
<description>Current pricing label</description>
</channel>
<channel id="east" typeId="energyType">
<label>EAST</label>
<description>Total active energy withdrawn</description>
</channel>
<channel id="easf01" typeId="energyType">
<label>EASF01</label>
<description>Active energy withdrawn from provider on index 01</description>
</channel>
<channel id="easf02" typeId="energyType">
<label>EASF02</label>
<description>Active energy withdrawn from provider on index 02</description>
</channel>
<channel id="easf03" typeId="energyType">
<label>EASF03</label>
<description>Active energy withdrawn from provider on index 03</description>
</channel>
<channel id="easf04" typeId="energyType">
<label>EASF04</label>
<description>Active energy withdrawn from provider on index 04</description>
</channel>
<channel id="easf05" typeId="energyType">
<label>EASF05</label>
<description>Active energy withdrawn from provider on index 05</description>
</channel>
<channel id="easf06" typeId="energyType">
<label>EASF06</label>
<description>Active energy withdrawn from provider on index 06</description>
</channel>
<channel id="easf07" typeId="energyType">
<label>EASF07</label>
<description>Active energy withdrawn from provider on index 07</description>
</channel>
<channel id="easf08" typeId="energyType">
<label>EASF08</label>
<description>Active energy withdrawn from provider on index 08</description>
</channel>
<channel id="easf09" typeId="energyType">
<label>EASF09</label>
<description>Active energy withdrawn from provider on index 09</description>
</channel>
<channel id="easf10" typeId="energyType">
<label>EASF10</label>
<description>Active energy withdrawn from provider on index 10</description>
</channel>
<channel id="easd01" typeId="energyType">
<label>EASD01</label>
<description>Active energy withdrawn from distributor on index 01</description>
</channel>
<channel id="easd02" typeId="energyType">
<label>EASD02</label>
<description>Active energy withdrawn from distributor on index 02</description>
</channel>
<channel id="easd03" typeId="energyType">
<label>EASD03</label>
<description>Active energy withdrawn from distributor on index 03</description>
</channel>
<channel id="easd04" typeId="energyType">
<label>EASD04</label>
<description>Active energy withdrawn from distributor on index 04</description>
</channel>
<channel id="irms1" typeId="currentType">
<label>IRMS1</label>
<description>RMS Current on phase 1</description>
</channel>
<channel id="urms1" typeId="potentialType">
<label>URMS1</label>
<description>RMS Voltage on phase 1</description>
</channel>
<channel id="pref" typeId="powerType">
<label>PREF</label>
<description>Reference apparent power</description>
</channel>
<channel id="pcoup" typeId="powerType">
<label>PCOUP</label>
<description>Apparent power rupture capacity</description>
</channel>
<channel id="sinsts" typeId="powerType">
<label>SINSTS</label>
<description>Instantaneous withdrawn apparent power</description>
</channel>
<channel id="smaxsn" typeId="powerType">
<label>SMAXSN</label>
<description>Maximum withdrawn apparent power of the day</description>
</channel>
<channel id="smaxsnMinus1" typeId="powerType">
<label>SMAXSN-1</label>
<description>Maximum withdrawn apparent power of the previous day</description>
</channel>
<channel id="ccasn" typeId="powerType">
<label>CCASN</label>
<description>Active charge point N</description>
</channel>
<channel id="ccasnMinus1" typeId="powerType">
<label>CCASN-1</label>
<description>Active charge point N-1</description>
</channel>
<channel id="umoy1" typeId="potentialType">
<label>UMOY1</label>
<description>Mean Voltage on phase 1</description>
</channel>
<channel id="stge" typeId="stringType">
<label>STGE</label>
<description>Status registry</description>
</channel>
<channel id="dpm1" typeId="stringType">
<label>DPM1</label>
<description>Start of mobile peak period 1</description>
</channel>
<channel id="fpm1" typeId="stringType">
<label>FPM1</label>
<description>End of mobile peak period 1</description>
</channel>
<channel id="dpm2" typeId="stringType">
<label>DPM2</label>
<description>Start of mobile peak period 2</description>
</channel>
<channel id="fpm2" typeId="stringType">
<label>FPM2</label>
<description>End of mobile peak period 2</description>
</channel>
<channel id="dpm3" typeId="stringType">
<label>DPM3</label>
<description>Start of mobile peak period 3</description>
</channel>
<channel id="fpm3" typeId="stringType">
<label>FPM3</label>
<description>End of mobile peak period 3</description>
</channel>
<channel id="msg1" typeId="stringType">
<label>MSG1</label>
<description>Short message</description>
</channel>
<channel id="msg2" typeId="stringType">
<label>MSG2</label>
<description>Very short message</description>
</channel>
<channel id="prm" typeId="stringType">
<label>PRM</label>
<description>PRM</description>
</channel>
<channel id="ntarf" typeId="stringType">
<label>NTARF</label>
<description>Index of current pricing</description>
</channel>
<channel id="njourf" typeId="stringType">
<label>NJOURF</label>
<description>Number of current provider schedule</description>
</channel>
<channel id="njourfPlus1" typeId="stringType">
<label>NJOURF+1</label>
<description>Number of next day provider schedule</description>
</channel>
<channel id="pjourfPlus1" typeId="stringType">
<label>PJOURF+1</label>
<description>Profile of next day provider schedule</description>
</channel>
<channel id="ppointe" typeId="stringType">
<label>PPOINTE</label>
<description>Profile of next rush day</description>
</channel>
<channel id="date" typeId="dateTimeType">
<label>DATE</label>
<description>Date and Time</description>
</channel>
<channel id="smaxsnDate" typeId="dateTimeType">
<label>SMAXSN TIMESTAMP</label>
<description>Timestamp of SMAXSN value</description>
</channel>
<channel id="smaxsnMinus1Date" typeId="dateTimeType">
<label>SMAXSN-1 TIMESTAMP</label>
<description>Timestamp of SMAXSN-1 value</description>
</channel>
<channel id="ccasnDate" typeId="dateTimeType">
<label>CCASN TIMESTAMP</label>
<description>Timestamp of CCASN value</description>
</channel>
<channel id="ccasnMinus1Date" typeId="dateTimeType">
<label>CCASN-1 TIMESTAMP</label>
<description>Timestamp of CCASN-1 value</description>
</channel>
<channel id="umoy1Date" typeId="dateTimeType">
<label>UMOY1 TIMESTAMP</label>
<description>Timestamp of UMOY1 value</description>
</channel>
<channel id="dpm1Date" typeId="dateTimeType">
<label>DPM1 TIMESTAMP</label>
<description>Date of DPM1</description>
</channel>
<channel id="fpm1Date" typeId="dateTimeType">
<label>FPM1 TIMESTAMP</label>
<description>Date of FPM1</description>
</channel>
<channel id="dpm2Date" typeId="dateTimeType">
<label>DPM2 TIMESTAMP</label>
<description>Date of DPM2</description>
</channel>
<channel id="fpm2Date" typeId="dateTimeType">
<label>FPM2 TIMESTAMP</label>
<description>Date of FPM2</description>
</channel>
<channel id="dpm3Date" typeId="dateTimeType">
<label>DPM3 TIMESTAMP</label>
<description>Date of DPM3</description>
</channel>
<channel id="fpm3Date" typeId="dateTimeType">
<label>FPM3 TIMESTAMP</label>
<description>Date of FPM3</description>
</channel>
<channel id="relais1" typeId="switchType">
<label>Relais 1</label>
</channel>
<channel id="relais2" typeId="switchType">
<label>Relais 2</label>
</channel>
<channel id="relais3" typeId="switchType">
<label>Relais 3</label>
</channel>
<channel id="relais4" typeId="switchType">
<label>Relais 4</label>
</channel>
<channel id="relais5" typeId="switchType">
<label>Relais 5</label>
</channel>
<channel id="relais6" typeId="switchType">
<label>Relais 6</label>
</channel>
<channel id="relais7" typeId="switchType">
<label>Relais 7</label>
</channel>
<channel id="relais8" typeId="switchType">
<label>Relais 8</label>
</channel>
</channels>
</channel-group-type>
<channel-type id="stringType">
<item-type>String</item-type>
<label>Teleinfo String Type</label>
<category>Energy</category>
<state pattern="%s" readOnly="true"/>
</channel-type>
<channel-type id="energyType">
<item-type>Number:Energy</item-type>
<label>Teleinfo Energy Type</label>
<category>Energy</category>
<state pattern="%d %unit%" readOnly="true"/>
</channel-type>
<channel-type id="currentType">
<item-type>Number:ElectricCurrent</item-type>
<label>Teleinfo Current Type</label>
<category>Energy</category>
<state pattern="%d %unit%" readOnly="true"/>
</channel-type>
<channel-type id="potentialType">
<item-type>Number:ElectricPotential</item-type>
<label>Teleinfo Potential Type</label>
<category>Energy</category>
<state pattern="%d %unit%" readOnly="true"/>
</channel-type>
<channel-type id="powerType">
<item-type>Number:Power</item-type>
<label>Teleinfo Power Type</label>
<category>Energy</category>
<state pattern="%d %unit%" readOnly="true"/>
</channel-type>
<channel-type id="switchType">
<item-type>Switch</item-type>
<label>Teleinfo Switch Type</label>
<category>Energy</category>
<state readOnly="true"/>
</channel-type>
<channel-type id="dateTimeType">
<item-type>DateTime</item-type>
<label>Teleinfo DateTime Type</label>
<category>Energy</category>
<state readOnly="true" pattern="%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS"/>
</channel-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,133 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="teleinfo"
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">
<channel-group-type id="producerLSMGroupType">
<label>Producer</label>
<description>Producer channels for Linky telemeter in standard teleinformation mode</description>
<category>Energy</category>
<channels>
<channel id="eait" typeId="energyType">
<label>EAIT</label>
<description>Total active energy injected</description>
</channel>
<channel id="erq1" typeId="energyType">
<label>ERQ1</label>
<description>Total reactive energy Q1</description>
</channel>
<channel id="erq2" typeId="energyType">
<label>ERQ2</label>
<description>Total reactive energy Q2</description>
</channel>
<channel id="erq3" typeId="energyType">
<label>ERQ3</label>
<description>Total reactive energy Q3</description>
</channel>
<channel id="erq4" typeId="energyType">
<label>ERQ4</label>
<description>Total reactive energy Q4</description>
</channel>
<channel id="sinsti" typeId="powerType">
<label>SINSTI</label>
<description>Instantaneous injected apparent power</description>
</channel>
<channel id="smaxin" typeId="powerType">
<label>SMAXIN</label>
<description>Maximum injected apparent power of the day</description>
</channel>
<channel id="smaxinMinus1" typeId="powerType">
<label>SMAXIN-1</label>
<description>Maximum injected apparent power of the previous day</description>
</channel>
<channel id="ccain" typeId="powerType">
<label>CCAIN</label>
<description>Injected active charge point N</description>
</channel>
<channel id="ccainMinus1" typeId="powerType">
<label>CCAIN-1</label>
<description>Injected active charge point N-1</description>
</channel>
<channel id="smaxinDate" typeId="dateTimeType">
<label>SMAXIN TIMESTAMP</label>
<description>Timestamp of SMAXIN value</description>
</channel>
<channel id="smaxinMinus1Date" typeId="dateTimeType">
<label>SMAXIN-1 TIMESTAMP</label>
<description>Timestamp of SMAXIN-1 value</description>
</channel>
<channel id="ccainDate" typeId="dateTimeType">
<label>CCAIN TIMESTAMP</label>
<description>Timestamp of CCAIN value</description>
</channel>
<channel id="ccainMinus1Date" typeId="dateTimeType">
<label>CCAIN-1 TIMESTAMP</label>
<description>Timestamp of CCAIN-1 value</description>
</channel>
</channels>
</channel-group-type>
<channel-type id="stringType">
<item-type>String</item-type>
<label>Teleinfo String Type</label>
<category>Energy</category>
<state pattern="%s" readOnly="true"/>
</channel-type>
<channel-type id="energyType">
<item-type>Number:Energy</item-type>
<label>Teleinfo Energy Type</label>
<category>Energy</category>
<state pattern="%d %unit%" readOnly="true"/>
</channel-type>
<channel-type id="currentType">
<item-type>Number:ElectricCurrent</item-type>
<label>Teleinfo Current Type</label>
<category>Energy</category>
<state pattern="%d %unit%" readOnly="true"/>
</channel-type>
<channel-type id="potentialType">
<item-type>Number:ElectricPotential</item-type>
<label>Teleinfo Potential Type</label>
<category>Energy</category>
<state pattern="%d %unit%" readOnly="true"/>
</channel-type>
<channel-type id="powerType">
<item-type>Number:Power</item-type>
<label>Teleinfo Power Type</label>
<category>Energy</category>
<state pattern="%d %unit%" readOnly="true"/>
</channel-type>
<channel-type id="switchType">
<item-type>Switch</item-type>
<label>Teleinfo Switch Type</label>
<category>Energy</category>
<state readOnly="true"/>
</channel-type>
<channel-type id="dateTimeType">
<item-type>DateTime</item-type>
<label>Teleinfo DateTime Type</label>
<category>Energy</category>
<state readOnly="true" pattern="%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS"/>
</channel-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,179 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="teleinfo"
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">
<channel-group-type id="threePhasedLSMGroupType">
<label>Three-phase</label>
<description>Three-phased channels for Linky telemeter in standard teleinformation mode</description>
<category>Energy</category>
<channels>
<channel id="irms2" typeId="currentType">
<label>IRMS2</label>
<description>RMS Current on phase 2</description>
</channel>
<channel id="irms3" typeId="currentType">
<label>IRMS3</label>
<description>RMS Current on phase 3</description>
</channel>
<channel id="urms2" typeId="potentialType">
<label>URMS2</label>
<description>RMS Voltage on phase 2</description>
</channel>
<channel id="urms3" typeId="potentialType">
<label>URMS3</label>
<description>RMS Voltage on phase 3</description>
</channel>
<channel id="sinsts1" typeId="powerType">
<label>SINSTS1</label>
<description>Instantaneous withdrawn apparent power on phase 1</description>
</channel>
<channel id="sinsts2" typeId="powerType">
<label>SINSTS2</label>
<description>Instantaneous withdrawn apparent power on phase 2</description>
</channel>
<channel id="sinsts3" typeId="powerType">
<label>SINSTS3</label>
<description>Instantaneous withdrawn apparent power on phase 3</description>
</channel>
<channel id="smaxsn1" typeId="powerType">
<label>SMAXSN1</label>
<description>Maximum withdrawn apparent power of the day on phase 1</description>
</channel>
<channel id="smaxsn2" typeId="powerType">
<label>SMAXSN2</label>
<description>Maximum withdrawn apparent power of the day on phase 2</description>
</channel>
<channel id="smaxsn3" typeId="powerType">
<label>SMAXSN3</label>
<description>Maximum withdrawn apparent power of the day on phase 3</description>
</channel>
<channel id="smaxsn1Minus1" typeId="powerType">
<label>SMAXSN1-1</label>
<description>Maximum withdrawn apparent power of the previous day on phase 1</description>
</channel>
<channel id="smaxsn2Minus1" typeId="powerType">
<label>SMAXSN2-1</label>
<description>Maximum withdrawn apparent power of the previous day on phase 2</description>
</channel>
<channel id="smaxsn3Minus1" typeId="powerType">
<label>SMAXSN3-1</label>
<description>Maximum withdrawn apparent power of the previous day on phase 3</description>
</channel>
<channel id="umoy2" typeId="potentialType">
<label>UMOY2</label>
<description>Mean Voltage on phase 2</description>
</channel>
<channel id="umoy3" typeId="potentialType">
<label>UMOY3</label>
<description>Mean Voltage on phase 3</description>
</channel>
<channel id="smaxsn1Date" typeId="dateTimeType">
<label>SMAXSN1 TIMESTAMP</label>
<description>Timestamp of SMAXSN1 value</description>
</channel>
<channel id="smaxsn2Date" typeId="dateTimeType">
<label>SMAXSN2 TIMESTAMP</label>
<description>Timestamp of SMAXSN2 value</description>
</channel>
<channel id="smaxsn3Date" typeId="dateTimeType">
<label>SMAXSN3 TIMESTAMP</label>
<description>Timestamp of SMAXSN3 value</description>
</channel>
<channel id="smaxsn1Minus1Date" typeId="dateTimeType">
<label>SMAXSN1-1 TIMESTAMP</label>
<description>Timestamp of SMAXSN1-1 value</description>
</channel>
<channel id="smaxsn2Minus1Date" typeId="dateTimeType">
<label>SMAXSN2-1 TIMESTAMP</label>
<description>Timestamp of SMAXSN2-1 value</description>
</channel>
<channel id="smaxsn3Minus1Date" typeId="dateTimeType">
<label>SMAXSN3-1 TIMESTAMP</label>
<description>Timestamp of SMAXSN3-1 value</description>
</channel>
<channel id="umoy2Date" typeId="dateTimeType">
<label>UMOY2 TIMESTAMP</label>
<description>Timestamp of UMOY2 value</description>
</channel>
<channel id="umoy3Date" typeId="dateTimeType">
<label>UMOY3 TIMESTAMP</label>
<description>Timestamp of UMOY3 value</description>
</channel>
</channels>
</channel-group-type>
<channel-type id="stringType">
<item-type>String</item-type>
<label>Teleinfo String Type</label>
<category>Energy</category>
<state pattern="%s" readOnly="true"/>
</channel-type>
<channel-type id="energyType">
<item-type>Number:Energy</item-type>
<label>Teleinfo Energy Type</label>
<category>Energy</category>
<state pattern="%d %unit%" readOnly="true"/>
</channel-type>
<channel-type id="currentType">
<item-type>Number:ElectricCurrent</item-type>
<label>Teleinfo Current Type</label>
<category>Energy</category>
<state pattern="%d %unit%" readOnly="true"/>
</channel-type>
<channel-type id="potentialType">
<item-type>Number:ElectricPotential</item-type>
<label>Teleinfo Potential Type</label>
<category>Energy</category>
<state pattern="%d %unit%" readOnly="true"/>
</channel-type>
<channel-type id="powerType">
<item-type>Number:Power</item-type>
<label>Teleinfo Power Type</label>
<category>Energy</category>
<state pattern="%d %unit%" readOnly="true"/>
</channel-type>
<channel-type id="switchType">
<item-type>Switch</item-type>
<label>Teleinfo Switch Type</label>
<category>Energy</category>
<state readOnly="true"/>
</channel-type>
<channel-type id="dateTimeType">
<item-type>DateTime</item-type>
<label>Teleinfo DateTime Type</label>
<category>Energy</category>
<state readOnly="true" pattern="%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS"/>
</channel-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="teleinfo"
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="lsmm_electricitymeter" listed="false">
<supported-bridge-type-refs>
<bridge-type-ref id="serialcontroller"/>
</supported-bridge-type-refs>
<label>Linky Single-phase</label>
<description>Single-phase Linky Electricity meter in standard mode</description>
<channel-groups>
<channel-group id="commonLSMGroup" typeId="commonLSMGroupType"/>
</channel-groups>
<config-description-ref uri="thing-type:teleinfo:adco"/>
</thing-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="teleinfo"
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="lsmm_prod_electricitymeter" listed="false">
<supported-bridge-type-refs>
<bridge-type-ref id="serialcontroller"/>
</supported-bridge-type-refs>
<label>Linky Single-phase Producer</label>
<description>Single-phase producer Linky Electricity meter in standard mode</description>
<channel-groups>
<channel-group id="commonLSMGroup" typeId="commonLSMGroupType"/>
<channel-group id="producerLSMGroup" typeId="producerLSMGroupType"/>
</channel-groups>
<config-description-ref uri="thing-type:teleinfo:adco"/>
</thing-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="teleinfo"
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="lsmt_electricitymeter" listed="false">
<supported-bridge-type-refs>
<bridge-type-ref id="serialcontroller"/>
</supported-bridge-type-refs>
<label>Linky Three-phase</label>
<description>Three-phase Linky Electricity meter in standard mode</description>
<channel-groups>
<channel-group id="commonLSMGroup" typeId="commonLSMGroupType"/>
<channel-group id="threePhasedLSMGroup" typeId="threePhasedLSMGroupType"/>
</channel-groups>
<config-description-ref uri="thing-type:teleinfo:adco"/>
</thing-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="teleinfo"
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="lsmt_prod_electricitymeter" listed="false">
<supported-bridge-type-refs>
<bridge-type-ref id="serialcontroller"/>
</supported-bridge-type-refs>
<label>Linky Three-phase Producer</label>
<description>Three-phase producer Linky Electricity meter in standard mode</description>
<channel-groups>
<channel-group id="commonLSMGroup" typeId="commonLSMGroupType"/>
<channel-group id="producerLSMGroup" typeId="producerLSMGroupType"/>
<channel-group id="threePhasedLSMGroup" typeId="threePhasedLSMGroupType"/>
</channel-groups>
<config-description-ref uri="thing-type:teleinfo:adco"/>
</thing-type>
</thing:thing-descriptions>

View File

@ -19,6 +19,22 @@
<description>Serial port of Teleinfo device (e.g.: /dev/ttyUSB0 on Linux, COM1 on Windows)</description>
<limitToOptions>false</limitToOptions>
</parameter>
<parameter name="ticMode" type="text" required="true">
<label>TIC mode</label>
<description>TIC Mode of the telemeter (Standard TIC mode is only available on Linky telemeters)</description>
<default>HISTORICAL</default>
<options>
<option value="HISTORICAL">Historical</option>
<option value="STANDARD">Standard</option>
</options>
<limitToOptions>true</limitToOptions>
</parameter>
<parameter name="verifyChecksum" type="boolean" required="true">
<label>Checksum Verification</label>
<description>Activate checksum verification</description>
<default>true</default>
<advanced>true</advanced>
</parameter>
<parameter name="autoRepairInvalidADPSgroupLine" type="boolean" required="false">
<label>Auto Repair Malformed ADPS Data</label>
<description>Try to auto repair malformed ADPS data from hardware issues (e.g: "ADPS032" instead of "ADPS 032"

View File

@ -15,13 +15,17 @@ package org.openhab.binding.teleinfo.internal.reader.io;
import static org.junit.jupiter.api.Assertions.*;
import java.io.FileInputStream;
import java.time.Month;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.Test;
import org.openhab.binding.teleinfo.internal.TeleinfoBindingConstants;
import org.openhab.binding.teleinfo.internal.data.Frame;
import org.openhab.binding.teleinfo.internal.data.FrameType;
import org.openhab.binding.teleinfo.internal.reader.io.serialport.Label;
import org.openhab.binding.teleinfo.internal.serial.TeleinfoTicMode;
import org.openhab.binding.teleinfo.util.TestUtils;
import org.openhab.core.library.types.DateTimeType;
/**
*
@ -33,7 +37,8 @@ public class TeleinfoInputStreamTest {
@Test
public void testReadNextFrameCbetmBase1() throws Exception {
try (TeleinfoInputStream in = new TeleinfoInputStream(
new FileInputStream(TestUtils.getTestFile("cbetm-base-option-1.raw")), false)) {
new FileInputStream(TestUtils.getTestFile("cbetm-base-option-1.raw")), false,
TeleinfoTicMode.HISTORICAL)) {
Frame frame = in.readNextFrame();
assertNotNull(frame);
@ -57,7 +62,8 @@ public class TeleinfoInputStreamTest {
@Test
public void testReadNextFrameCbemmEvoIccHc1() throws Exception {
try (TeleinfoInputStream in = new TeleinfoInputStream(
new FileInputStream(TestUtils.getTestFile("cbemm-evo-icc-hc-option-1.raw")), false)) {
new FileInputStream(TestUtils.getTestFile("cbemm-evo-icc-hc-option-1.raw")), false,
TeleinfoTicMode.HISTORICAL)) {
Frame frame = in.readNextFrame();
assertNotNull(frame);
@ -78,7 +84,8 @@ public class TeleinfoInputStreamTest {
@Test
public void testReadNextFrameCbetmEjp1() throws Exception {
try (TeleinfoInputStream in = new TeleinfoInputStream(
new FileInputStream(TestUtils.getTestFile("cbetm-ejp-option-1.raw")), false)) {
new FileInputStream(TestUtils.getTestFile("cbetm-ejp-option-1.raw")), false,
TeleinfoTicMode.HISTORICAL)) {
Frame frame = in.readNextFrame();
assertNotNull(frame);
@ -104,7 +111,8 @@ public class TeleinfoInputStreamTest {
@Test
public void testReadNextFrameCbemmEvoIccTempo1() throws Exception {
try (TeleinfoInputStream in = new TeleinfoInputStream(
new FileInputStream(TestUtils.getTestFile("cbemm-evo-icc-tempo-option-1.raw")), false)) {
new FileInputStream(TestUtils.getTestFile("cbemm-evo-icc-tempo-option-1.raw")), false,
TeleinfoTicMode.HISTORICAL)) {
Frame frame = in.readNextFrame();
assertNotNull(frame);
@ -133,7 +141,8 @@ public class TeleinfoInputStreamTest {
@Test
public void testReadNextFrameCbemmEvoIccBase1() throws Exception {
try (TeleinfoInputStream in = new TeleinfoInputStream(
new FileInputStream(TestUtils.getTestFile("cbemm-evo-icc-base-option-1.raw")), false)) {
new FileInputStream(TestUtils.getTestFile("cbemm-evo-icc-base-option-1.raw")), false,
TeleinfoTicMode.HISTORICAL)) {
Frame frame = in.readNextFrame();
assertNotNull(frame);
assertEquals(FrameType.CBEMM_ICC_BASE, frame.getType());
@ -151,7 +160,8 @@ public class TeleinfoInputStreamTest {
@Test
public void testInvalidADPSgrouplineWithAutoRepairActivated() throws Exception {
try (TeleinfoInputStream in = new TeleinfoInputStream(
new FileInputStream(TestUtils.getTestFile("invalid-adps-groupline.raw")), true)) {
new FileInputStream(TestUtils.getTestFile("invalid-adps-groupline.raw")), true,
TeleinfoTicMode.HISTORICAL)) {
Frame frame = in.readNextFrame();
assertNotNull(frame);
@ -159,4 +169,60 @@ public class TeleinfoInputStreamTest {
assertEquals(37, frame.getAsInt(Label.ADPS));
}
}
@Test
public void testReadNextFrameLinkyTICModeStandardThreePhaseProd() throws Exception {
try (TeleinfoInputStream in = new TeleinfoInputStream(
new FileInputStream(TestUtils.getTestFile("linky-tic-mode-standard-three-phase-prod.raw")), false,
TeleinfoTicMode.STANDARD, true)) {
Frame frame = in.readNextFrame();
assertNotNull(frame);
assertEquals(FrameType.LSMT_PROD, frame.getType());
assertEquals("123456789012", frame.get(Label.ADSC));
assertEquals("02", frame.get(Label.VTIC));
assertEquals("", frame.get(Label.DATE));
assertEquals(" TEMPO ", frame.get(Label.NGTF));
assertEquals(" HP BLEU ", frame.get(Label.LTARF));
assertEquals(11604109, frame.getAsInt(Label.EAST));
assertEquals(2741488, frame.getAsInt(Label.EASF01));
assertEquals(18, frame.getAsInt(Label.PCOUP));
assertEquals("2021-04-14T08:26:25", frame.getAsDateTime(Label.DATE));
DateTimeType dateTime = DateTimeType.valueOf(frame.getAsDateTime(Label.DATE));
assertEquals(2021, dateTime.getZonedDateTime().getYear());
assertEquals(Month.APRIL, dateTime.getZonedDateTime().getMonth());
assertEquals(14, dateTime.getZonedDateTime().getDayOfMonth());
assertEquals(8, dateTime.getZonedDateTime().getHour());
assertEquals(26, dateTime.getZonedDateTime().getMinute());
assertEquals(25, dateTime.getZonedDateTime().getSecond());
assertNotEquals(TeleinfoBindingConstants.NOT_A_CHANNEL, Label.CCASN.getTimestampChannelName());
assertEquals("2021-04-14T08:00:00", frame.getAsDateTime(Label.CCASN));
dateTime = DateTimeType.valueOf(frame.getAsDateTime(Label.CCASN));
assertEquals(2021, dateTime.getZonedDateTime().getYear());
assertEquals(Month.APRIL, dateTime.getZonedDateTime().getMonth());
assertEquals(14, dateTime.getZonedDateTime().getDayOfMonth());
assertEquals(8, dateTime.getZonedDateTime().getHour());
assertEquals(0, dateTime.getZonedDateTime().getMinute());
assertEquals(0, dateTime.getZonedDateTime().getSecond());
}
}
@Test
public void testReadNextFrameLinkyTICModeStandardSinglePhaseProd() throws Exception {
try (TeleinfoInputStream in = new TeleinfoInputStream(
new FileInputStream(TestUtils.getTestFile("linky-tic-mode-standard-single-phase-prod.raw")),
TeleinfoTicMode.STANDARD, true)) {
Frame frame = in.readNextFrame();
assertNotNull(frame);
assertEquals(FrameType.LSMM_PROD, frame.getType());
assertEquals("123456789012", frame.get(Label.ADSC));
assertEquals("02", frame.get(Label.VTIC));
assertEquals("", frame.get(Label.DATE));
assertEquals("PRODUCTEUR", frame.get(Label.NGTF));
assertEquals("INDEX NON CONSO ", frame.get(Label.LTARF));
assertEquals(0, frame.getAsInt(Label.EAST));
assertEquals(0, frame.getAsInt(Label.EASF01));
assertEquals(32781, frame.getAsInt(Label.EAIT));
}
}
}

View File

@ -0,0 +1,75 @@
/**
* Copyright (c) 2010-2021 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.teleinfo.internal.reader.io.serialport;
import static org.junit.jupiter.api.Assertions.*;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.Test;
import org.openhab.binding.teleinfo.internal.reader.io.TeleinfoInputStream;
import org.openhab.binding.teleinfo.internal.serial.TeleinfoTicMode;
import org.openhab.binding.teleinfo.util.TestUtils;
/**
*
* @author Olivier MARCEAU - Initial contribution
*/
@NonNullByDefault
public class FrameUtilTest {
@Test
public void testComputeGroupLineChecksumThreePhaseProd() throws Exception {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(
new FileInputStream(TestUtils.getTestFile("linky-tic-mode-standard-three-phase-prod.raw"))));
String groupLine;
int i = 0;
while ((groupLine = bufferedReader.readLine()) != null) {
if (i >= 1 && !TeleinfoInputStream.isHeaderFrame(groupLine)) {
char expected = groupLine.charAt(groupLine.length() - 1);
char actual = FrameUtil.computeGroupLineChecksum(groupLine.substring(0, groupLine.length() - 2),
TeleinfoTicMode.STANDARD);
assertEquals(expected, actual, i + " " + groupLine + " " + (int) expected + " " + (int) actual);
}
i++;
}
}
@Test
public void testComputeGroupLineChecksumSinglePhaseProd() throws Exception {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(
new FileInputStream(TestUtils.getTestFile("linky-tic-mode-standard-single-phase-prod.raw"))));
String groupLine;
int i = 0;
while ((groupLine = bufferedReader.readLine()) != null) {
if (i >= 1 && !TeleinfoInputStream.isHeaderFrame(groupLine)) {
char expected = groupLine.charAt(groupLine.length() - 1);
char actual = FrameUtil.computeGroupLineChecksum(groupLine.substring(0, groupLine.length() - 2),
TeleinfoTicMode.STANDARD);
assertEquals(expected, actual, i + " " + groupLine + " " + (int) expected + " " + (int) actual);
}
i++;
}
}
@Test
public void testComputeRelaisStates() {
assertArrayEquals(new boolean[] { true, false, false, false, false, false, false, false },
FrameUtil.parseRelaisStates("001"));
assertArrayEquals(new boolean[] { false, false, true, true, false, false, false, true },
FrameUtil.parseRelaisStates("140"));
}
}

View File

@ -14,6 +14,6 @@ IMAX3 027 ;
PMAX 07990 ?
PAPP 00540 *
MOTDETAT 400000 F
PPOT 00 #
PPOT 00 #

ADCO XXXXXXXXXXXX 7

View File

@ -15,6 +15,6 @@ IMAX3 044 :
PMAX 17480 :
PAPP 05800 .
MOTDETAT 000000 B
PPOT 00 #
PPOT 00 #

ADCO XXXXXXXXXX G

View File

@ -0,0 +1,70 @@
EP*PREF 03 B
PCOUP 03 \
SINSTS 00000 F
SMAXSN E180716063417 00021 9
SMAXSN-1 E180715064903 00023 Y
SINSTI 01258 L
SMAXIN E180716103316 01423 /
SMAXIN-1 E180715144229 01971 \
CCASN E180716100000 00000 0
CCASN-1 E180716090000 00000 V
UMOY1 E180716103000 230 +
STGE 002A0301 <
MSG1 PAS DE MESSAGE <
PRM 12345678901234 8
RELAIS 000 B
NTARF 01 N
NJOURF 00 &
NJOURF+1 00 B
PJOURF+1 00008001 NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE 9

ADSC 123456789012 =
VTIC 02 J
DATE E180716103423 B
NGTF PRODUCTEUR .
LTARF INDEX NON CONSO 0
EAST 000000000 O
EASF01 000000000 "
EASF02 000000000 #
EASF03 000000000 $
EASF04 000000000 %
EASF05 000000000 &
EASF06 000000000 '
EASF07 000000000 (
EASF08 000000000 )
EASF09 000000000 *
EASF10 000000000 "
EASD01 000000000
EASD02 000000000 !
EASD03 000000000 "
EASD04 000000000 #
EAIT 000032781 Z
ERQ1 000000000 ;
ERQ2 000000890 M
ERQ3 000002546 N
ERQ4 000000000 >
IRMS1 005 3
URMS1 228 F
PREF 03 B
PCOUP 03 \
SINSTS 00000 F
SMAXSN E180716063417 00021 9
SMAXSN-1 E180715064903 00023 Y
SINSTI 01253 G
SMAXIN E180716103316 01423 /
SMAXIN-1 E180715144229 01971 \
CCASN E180716100000 00000 0
CCASN-1 E180716090000 00000 V
UMOY1 E180716103000 230 +
STGE 002A0301 <
MSG1 PAS DE MESSAGE <
PRM 12345678901234 8
RELAIS 000 B
NTARF 01 N
NJOURF 00 &
NJOURF+1 00 B
PJOURF+1 00008001 NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE 9

ADSC 123456789012 =
VTIC 02 J
DATE E180716103424 C

View File

@ -0,0 +1,171 @@
774332 X
IRMS1 001 /
IRMS2 002 1
IRMS3 001 1
URMS1 234 C
URMS2 240 A
URMS3 242 D
PREF 18 H
PCOUP 18 "
SINSTS 00046 P
SINSTS1 00000 7
SINSTS2 00531 A
SINSTS3 00000 9
SMAXSN E210414070239 02636 <
SMAXSN1 E210414060632 00405 !
SMAXSN2 E210414070239 02194 -
SMAXSN3 E210414054725 00565 0
SMAXSN-1 E210413195606 06560 _
SMAXSN1-1 E210413111148 01084 A
SMAXSN2-1 E210413195606 03275 Q
SMAXSN3-1 E210413195814 02904 Q
SINSTI 00000 <
SMAXIN E210414000000 00000 L
SMAXIN-1 E210413141848 03861 U
CCASN E210414080000 00806 :
CCASN-1 E210414073000 01152 U
CCAIN E210414080000 00000 "
CCAIN-1 E210414073000 00000 B
UMOY1 E210414082000 230 &
UMOY2 E210414082000 239 0
UMOY3 E210414082000 243 ,
STGE 013A0501 @
MSG1 PAS DE MESSAGE <
PRM 12345678901234 8
RELAIS 000 B
NTARF 02 O
NJOURF 00 &
NJOURF+1 00 B
PJOURF+1 00004001 06004002 22004001 NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE .

ADSC 123456789012 =
VTIC 02 J
DATE E210414082625 A
NGTF TEMPO F
LTARF HP BLEU +
EAST 011604109 %
EASF01 002741488 D
EASF02 005905500 ;
EASF03 000624053 8
EASF04 001070566 >
EASF05 000524151 8
EASF06 000738351 B
EASF07 000000000 (
EASF08 000000000 )
EASF09 000000000 *
EASF10 000000000 "
EASD01 011604109 6
EASD02 000000000 !
EASD03 000000000 "
EASD04 000000000 #
EAIT 000671631 ]
ERQ1 002970842 [
ERQ2 000204084 N
ERQ3 000084948 ^
ERQ4 000774332 X
IRMS1 001 /
IRMS2 002 1
IRMS3 001 1
URMS1 234 C
URMS2 240 A
URMS3 242 D
PREF 18 H
PCOUP 18 "
SINSTS 00013 J
SINSTS1 00000 7
SINSTS2 00568 K
SINSTS3 00000 9
SMAXSN E210414070239 02636 <
SMAXSN1 E210414060632 00405 !
SMAXSN2 E210414070239 02194 -
SMAXSN3 E210414054725 00565 0
SMAXSN-1 E210413195606 06560 _
SMAXSN1-1 E210413111148 01084 A
SMAXSN2-1 E210413195606 03275 Q
SMAXSN3-1 E210413195814 02904 Q
SINSTI 00000 <
SMAXIN E210414000000 00000 L
SMAXIN-1 E210413141848 03861 U
CCASN E210414080000 00806 :
CCASN-1 E210414073000 01152 U
CCAIN E210414080000 00000 "
CCAIN-1 E210414073000 00000 B
UMOY1 E210414082000 230 &
UMOY2 E210414082000 239 0
UMOY3 E210414082000 243 ,
STGE 013A0501 @
MSG1 PAS DE MESSAGE <
PRM 12345678901234 8
RELAIS 000 B
NTARF 02 O
NJOURF 00 &
NJOURF+1 00 B
PJOURF+1 00004001 06004002 22004001 NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE .

ADSC 123456789012 =
VTIC 02 J
DATE E210414082627 C
NGTF TEMPO F
LTARF HP BLEU +
EAST 011604109 %
EASF01 002741488 D
EASF02 005905500 ;
EASF03 000624053 8
EASF04 001070566 >
EASF05 000524151 8
EASF06 000738351 B
EASF07 000000000 (
EASF08 000000000 )
EASF09 000000000 *
EASF10 000000000 "
EASD01 011604109 6
EASD02 000000000 !
EASD03 000000000 "
EASD04 000000000 #
EAIT 000671631 ]
ERQ1 002970842 [
ERQ2 000204084 N
ERQ3 000084948 ^
ERQ4 000774332 X
IRMS1 001 /
IRMS2 002 1
IRMS3 001 1
URMS1 234 C
URMS2 240 A
URMS3 242 D
PREF 18 H
PCOUP 18 "
SINSTS 00018 O
SINSTS1 00000 7
SINSTS2 00565 H
SINSTS3 00000 9
SMAXSN E210414070239 02636 <
SMAXSN1 E210414060632 00405 !
SMAXSN2 E210414070239 02194 -
SMAXSN3 E210414054725 00565 0
SMAXSN-1 E210413195606 06560 _
SMAXSN1-1 E210413111148 01084 A
SMAXSN2-1 E210413195606 03275 Q
SMAXSN3-1 E210413195814 02904 Q
SINSTI 00000 <
SMAXIN E210414000000 00000 L
SMAXIN-1 E210413141848 03861 U
CCASN E210414080000 00806 :
CCASN-1 E210414073000 01152 U
CCAIN E210414080000 00000 "
CCAIN-1 E210414073000 00000 B
UMOY1 E210414082000 230 &
UMOY2 E210414082000 239 0
UMOY3 E210414082000 243 ,
STGE 013A0501 @
MSG1 PAS DE MESSAGE <
PRM 12345678901234 8
RELAIS 000 B
NTARF 02 O
NJOURF 00 &
NJOURF+1 00 B
PJOURF+1 00004001 06004002 22004001 NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE .

ADSC 123456789012 =
VTIC 02 J
DATE E210414082629 E