diff --git a/bundles/org.openhab.binding.teleinfo/README.md b/bundles/org.openhab.binding.teleinfo/README.md old mode 100644 new mode 100755 index 4a2002a3bf9b3..7ebd4b22d555c --- a/bundles/org.openhab.binding.teleinfo/README.md +++ b/bundles/org.openhab.binding.teleinfo/README.md @@ -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 | All | All | +| easd*XX* | `Number:Energy` | Active energy withdrawn from distributor on index | All | All | +| irms*X* | `Number:ElectricCurrent` | RMS Current on phase *X* | All for , Three-phase for | All | +| urms*X* | `Number:Potential` | RMS Voltage on phase *X* | All for , Three-phase for | 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 , Three-phase for | All | +| dpm*X* | `String` | Start of mobile peak period | All | All | +| fpm*X* | `String` | End of mobile peak period | 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 , Three-phase for | 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 ( ) | 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 | All | All | +| sinsti | `Number:Energy` | Active energy withdrawn from distributor on index | All | All | +| smaxin | `Number:Power` | Maximum injected apparent power of the day | All for , Three-phase for | All | +| smaxinMinus1 | `Number:Power` | Maximum injected apparent power of the previous day | All for , Three-phase for | 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` : ``` diff --git a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/TeleinfoBindingConstants.java b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/TeleinfoBindingConstants.java index 3b942d2c22c39..f2ab5e97e32d4 100644 --- a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/TeleinfoBindingConstants.java +++ b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/TeleinfoBindingConstants.java @@ -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 @@ private 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 @@ private 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 @@ private 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"; diff --git a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/TeleinfoDiscoveryService.java b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/TeleinfoDiscoveryService.java index f3ff6c4bcac81..c6f59a4980e6f 100644 --- a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/TeleinfoDiscoveryService.java +++ b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/TeleinfoDiscoveryService.java @@ -17,8 +17,6 @@ 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 @@ public class TeleinfoDiscoveryService extends AbstractDiscoveryService implements TeleinfoControllerHandlerListener, ThingHandlerService, DiscoveryService { - private static final Set SUPPORTED_THING_TYPES = Stream.of(THING_HC_CBEMM_ELECTRICITY_METER_TYPE_UID, + private static final Set 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 @@ private void detectNewElectricityMeterFromReceivedFrame(final Frame frameSample) 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 @@ private void detectNewElectricityMeterFromReceivedFrame(final Frame frameSample) final Map 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(); diff --git a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/Evolution.java b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/Evolution.java index 158d58a844783..4a51753f1dafa 100644 --- a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/Evolution.java +++ b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/Evolution.java @@ -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 diff --git a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/Frame.java b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/Frame.java index 3594885198abb..e83f83efa7747 100644 --- a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/Frame.java +++ b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/Frame.java @@ -20,6 +20,7 @@ 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 labelToValues = new EnumMap<>(Label.class); + private Map 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 void put(Label label, String value) { 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 Pricing getPricing() throws InvalidFrameException { } } + 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 getLabelToValues() { return labelToValues; } + public Map getLabelToTimestamp() { + return labelToTimestamp; + } + private char getProgrammeChar() { String optarif = labelToValues.get(Label.OPTARIF); if (optarif == null) { diff --git a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/FrameType.java b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/FrameType.java index a829805b37ffd..05a590d9831ad 100644 --- a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/FrameType.java +++ b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/FrameType.java @@ -14,6 +14,8 @@ 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 @@ * @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; } } diff --git a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/Phase.java b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/Phase.java index 44edb6d0a4e25..dfe0c42d8d5f7 100644 --- a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/Phase.java +++ b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/Phase.java @@ -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 diff --git a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/Pricing.java b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/Pricing.java index cef1a504f6e47..6bc6cabcb670c 100644 --- a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/Pricing.java +++ b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/Pricing.java @@ -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, diff --git a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/handler/TeleinfoElectricityMeterHandler.java b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/handler/TeleinfoElectricityMeterHandler.java index 67a8bd8da717b..ee0a0c24b979c 100644 --- a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/handler/TeleinfoElectricityMeterHandler.java +++ b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/handler/TeleinfoElectricityMeterHandler.java @@ -21,10 +21,13 @@ 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 @@ protected void updateStatus(ThingStatus status) { @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 @@ private void updateStatesForChannels(Frame frame) { for (Entry 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())); } } - } - 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())); + 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)); + } } - } 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); + 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); + } + 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()); diff --git a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/handler/TeleinfoThingHandlerFactory.java b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/handler/TeleinfoThingHandlerFactory.java index bc7755c692ecb..2378dddd3b061 100644 --- a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/handler/TeleinfoThingHandlerFactory.java +++ b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/handler/TeleinfoThingHandlerFactory.java @@ -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; diff --git a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/reader/io/TeleinfoInputStream.java b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/reader/io/TeleinfoInputStream.java index 270675054f918..7152be74dc8b5 100644 --- a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/reader/io/TeleinfoInputStream.java +++ b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/reader/io/TeleinfoInputStream.java @@ -24,6 +24,7 @@ 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 void close() throws IOException { 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 void close() throws IOException { } frame.put(label, valueString); + if (timestampString != null) { + frame.putTimestamp(label, timestampString); + } } } @@ -152,7 +188,7 @@ public int read() throws IOException { 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); } diff --git a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/reader/io/serialport/FrameUtil.java b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/reader/io/serialport/FrameUtil.java index ee8268a1f0e0b..fd8b623c969aa 100644 --- a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/reader/io/serialport/FrameUtil.java +++ b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/reader/io/serialport/FrameUtil.java @@ -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 @@ private 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; + } } diff --git a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/reader/io/serialport/Label.java b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/reader/io/serialport/Label.java index 433fb136c862a..e2b56d9f3d57b 100644 --- a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/reader/io/serialport/Label.java +++ b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/reader/io/serialport/Label.java @@ -27,13 +27,14 @@ @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 String getChannelName() { 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); + } } diff --git a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/reader/io/serialport/ValueType.java b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/reader/io/serialport/ValueType.java index 62d743565fe00..76519d3b6790a 100644 --- a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/reader/io/serialport/ValueType.java +++ b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/reader/io/serialport/ValueType.java @@ -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 diff --git a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/serial/TeleinfoReceiveThread.java b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/serial/TeleinfoReceiveThread.java index a3eee6052cf19..7228190bf5d91 100644 --- a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/serial/TeleinfoReceiveThread.java +++ b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/serial/TeleinfoReceiveThread.java @@ -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) { diff --git a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/serial/TeleinfoSerialControllerConfiguration.java b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/serial/TeleinfoSerialControllerConfiguration.java index 654a6250d843f..71711c4dbdee4 100644 --- a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/serial/TeleinfoSerialControllerConfiguration.java +++ b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/serial/TeleinfoSerialControllerConfiguration.java @@ -23,5 +23,7 @@ public class TeleinfoSerialControllerConfiguration { public String serialport = ""; + public String ticMode = ""; + public boolean verifyChecksum = true; public boolean autoRepairInvalidADPSgroupLine = true; } diff --git a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/serial/TeleinfoSerialControllerHandler.java b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/serial/TeleinfoSerialControllerHandler.java index b5e08d32fbdb5..44fe2c15a27b5 100644 --- a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/serial/TeleinfoSerialControllerHandler.java +++ b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/serial/TeleinfoSerialControllerHandler.java @@ -148,7 +148,9 @@ private void openSerialPortAndStartReceiving() { 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 @@ private void openSerialPortAndStartReceiving() { } logger.debug("Starting receive thread"); TeleinfoReceiveThread receiveThread = new TeleinfoReceiveThread(commPort, this, - config.autoRepairInvalidADPSgroupLine); + config.autoRepairInvalidADPSgroupLine, ticMode, config.verifyChecksum); this.receiveThread = receiveThread; receiveThread.start(); diff --git a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/serial/TeleinfoTicMode.java b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/serial/TeleinfoTicMode.java new file mode 100644 index 0000000000000..77cd6ef0bd8b0 --- /dev/null +++ b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/serial/TeleinfoTicMode.java @@ -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; + } +} diff --git a/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/config/config-description.xml b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/config/config-description.xml index 6701d48d220c3..34d2a259b0429 100644 --- a/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/config/config-description.xml +++ b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/config/config-description.xml @@ -7,7 +7,7 @@ - + Electricity meter identifier (format: 12 characters / e.g: '031528042289') false diff --git a/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/common-lsm-channel-group.xml b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/common-lsm-channel-group.xml new file mode 100644 index 0000000000000..8a17dd7845d06 --- /dev/null +++ b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/common-lsm-channel-group.xml @@ -0,0 +1,362 @@ + + + + + + Common channels for Linky telemeter in standard teleinformation mode + Energy + + + + + Provider schedule name + + + + + Current pricing label + + + + + Total active energy withdrawn + + + + + Active energy withdrawn from provider on index 01 + + + + + Active energy withdrawn from provider on index 02 + + + + + Active energy withdrawn from provider on index 03 + + + + + Active energy withdrawn from provider on index 04 + + + + + Active energy withdrawn from provider on index 05 + + + + + Active energy withdrawn from provider on index 06 + + + + + Active energy withdrawn from provider on index 07 + + + + + Active energy withdrawn from provider on index 08 + + + + + Active energy withdrawn from provider on index 09 + + + + + Active energy withdrawn from provider on index 10 + + + + + Active energy withdrawn from distributor on index 01 + + + + + Active energy withdrawn from distributor on index 02 + + + + + Active energy withdrawn from distributor on index 03 + + + + + Active energy withdrawn from distributor on index 04 + + + + + RMS Current on phase 1 + + + + + RMS Voltage on phase 1 + + + + + Reference apparent power + + + + + Apparent power rupture capacity + + + + + Instantaneous withdrawn apparent power + + + + + Maximum withdrawn apparent power of the day + + + + + Maximum withdrawn apparent power of the previous day + + + + + Active charge point N + + + + + Active charge point N-1 + + + + + Mean Voltage on phase 1 + + + + + Status registry + + + + + Start of mobile peak period 1 + + + + + End of mobile peak period 1 + + + + + Start of mobile peak period 2 + + + + + End of mobile peak period 2 + + + + + Start of mobile peak period 3 + + + + + End of mobile peak period 3 + + + + + Short message + + + + + Very short message + + + + + PRM + + + + + + Index of current pricing + + + + + Number of current provider schedule + + + + + Number of next day provider schedule + + + + + Profile of next day provider schedule + + + + + Profile of next rush day + + + + + Date and Time + + + + + Timestamp of SMAXSN value + + + + + Timestamp of SMAXSN-1 value + + + + + Timestamp of CCASN value + + + + + Timestamp of CCASN-1 value + + + + + Timestamp of UMOY1 value + + + + + Date of DPM1 + + + + + Date of FPM1 + + + + + Date of DPM2 + + + + + Date of FPM2 + + + + + Date of DPM3 + + + + + Date of FPM3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + String + + Energy + + + + + Number:Energy + + Energy + + + + + Number:ElectricCurrent + + Energy + + + + + Number:ElectricPotential + + Energy + + + + + Number:Power + + Energy + + + + + Switch + + Energy + + + + + DateTime + + Energy + + + + diff --git a/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/common-lsm-prod-channel-group.xml b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/common-lsm-prod-channel-group.xml new file mode 100644 index 0000000000000..63399587edef0 --- /dev/null +++ b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/common-lsm-prod-channel-group.xml @@ -0,0 +1,133 @@ + + + + + + Producer channels for Linky telemeter in standard teleinformation mode + Energy + + + + Total active energy injected + + + + + Total reactive energy Q1 + + + + + Total reactive energy Q2 + + + + + Total reactive energy Q3 + + + + + Total reactive energy Q4 + + + + + Instantaneous injected apparent power + + + + + Maximum injected apparent power of the day + + + + + Maximum injected apparent power of the previous day + + + + + Injected active charge point N + + + + + Injected active charge point N-1 + + + + + Timestamp of SMAXIN value + + + + + Timestamp of SMAXIN-1 value + + + + + Timestamp of CCAIN value + + + + + Timestamp of CCAIN-1 value + + + + + + String + + Energy + + + + + Number:Energy + + Energy + + + + + Number:ElectricCurrent + + Energy + + + + + Number:ElectricPotential + + Energy + + + + + Number:Power + + Energy + + + + + Switch + + Energy + + + + + DateTime + + Energy + + + + diff --git a/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/common-lsm-three-phase-channel-group.xml b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/common-lsm-three-phase-channel-group.xml new file mode 100644 index 0000000000000..40860229781b2 --- /dev/null +++ b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/common-lsm-three-phase-channel-group.xml @@ -0,0 +1,179 @@ + + + + + + Three-phased channels for Linky telemeter in standard teleinformation mode + Energy + + + + + RMS Current on phase 2 + + + + + RMS Current on phase 3 + + + + + RMS Voltage on phase 2 + + + + + RMS Voltage on phase 3 + + + + + Instantaneous withdrawn apparent power on phase 1 + + + + + Instantaneous withdrawn apparent power on phase 2 + + + + + Instantaneous withdrawn apparent power on phase 3 + + + + + Maximum withdrawn apparent power of the day on phase 1 + + + + + Maximum withdrawn apparent power of the day on phase 2 + + + + + Maximum withdrawn apparent power of the day on phase 3 + + + + + Maximum withdrawn apparent power of the previous day on phase 1 + + + + + Maximum withdrawn apparent power of the previous day on phase 2 + + + + + Maximum withdrawn apparent power of the previous day on phase 3 + + + + + Mean Voltage on phase 2 + + + + + Mean Voltage on phase 3 + + + + + Timestamp of SMAXSN1 value + + + + + Timestamp of SMAXSN2 value + + + + + Timestamp of SMAXSN3 value + + + + + Timestamp of SMAXSN1-1 value + + + + + Timestamp of SMAXSN2-1 value + + + + + Timestamp of SMAXSN3-1 value + + + + + Timestamp of UMOY2 value + + + + + Timestamp of UMOY3 value + + + + + + String + + Energy + + + + + Number:Energy + + Energy + + + + + Number:ElectricCurrent + + Energy + + + + + Number:ElectricPotential + + Energy + + + + + Number:Power + + Energy + + + + + Switch + + Energy + + + + + DateTime + + Energy + + + + diff --git a/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/lsmmElectricityMeter.xml b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/lsmmElectricityMeter.xml new file mode 100644 index 0000000000000..674173ffc8f17 --- /dev/null +++ b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/lsmmElectricityMeter.xml @@ -0,0 +1,23 @@ + + + + + + + + + + Single-phase Linky Electricity meter in standard mode + + + + + + + + + + diff --git a/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/lsmmProdElectricityMeter.xml b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/lsmmProdElectricityMeter.xml new file mode 100644 index 0000000000000..d23487fdeeb6b --- /dev/null +++ b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/lsmmProdElectricityMeter.xml @@ -0,0 +1,24 @@ + + + + + + + + + + Single-phase producer Linky Electricity meter in standard mode + + + + + + + + + + + diff --git a/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/lsmtElectricityMeter.xml b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/lsmtElectricityMeter.xml new file mode 100644 index 0000000000000..de906e24f9e72 --- /dev/null +++ b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/lsmtElectricityMeter.xml @@ -0,0 +1,24 @@ + + + + + + + + + + Three-phase Linky Electricity meter in standard mode + + + + + + + + + + + diff --git a/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/lsmtProdElectricityMeter.xml b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/lsmtProdElectricityMeter.xml new file mode 100644 index 0000000000000..b744df2fdc627 --- /dev/null +++ b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/lsmtProdElectricityMeter.xml @@ -0,0 +1,25 @@ + + + + + + + + + + Three-phase producer Linky Electricity meter in standard mode + + + + + + + + + + + + diff --git a/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/serialController.xml b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/serialController.xml index 486c94676f538..22984bc17e981 100644 --- a/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/serialController.xml +++ b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/serialController.xml @@ -19,6 +19,22 @@ Serial port of Teleinfo device (e.g.: /dev/ttyUSB0 on Linux, COM1 on Windows) false + + + TIC Mode of the telemeter (Standard TIC mode is only available on Linky telemeters) + HISTORICAL + + + + + true + + + + Activate checksum verification + true + true + Try to auto repair malformed ADPS data from hardware issues (e.g: "ADPS032" instead of "ADPS 032" diff --git a/bundles/org.openhab.binding.teleinfo/src/test/java/org/openhab/binding/teleinfo/internal/reader/io/TeleinfoInputStreamTest.java b/bundles/org.openhab.binding.teleinfo/src/test/java/org/openhab/binding/teleinfo/internal/reader/io/TeleinfoInputStreamTest.java index d17f77c9d25a1..d420013900488 100644 --- a/bundles/org.openhab.binding.teleinfo/src/test/java/org/openhab/binding/teleinfo/internal/reader/io/TeleinfoInputStreamTest.java +++ b/bundles/org.openhab.binding.teleinfo/src/test/java/org/openhab/binding/teleinfo/internal/reader/io/TeleinfoInputStreamTest.java @@ -15,13 +15,17 @@ 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 void testReadNextFrameCbetmBase1() throws Exception { @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 void testReadNextFrameCbemmEvoIccHc1() throws Exception { @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 void testReadNextFrameCbetmEjp1() throws Exception { @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 void testReadNextFrameCbemmEvoIccTempo1() throws Exception { @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 void testReadNextFrameCbemmEvoIccBase1() throws Exception { @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 void testInvalidADPSgrouplineWithAutoRepairActivated() throws Exception { 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)); + } + } } diff --git a/bundles/org.openhab.binding.teleinfo/src/test/java/org/openhab/binding/teleinfo/internal/reader/io/serialport/FrameUtilTest.java b/bundles/org.openhab.binding.teleinfo/src/test/java/org/openhab/binding/teleinfo/internal/reader/io/serialport/FrameUtilTest.java new file mode 100644 index 0000000000000..057bc062b7f02 --- /dev/null +++ b/bundles/org.openhab.binding.teleinfo/src/test/java/org/openhab/binding/teleinfo/internal/reader/io/serialport/FrameUtilTest.java @@ -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")); + } +} diff --git a/bundles/org.openhab.binding.teleinfo/src/test/resources/cbemm-evo-icc-tempo-option-1.raw b/bundles/org.openhab.binding.teleinfo/src/test/resources/cbemm-evo-icc-tempo-option-1.raw index e258d50e97c37..33fe7015dca6f 100644 Binary files a/bundles/org.openhab.binding.teleinfo/src/test/resources/cbemm-evo-icc-tempo-option-1.raw and b/bundles/org.openhab.binding.teleinfo/src/test/resources/cbemm-evo-icc-tempo-option-1.raw differ diff --git a/bundles/org.openhab.binding.teleinfo/src/test/resources/cbetm-base-option-1.raw b/bundles/org.openhab.binding.teleinfo/src/test/resources/cbetm-base-option-1.raw index 888d21217de8e..687acf0481001 100644 --- a/bundles/org.openhab.binding.teleinfo/src/test/resources/cbetm-base-option-1.raw +++ b/bundles/org.openhab.binding.teleinfo/src/test/resources/cbetm-base-option-1.raw @@ -14,6 +14,6 @@ IMAX3 027 ; PMAX 07990 ? PAPP 00540 * MOTDETAT 400000 F -PPOT 00 # +PPOT 00 #  ADCO XXXXXXXXXXXX 7 \ No newline at end of file diff --git a/bundles/org.openhab.binding.teleinfo/src/test/resources/cbetm-ejp-option-1.raw b/bundles/org.openhab.binding.teleinfo/src/test/resources/cbetm-ejp-option-1.raw index 6ce7b6c901739..c080ed2ccb7b1 100644 --- a/bundles/org.openhab.binding.teleinfo/src/test/resources/cbetm-ejp-option-1.raw +++ b/bundles/org.openhab.binding.teleinfo/src/test/resources/cbetm-ejp-option-1.raw @@ -15,6 +15,6 @@ IMAX3 044 : PMAX 17480 : PAPP 05800 . MOTDETAT 000000 B -PPOT 00 # +PPOT 00 #  ADCO XXXXXXXXXX G \ No newline at end of file diff --git a/bundles/org.openhab.binding.teleinfo/src/test/resources/linky-tic-mode-standard-single-phase-prod.raw b/bundles/org.openhab.binding.teleinfo/src/test/resources/linky-tic-mode-standard-single-phase-prod.raw new file mode 100644 index 0000000000000..f1057181c7905 --- /dev/null +++ b/bundles/org.openhab.binding.teleinfo/src/test/resources/linky-tic-mode-standard-single-phase-prod.raw @@ -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 diff --git a/bundles/org.openhab.binding.teleinfo/src/test/resources/linky-tic-mode-standard-three-phase-prod.raw b/bundles/org.openhab.binding.teleinfo/src/test/resources/linky-tic-mode-standard-three-phase-prod.raw new file mode 100644 index 0000000000000..dc0225ac94057 --- /dev/null +++ b/bundles/org.openhab.binding.teleinfo/src/test/resources/linky-tic-mode-standard-three-phase-prod.raw @@ -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 \ No newline at end of file