]> git.basschouten.com Git - openhab-addons.git/blob
d23f4b748f8106ac28b598ca66af11acaaa8b2fe
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2020 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.dsmr.internal.device.cosem;
14
15 import java.util.AbstractMap.SimpleEntry;
16 import java.util.Arrays;
17 import java.util.Collections;
18 import java.util.List;
19 import java.util.Map.Entry;
20
21 import org.openhab.binding.dsmr.internal.meter.DSMRMeterConstants;
22 import org.openhab.core.library.unit.SmartHomeUnits;
23
24 /**
25  * Enumeration Cosem Object types
26  * <p>
27  * Each Cosem Object type consists of the following attributes:
28  * <p>
29  * <ul>
30  * <li>OBIS Identifier (reduced form)
31  * <li>List of value descriptors (See {@link CosemValueDescriptor})
32  * <li>List of repeating value descriptors (See {@link CosemValueDescriptor}). Repeating value descriptors will always
33  * be the last descriptors.
34  * </ul>
35  *
36  * @author M. Volaart - Initial contribution
37  * @author Hilbrand Bouwkamp - Cosem subclasses made into factory classes and introduced quantity type
38  */
39 public enum CosemObjectType {
40     UNKNOWN(new OBISIdentifier(-1, DSMRMeterConstants.UNKNOWN_CHANNEL, -1, -1, -1, null), CosemString.INSTANCE),
41
42     /* General messages */
43     P1_VERSION_OUTPUT(new OBISIdentifier(1, 3, 0, 2, 8, null), CosemString.INSTANCE),
44     P1_EMUCS_VERSION_OUTPUT(new OBISIdentifier(0, 0, 96, 1, 4, null), CosemString.INSTANCE),
45     P1_TIMESTAMP(new OBISIdentifier(0, 0, 1, 0, 0, null), new CosemDate("")),
46     P1_TEXT_CODE(new OBISIdentifier(0, 0, 96, 13, 1, null), CosemHexString.INSTANCE),
47     P1_TEXT_STRING(new OBISIdentifier(0, 0, 96, 13, 0, null), CosemHexString.INSTANCE),
48     P1_TEXT_STRING_LONG(new OBISIdentifier(0, 0, 96, 13, null, null), CosemHexString.INSTANCE),
49
50     /* Generic Meter Cosem Object types */
51     METER_EQUIPMENT_IDENTIFIER(new OBISIdentifier(0, null, 96, 1, 0, null), CosemHexString.INSTANCE),
52     METER_DEVICE_TYPE(new OBISIdentifier(0, null, 24, 1, 0, null), CosemString.INSTANCE),
53     METER_VALVE_SWITCH_POSITION(new OBISIdentifier(0, null, 24, 4, 0, null), CosemDecimal.INSTANCE),
54
55     /* Electricity Meter */
56     EMETER_EQUIPMENT_IDENTIFIER_V2_X(new OBISIdentifier(0, 0, 42, 0, 0, null), CosemString.INSTANCE),
57     EMETER_EQUIPMENT_IDENTIFIER(new OBISIdentifier(0, null, 96, 1, 1, null), CosemHexString.INSTANCE),
58     EMETER_VALUE(new OBISIdentifier(0, null, 24, 2, 1, null), CosemDate.INSTANCE, CosemQuantity.KILO_WATT_HOUR),
59     EMETER_DELIVERY_TARIFF0(new OBISIdentifier(1, null, 1, 8, 0, null), CosemQuantity.KILO_WATT_HOUR),
60     EMETER_DELIVERY_TARIFF1(new OBISIdentifier(1, null, 1, 8, 1, null), CosemQuantity.KILO_WATT_HOUR),
61     EMETER_DELIVERY_TARIFF2(new OBISIdentifier(1, null, 1, 8, 2, null), CosemQuantity.KILO_WATT_HOUR),
62     EMETER_DELIVERY_TARIFF0_ANTIFRAUD(new OBISIdentifier(1, null, 15, 8, 0, null), CosemQuantity.KILO_WATT_HOUR),
63     EMETER_DELIVERY_TARIFF1_ANTIFRAUD(new OBISIdentifier(1, null, 15, 8, 1, null), CosemQuantity.KILO_WATT_HOUR),
64     EMETER_DELIVERY_TARIFF2_ANTIFRAUD(new OBISIdentifier(1, null, 15, 8, 2, null), CosemQuantity.KILO_WATT_HOUR),
65     EMETER_PRODUCTION_TARIFF0(new OBISIdentifier(1, null, 2, 8, 0, null), CosemQuantity.KILO_WATT_HOUR),
66     EMETER_PRODUCTION_TARIFF1(new OBISIdentifier(1, null, 2, 8, 1, null), CosemQuantity.KILO_WATT_HOUR),
67     EMETER_PRODUCTION_TARIFF2(new OBISIdentifier(1, null, 2, 8, 2, null), CosemQuantity.KILO_WATT_HOUR),
68     EMETER_TARIFF_INDICATOR(new OBISIdentifier(0, null, 96, 14, 0, null), CosemString.INSTANCE),
69     EMETER_ACTIVE_IMPORT_POWER(new OBISIdentifier(1, null, 15, 7, 0, null), CosemQuantity.WATT),
70     EMETER_ACTUAL_DELIVERY(new OBISIdentifier(1, 0, 1, 7, 0, null), CosemQuantity.KILO_WATT),
71     EMETER_ACTUAL_PRODUCTION(new OBISIdentifier(1, 0, 2, 7, 0, null), CosemQuantity.KILO_WATT),
72     EMETER_TRESHOLD_A_V2_1(new OBISIdentifier(1, 0, 17, 0, 0, null), CosemQuantity.AMPERE),
73     EMETER_TRESHOLD_A(new OBISIdentifier(0, 0, 17, 0, 0, null, true), CosemQuantity.AMPERE),
74     EMETER_FUSE_THRESHOLD_A(new OBISIdentifier(1, 0, 31, 4, 0, null), CosemQuantity.AMPERE),
75     EMETER_TRESHOLD_KWH(new OBISIdentifier(0, 0, 17, 0, 0, null, true), CosemQuantity.KILO_WATT),
76     EMETER_SWITCH_POSITION_V2_1(new OBISIdentifier(1, 0, 96, 3, 10, null), CosemDecimal.INSTANCE),
77     EMETER_SWITCH_POSITION(new OBISIdentifier(0, 0, 96, 3, 10, null), CosemDecimal.INSTANCE),
78     EMETER_POWER_FAILURES(new OBISIdentifier(0, 0, 96, 7, 21, null), CosemDecimal.INSTANCE),
79     EMETER_LONG_POWER_FAILURES(new OBISIdentifier(0, 0, 96, 7, 9, null), CosemDecimal.INSTANCE),
80     EMETER_POWER_FAILURE_LOG(new OBISIdentifier(1, 0, 99, 97, 0, null), 2, new CosemDecimal("entries"),
81             new CosemString("obisId"),
82             /* Next 2 descriptors are repeating */
83             CosemDate.INSTANCE, new CosemQuantity<>(SmartHomeUnits.SECOND, "duration")),
84     EMETER_VOLTAGE_SAGS_L1(new OBISIdentifier(1, 0, 32, 32, 0, null), CosemDecimal.INSTANCE),
85     EMETER_VOLTAGE_SAGS_L2(new OBISIdentifier(1, 0, 52, 32, 0, null), CosemDecimal.INSTANCE),
86     EMETER_VOLTAGE_SAGS_L3(new OBISIdentifier(1, 0, 72, 32, 0, null), CosemDecimal.INSTANCE),
87     EMETER_VOLTAGE_SWELLS_L1(new OBISIdentifier(1, 0, 32, 36, 0, null), CosemDecimal.INSTANCE),
88     EMETER_VOLTAGE_SWELLS_L2(new OBISIdentifier(1, 0, 52, 36, 0, null), CosemDecimal.INSTANCE),
89     EMETER_VOLTAGE_SWELLS_L3(new OBISIdentifier(1, 0, 72, 36, 0, null), CosemDecimal.INSTANCE),
90     EMETER_INSTANT_CURRENT_L1(new OBISIdentifier(1, 0, 31, 7, 0, null), CosemQuantity.AMPERE),
91     EMETER_INSTANT_CURRENT_L2(new OBISIdentifier(1, 0, 51, 7, 0, null), CosemQuantity.AMPERE),
92     EMETER_INSTANT_CURRENT_L3(new OBISIdentifier(1, 0, 71, 7, 0, null), CosemQuantity.AMPERE),
93     EMETER_INSTANT_POWER_DELIVERY_L1(new OBISIdentifier(1, 0, 21, 7, 0, null), CosemQuantity.KILO_WATT),
94     EMETER_INSTANT_POWER_DELIVERY_L2(new OBISIdentifier(1, 0, 41, 7, 0, null), CosemQuantity.KILO_WATT),
95     EMETER_INSTANT_POWER_DELIVERY_L3(new OBISIdentifier(1, 0, 61, 7, 0, null), CosemQuantity.KILO_WATT),
96     EMETER_INSTANT_POWER_PRODUCTION_L1(new OBISIdentifier(1, 0, 22, 7, 0, null), CosemQuantity.KILO_WATT),
97     EMETER_INSTANT_POWER_PRODUCTION_L2(new OBISIdentifier(1, 0, 42, 7, 0, null), CosemQuantity.KILO_WATT),
98     EMETER_INSTANT_POWER_PRODUCTION_L3(new OBISIdentifier(1, 0, 62, 7, 0, null), CosemQuantity.KILO_WATT),
99     EMETER_INSTANT_VOLTAGE_L1(new OBISIdentifier(1, 0, 32, 7, 0, null), CosemQuantity.VOLT),
100     EMETER_INSTANT_VOLTAGE_L2(new OBISIdentifier(1, 0, 52, 7, 0, null), CosemQuantity.VOLT),
101     EMETER_INSTANT_VOLTAGE_L3(new OBISIdentifier(1, 0, 72, 7, 0, null), CosemQuantity.VOLT),
102
103     /* Gas Meter */
104     GMETER_EQUIPMENT_IDENTIFIER_V2(new OBISIdentifier(7, 0, 0, 0, 0, null), CosemString.INSTANCE),
105     GMETER_24H_DELIVERY_V2(new OBISIdentifier(7, 0, 23, 1, 0, null), CosemQuantity.CUBIC_METRE, CosemDate.INSTANCE),
106     GMETER_24H_DELIVERY_COMPENSATED_V2(new OBISIdentifier(7, 0, 23, 2, 0, null), CosemQuantity.CUBIC_METRE,
107             CosemDate.INSTANCE),
108     GMETER_LAST_VALUE(new OBISIdentifier(0, null, 24, 2, 3, null), CosemDate.INSTANCE, CosemQuantity.CUBIC_METRE),
109     GMETER_VALUE_V3(new OBISIdentifier(0, null, 24, 3, 0, null), CosemDate.INSTANCE, // Time stamp off the reading
110             new CosemString("val1"), // Specification is not clear what this value is
111             new CosemDecimal("val2"), // Specification is not clear what this value is
112             new CosemDecimal("val3"), // Specification is not clear what this value is
113             new CosemString("obisId"), // String containing a OBIS Identifier
114             new CosemString("unit"), // String containing the type (m3)
115             CosemDecimal.INSTANCE),
116     GMETER_VALVE_POSITION_V2_1(new OBISIdentifier(7, 0, 96, 3, 10, null), CosemDecimal.INSTANCE),
117     GMETER_VALVE_POSITION_V2_2(new OBISIdentifier(7, 0, 24, 4, 0, null), CosemDecimal.INSTANCE),
118
119     /* Heating Meter */
120     HMETER_EQUIPMENT_IDENTIFIER_V2_2(new OBISIdentifier(5, 0, 0, 0, 0, null), CosemString.INSTANCE),
121     HMETER_VALUE_V2(new OBISIdentifier(5, 0, 1, 0, 0, null), CosemQuantity.GIGA_JOULE, CosemDate.INSTANCE),
122
123     /* Cooling Meter */
124     CMETER_EQUIPMENT_IDENTIFIER_V2_2(new OBISIdentifier(6, 0, 0, 0, 0, null), CosemString.INSTANCE),
125     CMETER_VALUE_V2(new OBISIdentifier(6, 0, 1, 0, 0, null), CosemQuantity.GIGA_JOULE, CosemDate.INSTANCE),
126
127     /* Water Meter */
128     WMETER_EQUIPMENT_IDENTIFIER_V2_2(new OBISIdentifier(8, 0, 0, 0, 0, null), CosemString.INSTANCE),
129     WMETER_VALUE_V2(new OBISIdentifier(8, 0, 1, 0, 0, null), CosemQuantity.CUBIC_METRE, CosemDate.INSTANCE),
130     WMETER_VALUE_V3(new OBISIdentifier(0, null, 24, 3, 0, null), CosemQuantity.CUBIC_METRE),
131
132     /* M3 Meter (Gas, Water) */
133     M3METER_VALUE(new OBISIdentifier(0, null, 24, 2, 1, null), CosemDate.INSTANCE, CosemQuantity.CUBIC_METRE),
134
135     /* GJ Meter (Heating, Cooling) */
136     GJMETER_VALUE_V3(new OBISIdentifier(0, null, 24, 3, 0, null), CosemQuantity.GIGA_JOULE),
137     GJMETER_VALUE_V4(new OBISIdentifier(0, null, 24, 2, 1, null), CosemDate.INSTANCE, CosemQuantity.GIGA_JOULE),
138
139     /* Generic Meter (DSMR v3 only) */
140     GENMETER_VALUE_V3(new OBISIdentifier(0, null, 24, 3, 0, null), CosemDecimal.INSTANCE),
141
142     /* Additional Luxembourgish Smarty Electricity */
143     EMETER_TOTAL_IMPORTED_ENERGY_REGISTER_Q(new OBISIdentifier(1, null, 3, 8, 0, null), CosemQuantity.KILO_VAR_HOUR),
144     EMETER_TOTAL_EXPORTED_ENERGY_REGISTER_Q(new OBISIdentifier(1, null, 4, 8, 0, null), CosemQuantity.KILO_VAR_HOUR),
145     // The actual reactive's and threshold have no unit in the data and therefore are not quantity types.
146     EMETER_ACTUAL_REACTIVE_DELIVERY(new OBISIdentifier(1, 0, 3, 7, 0, null), CosemDecimal.INSTANCE_WITH_UNITS),
147     EMETER_ACTUAL_REACTIVE_PRODUCTION(new OBISIdentifier(1, 0, 4, 7, 0, null), CosemDecimal.INSTANCE_WITH_UNITS),
148     EMETER_ACTIVE_THRESHOLD_SMAX(new OBISIdentifier(0, 0, 17, 0, 0, null, true), CosemDecimal.INSTANCE_WITH_UNITS),
149     EMETER_INSTANT_REACTIVE_POWER_DELIVERY_L1(new OBISIdentifier(1, 0, 23, 7, 0, null), CosemQuantity.KILO_VAR),
150     EMETER_INSTANT_REACTIVE_POWER_DELIVERY_L2(new OBISIdentifier(1, 0, 43, 7, 0, null), CosemQuantity.KILO_VAR),
151     EMETER_INSTANT_REACTIVE_POWER_DELIVERY_L3(new OBISIdentifier(1, 0, 63, 7, 0, null), CosemQuantity.KILO_VAR),
152     EMETER_INSTANT_REACTIVE_POWER_PRODUCTION_L1(new OBISIdentifier(1, 0, 24, 7, 0, null), CosemQuantity.KILO_VAR),
153     EMETER_INSTANT_REACTIVE_POWER_PRODUCTION_L2(new OBISIdentifier(1, 0, 44, 7, 0, null), CosemQuantity.KILO_VAR),
154     EMETER_INSTANT_REACTIVE_POWER_PRODUCTION_L3(new OBISIdentifier(1, 0, 64, 7, 0, null), CosemQuantity.KILO_VAR);
155
156     /** OBIS reduced identifier */
157     public final OBISIdentifier obisId;
158
159     /** COSEM value descriptors */
160     private final List<CosemValueDescriptor<?>> descriptors;
161     private final List<CosemValueDescriptor<?>> repeatingDescriptors;
162
163     /**
164      * Constructs a new CosemObjectType
165      *
166      * @param obisId {@link OBISIdentifier} containing the obisIdentifier for CosemObjectType
167      * @param descriptors variable parameter list of {@link CosemValueDescriptor}
168      */
169     CosemObjectType(OBISIdentifier obisId, CosemValueDescriptor<?>... descriptors) {
170         this(obisId, 0, descriptors);
171     }
172
173     /**
174      * Constructs a new CosemObjectType
175      *
176      * @param obisId {@link OBISIdentifier} containing the obisIdentifier for CosemObjectType
177      * @param nrOfRepeatingDescriptors nr of repeating descriptors (this are the last n descriptors in the variable list
178      *            descriptors)
179      * @param descriptors variable parameter list of {@link CosemValueDescriptor}
180      */
181     CosemObjectType(OBISIdentifier obisId, int nrOfRepeatingDescriptors, CosemValueDescriptor<?>... descriptors) {
182         this.obisId = obisId;
183         if (nrOfRepeatingDescriptors == 0) {
184             this.descriptors = Arrays.asList(descriptors);
185             this.repeatingDescriptors = Collections.emptyList();
186         } else {
187             List<CosemValueDescriptor<?>> allDescriptors = Arrays.asList(descriptors);
188
189             /*
190              * The last nrOfRepeatingDescriptors CosemValueDescriptor will go into the repeatingDescriptor list.
191              * The other descriptors will got into the regular list
192              */
193             this.descriptors = allDescriptors.subList(0, allDescriptors.size() - nrOfRepeatingDescriptors);
194             this.repeatingDescriptors = allDescriptors.subList(this.descriptors.size(),
195                     this.descriptors.size() + nrOfRepeatingDescriptors);
196         }
197     }
198
199     /**
200      * Returns the {@link CosemValueDescriptor} for the specified index.
201      * If the list contains repeating descriptors the specified index will mapped onto the repeating list
202      *
203      * e.g. If the list contains 4 descriptors and the last 2 are repeating, idx=6 will return the 4th descriptor.
204      *
205      * The idx is < 0 or outside a non-repeating descriptorslist size null is returned
206      *
207      * @param idx the CosemValueDescriptor to return
208      * @return the CosemValueDescriptor or null if not found.
209      */
210     public Entry<String, CosemValueDescriptor<?>> getDescriptor(int idx) {
211         if (idx >= descriptors.size() && !repeatingDescriptors.isEmpty()) {
212             /* We have a repeating list, find the correct repeating descriptor */
213             int repeatingIdx = (idx - descriptors.size()) % repeatingDescriptors.size();
214
215             CosemValueDescriptor<?> descriptor = repeatingDescriptors.get(repeatingIdx);
216
217             /* The repeating descriptor must have a specific channel */
218             int repeatCount = (idx - descriptors.size()) / repeatingDescriptors.size();
219
220             return new SimpleEntry<>(descriptor.getChannelId() + repeatCount, descriptor);
221         } else if (idx < descriptors.size()) {
222             CosemValueDescriptor<?> descriptor = descriptors.get(idx);
223
224             return new SimpleEntry<>(descriptor.getChannelId(), descriptor);
225         } else {
226             return null;
227         }
228     }
229
230     /**
231      * Returns if this CosemObjectType supports the requested number of values.
232      *
233      * Note that for repeating list the number of values must match the repeating pattern.
234      *
235      * So if the list contains 4 values and the last 2 are repeating, nrOfValues = 6 will return true,
236      * however nrOfvalues = 7 will return false (only 4, 6, 8, etc... is allowed)
237      *
238      * @param nrOfValues number of values to check.
239      *
240      * @return true if this CosemObjectType support the requested number of values, false otherwise.
241      */
242     public boolean supportsNrOfValues(int nrOfValues) {
243         if (repeatingDescriptors.size() == 0) {
244             return nrOfValues == descriptors.size();
245         } else {
246             /* There are repeating descriptors */
247             return ((nrOfValues - descriptors.size()) % repeatingDescriptors.size()) == 0;
248         }
249     }
250 }