]> git.basschouten.com Git - openhab-addons.git/blob
32a2955c0fd9e0a37b392857e0936e1085ce93ad
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 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.meter;
14
15 import java.util.Arrays;
16 import java.util.HashMap;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.Map.Entry;
20 import java.util.Optional;
21 import java.util.Set;
22 import java.util.concurrent.atomic.AtomicBoolean;
23 import java.util.concurrent.atomic.AtomicInteger;
24 import java.util.stream.Collectors;
25
26 import org.eclipse.jdt.annotation.NonNullByDefault;
27 import org.eclipse.jdt.annotation.Nullable;
28 import org.openhab.binding.dsmr.internal.DSMRBindingConstants;
29 import org.openhab.binding.dsmr.internal.device.cosem.CosemObject;
30 import org.openhab.binding.dsmr.internal.device.cosem.CosemObjectType;
31 import org.openhab.core.thing.ThingTypeUID;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 /**
36  * Supported meters
37  *
38  * @author M. Volaart - Initial contribution
39  */
40 @NonNullByDefault
41 public enum DSMRMeterType {
42     // Don't auto format the enum list. For readability the format for the enum is:
43     // First line parameters; DSMRMeterKind and CosemObjectType (identification object type)
44     // 2nd line and further required CosemObjectType
45     // optional CosemObjectType start on a new line
46     //@formatter:off
47
48     /** DSMR V2 / V3 Device meter type (used for device (and not meter specific) related messages) */
49     DEVICE_V2_V3(DSMRMeterKind.DEVICE, CosemObjectType.UNKNOWN,
50             CosemObjectType.P1_TEXT_CODE, CosemObjectType.P1_TEXT_STRING),
51
52     /** DSMR V4 Device meter type (used for device (and not meter specific) related messages) */
53     DEVICE_V4(DSMRMeterKind.DEVICE, CosemObjectType.UNKNOWN,
54             CosemObjectType.P1_TEXT_CODE, CosemObjectType.P1_TEXT_STRING, CosemObjectType.P1_VERSION_OUTPUT,
55             CosemObjectType.P1_TIMESTAMP),
56
57     /** DSMR V5 Device meter type (used for device (and not meter specific) related messages) */
58     DEVICE_V5(DSMRMeterKind.DEVICE, CosemObjectType.UNKNOWN,
59             new CosemObjectType[] {
60                     CosemObjectType.P1_TEXT_STRING, CosemObjectType.P1_VERSION_OUTPUT, CosemObjectType.P1_TIMESTAMP },
61             new CosemObjectType[] {
62                     CosemObjectType.P1_TEXT_STRING_LONG }),
63
64     /** ACE4000 Electricity */
65     ELECTRICITY_ACE4000(DSMRMeterKind.MAIN_ELECTRICITY, CosemObjectType.METER_EQUIPMENT_IDENTIFIER,
66             new CosemObjectType[] {
67                     CosemObjectType.METER_EQUIPMENT_IDENTIFIER, CosemObjectType.EMETER_DELIVERY_TARIFF0,
68                     CosemObjectType.EMETER_DELIVERY_TARIFF1, CosemObjectType.EMETER_PRODUCTION_TARIFF0,
69                     CosemObjectType.EMETER_PRODUCTION_TARIFF1, CosemObjectType.EMETER_TARIFF_INDICATOR,
70                     CosemObjectType.EMETER_ACTIVE_IMPORT_POWER, CosemObjectType.EMETER_SWITCH_POSITION },
71             new CosemObjectType[] {
72                     CosemObjectType.EMETER_DELIVERY_TARIFF2, CosemObjectType.EMETER_DELIVERY_TARIFF0_ANTIFRAUD,
73                     CosemObjectType.EMETER_DELIVERY_TARIFF1_ANTIFRAUD, CosemObjectType.EMETER_DELIVERY_TARIFF2_ANTIFRAUD,
74                     CosemObjectType.EMETER_PRODUCTION_TARIFF2, CosemObjectType.EMETER_TRESHOLD_A }),
75
76     /** ACE4000 Gas meter */
77     GAS_ACE4000(DSMRMeterKind.GAS, CosemObjectType.METER_EQUIPMENT_IDENTIFIER,
78             CosemObjectType.METER_EQUIPMENT_IDENTIFIER, CosemObjectType.GMETER_24H_DELIVERY_V2,
79             CosemObjectType.GMETER_VALVE_POSITION_V2_2),
80
81     /** ACE4000 Heating meter */
82     HEATING_ACE4000(DSMRMeterKind.HEATING, CosemObjectType.METER_EQUIPMENT_IDENTIFIER,
83             CosemObjectType.METER_EQUIPMENT_IDENTIFIER, CosemObjectType.HMETER_VALUE_V2),
84
85     /** ACE4000 Cooling meter */
86     COOLING_ACE4000(DSMRMeterKind.COOLING, CosemObjectType.UNKNOWN,
87             CosemObjectType.CMETER_VALUE_V2),
88
89     /** ACE4000 Water meter */
90     WATER_ACE4000(DSMRMeterKind.WATER, CosemObjectType.METER_EQUIPMENT_IDENTIFIER,
91             CosemObjectType.METER_EQUIPMENT_IDENTIFIER, CosemObjectType.WMETER_VALUE_V2),
92
93     /** ACE4000 first Slave electricity meter */
94     SLAVE_ELECTRICITY1_ACE4000(DSMRMeterKind.SLAVE_ELECTRICITY1, CosemObjectType.UNKNOWN,
95             CosemObjectType.EMETER_DELIVERY_TARIFF0, CosemObjectType.EMETER_DELIVERY_TARIFF1,
96             CosemObjectType.EMETER_DELIVERY_TARIFF2, CosemObjectType.EMETER_PRODUCTION_TARIFF0,
97             CosemObjectType.EMETER_PRODUCTION_TARIFF1, CosemObjectType.EMETER_PRODUCTION_TARIFF2,
98             CosemObjectType.EMETER_TARIFF_INDICATOR, CosemObjectType.EMETER_ACTIVE_IMPORT_POWER,
99             CosemObjectType.EMETER_TRESHOLD_A, CosemObjectType.EMETER_SWITCH_POSITION),
100
101     /** ACE4000 second Slave electricity meter */
102     SLAVE_ELECTRICITY2_ACE4000(DSMRMeterKind.SLAVE_ELECTRICITY2, CosemObjectType.UNKNOWN,
103             CosemObjectType.EMETER_DELIVERY_TARIFF0, CosemObjectType.EMETER_DELIVERY_TARIFF1,
104             CosemObjectType.EMETER_DELIVERY_TARIFF2, CosemObjectType.EMETER_PRODUCTION_TARIFF0,
105             CosemObjectType.EMETER_PRODUCTION_TARIFF1, CosemObjectType.EMETER_PRODUCTION_TARIFF2,
106             CosemObjectType.EMETER_TARIFF_INDICATOR, CosemObjectType.EMETER_ACTIVE_IMPORT_POWER,
107             CosemObjectType.EMETER_TRESHOLD_A, CosemObjectType.EMETER_SWITCH_POSITION),
108
109     /** DSMR V2.1 Electricity meter */
110     ELECTRICITY_V2_1(DSMRMeterKind.MAIN_ELECTRICITY, CosemObjectType.EMETER_EQUIPMENT_IDENTIFIER_V2_X,
111             CosemObjectType.EMETER_EQUIPMENT_IDENTIFIER_V2_X, CosemObjectType.EMETER_DELIVERY_TARIFF1,
112             CosemObjectType.EMETER_DELIVERY_TARIFF2, CosemObjectType.EMETER_PRODUCTION_TARIFF1,
113             CosemObjectType.EMETER_PRODUCTION_TARIFF2, CosemObjectType.EMETER_TARIFF_INDICATOR,
114             CosemObjectType.EMETER_TRESHOLD_A_V2_1, CosemObjectType.EMETER_SWITCH_POSITION_V2_1,
115             CosemObjectType.EMETER_ACTUAL_DELIVERY),
116
117     /** DSMR V2.1 Gas meter */
118     GAS_V2_1(DSMRMeterKind.GAS, CosemObjectType.GMETER_EQUIPMENT_IDENTIFIER_V2,
119             CosemObjectType.GMETER_EQUIPMENT_IDENTIFIER_V2, CosemObjectType.GMETER_24H_DELIVERY_V2,
120             CosemObjectType.GMETER_24H_DELIVERY_COMPENSATED_V2, CosemObjectType.GMETER_VALVE_POSITION_V2_1),
121
122     /** DSMR V2.2 Electricity meter */
123     ELECTRICITY_V2_2(DSMRMeterKind.MAIN_ELECTRICITY, CosemObjectType.EMETER_EQUIPMENT_IDENTIFIER_V2_X,
124             CosemObjectType.EMETER_EQUIPMENT_IDENTIFIER_V2_X, CosemObjectType.EMETER_DELIVERY_TARIFF1,
125             CosemObjectType.EMETER_DELIVERY_TARIFF2, CosemObjectType.EMETER_PRODUCTION_TARIFF1,
126             CosemObjectType.EMETER_PRODUCTION_TARIFF2, CosemObjectType.EMETER_TARIFF_INDICATOR,
127             CosemObjectType.EMETER_TRESHOLD_A, CosemObjectType.METER_VALVE_SWITCH_POSITION,
128             CosemObjectType.EMETER_ACTUAL_DELIVERY),
129
130     /** DSMR V2.2 Gas meter */
131     GAS_V2_2(DSMRMeterKind.GAS, CosemObjectType.GMETER_EQUIPMENT_IDENTIFIER_V2,
132             CosemObjectType.GMETER_EQUIPMENT_IDENTIFIER_V2, CosemObjectType.GMETER_24H_DELIVERY_V2,
133             CosemObjectType.GMETER_24H_DELIVERY_COMPENSATED_V2, CosemObjectType.GMETER_VALVE_POSITION_V2_2),
134
135     /** DSMR V2.2 Heating meter */
136     HEATING_V2_2(DSMRMeterKind.HEATING, CosemObjectType.HMETER_EQUIPMENT_IDENTIFIER_V2_2,
137             CosemObjectType.HMETER_EQUIPMENT_IDENTIFIER_V2_2, CosemObjectType.HMETER_VALUE_V2),
138
139     /** DSMR V2.2 Cooling meter */
140     COOLING_V2_2(DSMRMeterKind.COOLING, CosemObjectType.CMETER_EQUIPMENT_IDENTIFIER_V2_2,
141             CosemObjectType.CMETER_EQUIPMENT_IDENTIFIER_V2_2, CosemObjectType.CMETER_VALUE_V2),
142
143     /** DSMR V2.2 Water meter */
144     WATER_V2_2(DSMRMeterKind.WATER, CosemObjectType.WMETER_EQUIPMENT_IDENTIFIER_V2_2,
145             CosemObjectType.WMETER_EQUIPMENT_IDENTIFIER_V2_2, CosemObjectType.WMETER_VALUE_V2),
146
147     /** DSMR V3.0 Electricity meter */
148     ELECTRICITY_V3_0(DSMRMeterKind.MAIN_ELECTRICITY, CosemObjectType.EMETER_EQUIPMENT_IDENTIFIER,
149             new CosemObjectType[] {
150                     CosemObjectType.EMETER_EQUIPMENT_IDENTIFIER, CosemObjectType.EMETER_DELIVERY_TARIFF1,
151                     CosemObjectType.EMETER_DELIVERY_TARIFF2, CosemObjectType.EMETER_PRODUCTION_TARIFF1,
152                     CosemObjectType.EMETER_PRODUCTION_TARIFF2, CosemObjectType.EMETER_TARIFF_INDICATOR,
153                     CosemObjectType.EMETER_ACTUAL_DELIVERY, CosemObjectType.EMETER_ACTUAL_PRODUCTION},
154             new CosemObjectType[] {
155                     CosemObjectType.EMETER_TRESHOLD_A, CosemObjectType.EMETER_TRESHOLD_KW,
156                     CosemObjectType.EMETER_SWITCH_POSITION}),
157
158     /** DSMR V3.0 Gas meter */
159     GAS_V3_0(DSMRMeterKind.GAS, CosemObjectType.METER_EQUIPMENT_IDENTIFIER,
160             new CosemObjectType[] {
161                     CosemObjectType.METER_DEVICE_TYPE, CosemObjectType.METER_EQUIPMENT_IDENTIFIER,
162                     CosemObjectType.GMETER_VALUE_V3},
163             new CosemObjectType[] {
164                     CosemObjectType.METER_VALVE_SWITCH_POSITION}),
165
166     /** DSMR V3.0 Water meter */
167     WATER_V3_0(DSMRMeterKind.WATER, CosemObjectType.METER_EQUIPMENT_IDENTIFIER,
168             CosemObjectType.METER_DEVICE_TYPE, CosemObjectType.METER_EQUIPMENT_IDENTIFIER,
169             CosemObjectType.WMETER_VALUE_V3, CosemObjectType.METER_VALVE_SWITCH_POSITION),
170
171     /** DSMR V3.0 GJ meter (heating, cooling) */
172     GJ_V3_0(DSMRMeterKind.GJ, CosemObjectType.METER_EQUIPMENT_IDENTIFIER,
173             CosemObjectType.METER_DEVICE_TYPE, CosemObjectType.METER_EQUIPMENT_IDENTIFIER,
174             CosemObjectType.GJMETER_VALUE_V3, CosemObjectType.METER_VALVE_SWITCH_POSITION),
175
176     /** DSMR V3.0 Generic meter */
177     GENERIC_V3_0(DSMRMeterKind.GENERIC, CosemObjectType.METER_EQUIPMENT_IDENTIFIER,
178             CosemObjectType.METER_DEVICE_TYPE, CosemObjectType.METER_EQUIPMENT_IDENTIFIER,
179             CosemObjectType.GENMETER_VALUE_V3, CosemObjectType.METER_VALVE_SWITCH_POSITION),
180
181     /** DSMR V4.0 Electricity meter */
182     ELECTRICITY_V4_0(DSMRMeterKind.MAIN_ELECTRICITY, CosemObjectType.EMETER_EQUIPMENT_IDENTIFIER,
183             new CosemObjectType[] {
184                     CosemObjectType.EMETER_EQUIPMENT_IDENTIFIER, CosemObjectType.EMETER_DELIVERY_TARIFF1,
185                     CosemObjectType.EMETER_DELIVERY_TARIFF2, CosemObjectType.EMETER_PRODUCTION_TARIFF1,
186                     CosemObjectType.EMETER_PRODUCTION_TARIFF2, CosemObjectType.EMETER_TARIFF_INDICATOR,
187                     CosemObjectType.EMETER_TRESHOLD_KW, CosemObjectType.EMETER_SWITCH_POSITION,
188                     CosemObjectType.EMETER_ACTUAL_DELIVERY, CosemObjectType.EMETER_ACTUAL_PRODUCTION,
189                     CosemObjectType.EMETER_POWER_FAILURES, CosemObjectType.EMETER_LONG_POWER_FAILURES,
190                     CosemObjectType.EMETER_VOLTAGE_SAGS_L1, CosemObjectType.EMETER_VOLTAGE_SWELLS_L1 },
191             new CosemObjectType[] {
192                     CosemObjectType.EMETER_POWER_FAILURE_LOG, CosemObjectType.EMETER_VOLTAGE_SAGS_L2,
193                     CosemObjectType.EMETER_VOLTAGE_SAGS_L3, CosemObjectType.EMETER_VOLTAGE_SWELLS_L2,
194                     CosemObjectType.EMETER_VOLTAGE_SWELLS_L3 }),
195
196     /** DSMR V4 m3 meter (gas, water) */
197     M3_V4(DSMRMeterKind.M3, CosemObjectType.METER_EQUIPMENT_IDENTIFIER,
198             CosemObjectType.METER_DEVICE_TYPE, CosemObjectType.METER_EQUIPMENT_IDENTIFIER,
199             CosemObjectType.M3METER_VALUE, CosemObjectType.METER_VALVE_SWITCH_POSITION),
200
201     /** DSMR V4 GJ meter (heating, cooling) */
202     GJ_V4(DSMRMeterKind.GJ, CosemObjectType.METER_EQUIPMENT_IDENTIFIER,
203             CosemObjectType.METER_DEVICE_TYPE, CosemObjectType.METER_EQUIPMENT_IDENTIFIER,
204             CosemObjectType.GJMETER_VALUE_V4, CosemObjectType.METER_VALVE_SWITCH_POSITION),
205
206     /** DSMR V4 Slave Electricity meter */
207     SLAVE_ELECTRICITY_V4(DSMRMeterKind.SLAVE_ELECTRICITY1, CosemObjectType.METER_EQUIPMENT_IDENTIFIER,
208             CosemObjectType.METER_DEVICE_TYPE, CosemObjectType.METER_EQUIPMENT_IDENTIFIER,
209             CosemObjectType.EMETER_VALUE, CosemObjectType.EMETER_SWITCH_POSITION),
210
211     /** DSMR V4.0.4 Electricity meter */
212     ELECTRICITY_V4_0_4(DSMRMeterKind.MAIN_ELECTRICITY, CosemObjectType.EMETER_EQUIPMENT_IDENTIFIER,
213             new CosemObjectType[] {
214                     CosemObjectType.EMETER_EQUIPMENT_IDENTIFIER, CosemObjectType.EMETER_DELIVERY_TARIFF1,
215                     CosemObjectType.EMETER_DELIVERY_TARIFF2, CosemObjectType.EMETER_PRODUCTION_TARIFF1,
216                     CosemObjectType.EMETER_PRODUCTION_TARIFF2, CosemObjectType.EMETER_TARIFF_INDICATOR,
217                     CosemObjectType.EMETER_TRESHOLD_KW, CosemObjectType.EMETER_SWITCH_POSITION,
218                     CosemObjectType.EMETER_ACTUAL_DELIVERY, CosemObjectType.EMETER_ACTUAL_PRODUCTION,
219                     CosemObjectType.EMETER_POWER_FAILURES, CosemObjectType.EMETER_LONG_POWER_FAILURES,
220                     CosemObjectType.EMETER_VOLTAGE_SAGS_L1, CosemObjectType.EMETER_VOLTAGE_SWELLS_L1,
221                     CosemObjectType.EMETER_INSTANT_CURRENT_L1, CosemObjectType.EMETER_INSTANT_POWER_DELIVERY_L1,
222                     CosemObjectType.EMETER_INSTANT_POWER_PRODUCTION_L1 },
223             new CosemObjectType[] {
224                     CosemObjectType.EMETER_POWER_FAILURE_LOG, CosemObjectType.EMETER_VOLTAGE_SAGS_L2,
225                     CosemObjectType.EMETER_VOLTAGE_SAGS_L3, CosemObjectType.EMETER_VOLTAGE_SWELLS_L2,
226                     CosemObjectType.EMETER_VOLTAGE_SWELLS_L3, CosemObjectType.EMETER_INSTANT_CURRENT_L2,
227                     CosemObjectType.EMETER_INSTANT_CURRENT_L3, CosemObjectType.EMETER_INSTANT_POWER_DELIVERY_L2,
228                     CosemObjectType.EMETER_INSTANT_POWER_DELIVERY_L3, CosemObjectType.EMETER_INSTANT_POWER_PRODUCTION_L2,
229                     CosemObjectType.EMETER_INSTANT_POWER_PRODUCTION_L3 }),
230
231     /** DSMR V4.2 Electricity meter (specification not available, implemented by reverse engineering */
232     ELECTRICITY_V4_2(DSMRMeterKind.MAIN_ELECTRICITY, CosemObjectType.EMETER_EQUIPMENT_IDENTIFIER,
233             new CosemObjectType[] {
234                     CosemObjectType.EMETER_EQUIPMENT_IDENTIFIER, CosemObjectType.EMETER_DELIVERY_TARIFF1,
235                     CosemObjectType.EMETER_DELIVERY_TARIFF2, CosemObjectType.EMETER_PRODUCTION_TARIFF1,
236                     CosemObjectType.EMETER_PRODUCTION_TARIFF2, CosemObjectType.EMETER_TARIFF_INDICATOR,
237                     CosemObjectType.EMETER_ACTUAL_DELIVERY, CosemObjectType.EMETER_ACTUAL_PRODUCTION,
238                     CosemObjectType.EMETER_POWER_FAILURES, CosemObjectType.EMETER_LONG_POWER_FAILURES,
239                     CosemObjectType.EMETER_VOLTAGE_SAGS_L1, CosemObjectType.EMETER_VOLTAGE_SWELLS_L1,
240                     CosemObjectType.EMETER_INSTANT_CURRENT_L1, CosemObjectType.EMETER_INSTANT_POWER_DELIVERY_L1,
241                     CosemObjectType.EMETER_INSTANT_POWER_PRODUCTION_L1 },
242             new CosemObjectType[] {
243                     CosemObjectType.EMETER_POWER_FAILURE_LOG, CosemObjectType.EMETER_VOLTAGE_SAGS_L2,
244                     CosemObjectType.EMETER_VOLTAGE_SAGS_L3, CosemObjectType.EMETER_VOLTAGE_SWELLS_L2,
245                     CosemObjectType.EMETER_VOLTAGE_SWELLS_L3, CosemObjectType.EMETER_INSTANT_CURRENT_L2,
246                     CosemObjectType.EMETER_INSTANT_CURRENT_L3, CosemObjectType.EMETER_INSTANT_POWER_DELIVERY_L2,
247                     CosemObjectType.EMETER_INSTANT_POWER_DELIVERY_L3, CosemObjectType.EMETER_INSTANT_POWER_PRODUCTION_L2,
248                     CosemObjectType.EMETER_INSTANT_POWER_PRODUCTION_L3 }),
249
250     /** DSMR V5.0 Electricity meter */
251     ELECTRICITY_V5_0(DSMRMeterKind.MAIN_ELECTRICITY, CosemObjectType.EMETER_EQUIPMENT_IDENTIFIER,
252             new CosemObjectType[] {
253                     CosemObjectType.EMETER_EQUIPMENT_IDENTIFIER, CosemObjectType.EMETER_DELIVERY_TARIFF1,
254                     CosemObjectType.EMETER_DELIVERY_TARIFF2, CosemObjectType.EMETER_PRODUCTION_TARIFF1,
255                     CosemObjectType.EMETER_PRODUCTION_TARIFF2, CosemObjectType.EMETER_TARIFF_INDICATOR,
256                     CosemObjectType.EMETER_ACTUAL_DELIVERY, CosemObjectType.EMETER_ACTUAL_PRODUCTION,
257                     CosemObjectType.EMETER_POWER_FAILURES, CosemObjectType.EMETER_LONG_POWER_FAILURES,
258                     CosemObjectType.EMETER_VOLTAGE_SAGS_L1, CosemObjectType.EMETER_VOLTAGE_SWELLS_L1,
259                     CosemObjectType.EMETER_INSTANT_CURRENT_L1, CosemObjectType.EMETER_INSTANT_POWER_DELIVERY_L1,
260                     CosemObjectType.EMETER_INSTANT_POWER_PRODUCTION_L1, CosemObjectType.EMETER_INSTANT_VOLTAGE_L1 },
261             new CosemObjectType[] {
262                     CosemObjectType.EMETER_POWER_FAILURE_LOG, CosemObjectType.EMETER_VOLTAGE_SAGS_L2,
263                     CosemObjectType.EMETER_VOLTAGE_SAGS_L3, CosemObjectType.EMETER_VOLTAGE_SWELLS_L2,
264                     CosemObjectType.EMETER_VOLTAGE_SWELLS_L3, CosemObjectType.EMETER_INSTANT_CURRENT_L2,
265                     CosemObjectType.EMETER_INSTANT_CURRENT_L3, CosemObjectType.EMETER_INSTANT_POWER_DELIVERY_L2,
266                     CosemObjectType.EMETER_INSTANT_POWER_DELIVERY_L3, CosemObjectType.EMETER_INSTANT_POWER_PRODUCTION_L2,
267                     CosemObjectType.EMETER_INSTANT_POWER_PRODUCTION_L3, CosemObjectType.EMETER_INSTANT_VOLTAGE_L2,
268                     CosemObjectType.EMETER_INSTANT_VOLTAGE_L3 }),
269
270     /** DSMR V5.0 m3 meter (gas, water) */
271     M3_V5_0(DSMRMeterKind.M3, CosemObjectType.METER_EQUIPMENT_IDENTIFIER,
272             CosemObjectType.METER_DEVICE_TYPE, CosemObjectType.METER_EQUIPMENT_IDENTIFIER,
273             CosemObjectType.M3METER_VALUE),
274
275     /** DSMR V5.0 GJ meter (heating, cooling) */
276     GJ_V5_0(DSMRMeterKind.GJ, CosemObjectType.METER_EQUIPMENT_IDENTIFIER,
277             CosemObjectType.METER_DEVICE_TYPE, CosemObjectType.METER_EQUIPMENT_IDENTIFIER,
278             CosemObjectType.GJMETER_VALUE_V4),
279
280     /** DSMR V5.0 Slave Electricity meter */
281     SLAVE_ELECTRICITY_V5_0(DSMRMeterKind.SLAVE_ELECTRICITY1, CosemObjectType.METER_EQUIPMENT_IDENTIFIER,
282             CosemObjectType.METER_DEVICE_TYPE, CosemObjectType.METER_EQUIPMENT_IDENTIFIER,
283             CosemObjectType.EMETER_VALUE),
284
285     /** Luxembourg "Smarty" V1.0 Electricity meter */
286     ELECTRICITY_SMARTY_V1_0(DSMRMeterKind.MAIN_ELECTRICITY, CosemObjectType.EMETER_EQUIPMENT_IDENTIFIER_V2_X,
287             new CosemObjectType[] {
288                     CosemObjectType.EMETER_EQUIPMENT_IDENTIFIER_V2_X, CosemObjectType.EMETER_DELIVERY_TARIFF0,
289                     CosemObjectType.EMETER_PRODUCTION_TARIFF0, CosemObjectType.EMETER_TOTAL_IMPORTED_ENERGY_REGISTER_Q,
290                     CosemObjectType.EMETER_TOTAL_EXPORTED_ENERGY_REGISTER_Q, CosemObjectType.EMETER_ACTUAL_DELIVERY,
291                     CosemObjectType.EMETER_ACTUAL_PRODUCTION, CosemObjectType.EMETER_ACTUAL_REACTIVE_DELIVERY,
292                     CosemObjectType.EMETER_ACTUAL_REACTIVE_PRODUCTION,
293                     CosemObjectType.EMETER_SWITCH_POSITION },
294             new CosemObjectType[] {
295                     CosemObjectType.EMETER_TRESHOLD_KW, CosemObjectType.EMETER_ACTIVE_THRESHOLD_SMAX,
296                     CosemObjectType.EMETER_POWER_FAILURES, CosemObjectType.EMETER_VOLTAGE_SAGS_L1,
297                     CosemObjectType.EMETER_VOLTAGE_SAGS_L2, CosemObjectType.EMETER_VOLTAGE_SAGS_L3,
298                     CosemObjectType.EMETER_VOLTAGE_SWELLS_L1, CosemObjectType.EMETER_VOLTAGE_SWELLS_L2,
299                     CosemObjectType.EMETER_VOLTAGE_SWELLS_L3, CosemObjectType.EMETER_INSTANT_CURRENT_L1,
300                     CosemObjectType.EMETER_INSTANT_CURRENT_L2, CosemObjectType.EMETER_INSTANT_CURRENT_L3,
301                     CosemObjectType.EMETER_INSTANT_POWER_DELIVERY_L1, CosemObjectType.EMETER_INSTANT_POWER_DELIVERY_L2,
302                     CosemObjectType.EMETER_INSTANT_POWER_DELIVERY_L3, CosemObjectType.EMETER_INSTANT_POWER_PRODUCTION_L1,
303                     CosemObjectType.EMETER_INSTANT_POWER_PRODUCTION_L2, CosemObjectType.EMETER_INSTANT_POWER_PRODUCTION_L3,
304                     CosemObjectType.EMETER_INSTANT_REACTIVE_POWER_DELIVERY_L1, CosemObjectType.EMETER_INSTANT_REACTIVE_POWER_DELIVERY_L2,
305                     CosemObjectType.EMETER_INSTANT_REACTIVE_POWER_DELIVERY_L3, CosemObjectType.EMETER_INSTANT_REACTIVE_POWER_PRODUCTION_L1,
306                     CosemObjectType.EMETER_INSTANT_REACTIVE_POWER_PRODUCTION_L2, CosemObjectType.EMETER_INSTANT_REACTIVE_POWER_PRODUCTION_L3,
307     }),
308     /** Austrian "Smarty" meter */
309     ELECTRICITY_SMARTY_V1_0_AUSTRIA(DSMRMeterKind.MAIN_ELECTRICITY, CosemObjectType.UNKNOWN,
310             new CosemObjectType[] {
311                     CosemObjectType.EMETER_DELIVERY_TARIFF0, CosemObjectType.EMETER_DELIVERY_TARIFF1,
312                     CosemObjectType.EMETER_DELIVERY_TARIFF2, CosemObjectType.EMETER_PRODUCTION_TARIFF0,
313                     CosemObjectType.EMETER_PRODUCTION_TARIFF1, CosemObjectType.EMETER_PRODUCTION_TARIFF2,
314                     CosemObjectType.EMETER_ACTUAL_DELIVERY, CosemObjectType.EMETER_ACTUAL_PRODUCTION,
315                     CosemObjectType.EMETER_ACTUAL_REACTIVE_DELIVERY, CosemObjectType.EMETER_ACTUAL_REACTIVE_PRODUCTION,
316                     CosemObjectType.EMETER_TOTAL_IMPORTED_ENERGY_REGISTER_Q, CosemObjectType.EMETER_TOTAL_EXPORTED_ENERGY_REGISTER_Q,
317                     CosemObjectType.EMETER_TOTAL_IMPORTED_ENERGY_REGISTER_R_RATE1, CosemObjectType.EMETER_TOTAL_IMPORTED_ENERGY_REGISTER_R_RATE2,
318                     CosemObjectType.EMETER_TOTAL_EXPORTED_ENERGY_REGISTER_R_RATE1, CosemObjectType.EMETER_TOTAL_EXPORTED_ENERGY_REGISTER_R_RATE2,
319     },
320             new CosemObjectType[] {
321                     CosemObjectType.P1_VERSION_OUTPUT, CosemObjectType.P1_TIMESTAMP,
322     }),
323
324     /** Belgium Smart Meter for the e-MUCS specification */
325     DEVICE_EMUCS_V1_0(DSMRMeterKind.DEVICE, CosemObjectType.UNKNOWN,
326             CosemObjectType.P1_TEXT_STRING, CosemObjectType.P1_TEXT_STRING, CosemObjectType.P1_EMUCS_VERSION_OUTPUT,
327             CosemObjectType.P1_TIMESTAMP),
328
329     /** Belgium Smart Electricity Meter for the e-MUCS specification */
330     ELECTRICITY_EMUCS_V1_0(DSMRMeterKind.MAIN_ELECTRICITY, CosemObjectType.EMETER_EQUIPMENT_IDENTIFIER,
331             new CosemObjectType[] {
332                     CosemObjectType.EMETER_EQUIPMENT_IDENTIFIER, CosemObjectType.EMETER_DELIVERY_TARIFF1,
333                     CosemObjectType.EMETER_DELIVERY_TARIFF2, CosemObjectType.EMETER_PRODUCTION_TARIFF1,
334                     CosemObjectType.EMETER_PRODUCTION_TARIFF2, CosemObjectType.EMETER_TARIFF_INDICATOR,
335                     CosemObjectType.EMETER_ACTUAL_DELIVERY, CosemObjectType.EMETER_ACTUAL_PRODUCTION,
336                     CosemObjectType.EMETER_TRESHOLD_KW, CosemObjectType.EMETER_FUSE_THRESHOLD_A,
337                     CosemObjectType.EMETER_SWITCH_POSITION},
338             new CosemObjectType[] {
339                     CosemObjectType.EMETER_INSTANT_POWER_DELIVERY_L1, CosemObjectType.EMETER_INSTANT_POWER_DELIVERY_L2,
340                     CosemObjectType.EMETER_INSTANT_POWER_DELIVERY_L3, CosemObjectType.EMETER_INSTANT_POWER_PRODUCTION_L1,
341                     CosemObjectType.EMETER_INSTANT_POWER_PRODUCTION_L2, CosemObjectType.EMETER_INSTANT_POWER_PRODUCTION_L3,
342                     CosemObjectType.EMETER_INSTANT_CURRENT_L1, CosemObjectType.EMETER_INSTANT_CURRENT_L2,
343                     CosemObjectType.EMETER_INSTANT_CURRENT_L3, CosemObjectType.EMETER_INSTANT_VOLTAGE_L1,
344                     CosemObjectType.EMETER_INSTANT_VOLTAGE_L2, CosemObjectType.EMETER_INSTANT_VOLTAGE_L3
345     }),
346
347     /** Belgium Smart Gas Meter for the e-MUCS specification */
348     GAS_EMUCS_V1_0(DSMRMeterKind.GAS, CosemObjectType.EMETER_EQUIPMENT_IDENTIFIER,
349             new CosemObjectType[] {
350                     CosemObjectType.EMETER_EQUIPMENT_IDENTIFIER, CosemObjectType.METER_DEVICE_TYPE,
351                     CosemObjectType.GMETER_LAST_VALUE, CosemObjectType.METER_VALVE_SWITCH_POSITION });
352     // @formatter:on
353
354     public static final Set<ThingTypeUID> METER_THING_TYPES = Arrays.asList(DSMRMeterType.values()).stream()
355             .map(DSMRMeterType::getThingTypeUID).collect(Collectors.toSet());
356
357     private final Logger logger = LoggerFactory.getLogger(DSMRMeterType.class);
358
359     /**
360      * Meter kind
361      */
362     public final DSMRMeterKind meterKind;
363
364     /**
365      * Required objects for this meter type
366      */
367     public final CosemObjectType[] requiredCosemObjects;
368
369     /**
370      * Additional object this meter type can receive
371      */
372     public final CosemObjectType[] optionalCosemObjects;
373
374     /**
375      * All objects this meter type can receive (convenience for {requiredCosemObjects, optionalCosemObjects})
376      */
377     public final CosemObjectType[] supportedCosemObjects;
378
379     /**
380      * Which CosemObjectType is used to identify this meter
381      */
382     public final CosemObjectType cosemObjectTypeMeterId;
383
384     /**
385      * Creates a new enum
386      *
387      * @param meterKind kind of meter
388      * @param cosemObjectTypeMeterId identifier cosem object
389      * @param requiredCosemObjects list of objects that are present in this meter type
390      */
391     DSMRMeterType(DSMRMeterKind meterKind, CosemObjectType cosemObjectTypeMeterId,
392             CosemObjectType... requiredCosemObjects) {
393         this(meterKind, cosemObjectTypeMeterId, requiredCosemObjects, new CosemObjectType[0]);
394     }
395
396     /**
397      * Creates a new enum
398      *
399      * @param meterKind kind of meter
400      * @param cosemObjectTypeMeterId identifier cosem object
401      * @param requiredCosemObjects list of objects that are present in this meter type
402      * @param optionalCosemObjects list of objects that are optional present in this meter type
403      */
404     DSMRMeterType(DSMRMeterKind meterKind, CosemObjectType cosemObjectTypeMeterId,
405             CosemObjectType[] requiredCosemObjects, CosemObjectType[] optionalCosemObjects) {
406         this.meterKind = meterKind;
407         this.cosemObjectTypeMeterId = cosemObjectTypeMeterId;
408         this.requiredCosemObjects = requiredCosemObjects;
409         this.optionalCosemObjects = optionalCosemObjects;
410
411         supportedCosemObjects = new CosemObjectType[requiredCosemObjects.length + optionalCosemObjects.length];
412         System.arraycopy(requiredCosemObjects, 0, supportedCosemObjects, 0, requiredCosemObjects.length);
413         System.arraycopy(optionalCosemObjects, 0, supportedCosemObjects, requiredCosemObjects.length,
414                 optionalCosemObjects.length);
415     }
416
417     /**
418      * Returns if this DSMRMeterType is compatible for the Cosem Objects.
419      *
420      * If successful the real OBIS identification message (including the actual channel and identification value)
421      * is returned.
422      * If the meter is compatible but the meter type has no identification message, a message is created using the
423      * UNKNOWN OBISMsgType and no value.
424      * If the meter is not compatible, null is returned
425      *
426      *
427      * @param availableCosemObjects the Cosem Objects to detect if the current meter compatible
428      * @return {@link DSMRMeterDescriptor} containing the identification of the compatible meter
429      */
430     public @Nullable DSMRMeterDescriptor findCompatible(List<CosemObject> availableCosemObjects) {
431         final Map<@Nullable Integer, AtomicInteger> channelCounter = new HashMap<>(3);
432
433         for (final CosemObjectType objectType : requiredCosemObjects) {
434             final AtomicBoolean match = new AtomicBoolean();
435             availableCosemObjects.stream().filter(a -> a.getType() == objectType).forEach(b -> {
436                 match.set(true);
437                 channelCounter.computeIfAbsent(b.getObisIdentifier().getChannel(), t -> new AtomicInteger())
438                         .incrementAndGet();
439             });
440             if (!match.get()) {
441                 logger.trace("Required objectType {} not found for meter: {}", objectType, this);
442                 return null;
443             }
444         }
445         DSMRMeterDescriptor meterDescriptor = null;
446
447         if (meterKind.isChannelRelevant()) {
448             final Optional<Entry<@Nullable Integer, AtomicInteger>> max = channelCounter.entrySet().stream()
449                     .max((e1, e2) -> Integer.compare(e1.getValue().get(), e2.getValue().get()));
450
451             if (max.isPresent()) {
452                 final Integer channel = max.get().getKey();
453                 meterDescriptor = new DSMRMeterDescriptor(this,
454                         channel == null ? DSMRMeterConstants.UNKNOWN_CHANNEL : channel);
455             }
456         } else {
457             meterDescriptor = new DSMRMeterDescriptor(this, DSMRMeterConstants.UNKNOWN_CHANNEL);
458         }
459
460         // Meter type is compatible, check if an identification exists
461         if (meterDescriptor == null && cosemObjectTypeMeterId == CosemObjectType.UNKNOWN) {
462             logger.trace("Meter type {} has no identification, but is compatible", this);
463             meterDescriptor = new DSMRMeterDescriptor(this, DSMRMeterConstants.UNKNOWN_CHANNEL);
464         } else if (meterDescriptor != null) {
465             logger.trace("Meter type is compatible and has the following meter type:{}", this);
466         }
467         return meterDescriptor;
468     }
469
470     /**
471      * Returns the ThingTypeUID for this meterType
472      *
473      * @return {@link ThingTypeUID} containing the unique identifier for this meter type
474      */
475     public ThingTypeUID getThingTypeUID() {
476         return new ThingTypeUID(DSMRBindingConstants.BINDING_ID, name().toLowerCase());
477     }
478 }