2 * Copyright (c) 2010-2020 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
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
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.dsmr.internal.discovery;
15 import java.util.AbstractMap.SimpleEntry;
16 import java.util.Collection;
17 import java.util.HashMap;
19 import java.util.Map.Entry;
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.openhab.binding.dsmr.internal.device.cosem.CosemObject;
23 import org.openhab.binding.dsmr.internal.device.cosem.CosemObjectType;
24 import org.openhab.binding.dsmr.internal.device.p1telegram.P1Telegram;
25 import org.openhab.binding.dsmr.internal.meter.DSMRMeterDescriptor;
26 import org.openhab.binding.dsmr.internal.meter.DSMRMeterKind;
27 import org.openhab.binding.dsmr.internal.meter.DSMRMeterType;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
32 * The {@link DSMRMeterDetector} class contains the logic to discover DSMR Meters from a list of CosemObjects.
34 * @author M. Volaart - Initial contribution
35 * @author Hilbrand Bouwkamp - Refactored code to detect meters during actual discovery phase.
38 class DSMRMeterDetector {
39 private final Logger logger = LoggerFactory.getLogger(DSMRMeterDetector.class);
42 * Returns a collection of {@link DSMRMeterDescriptor} that can handle the supplied list of CosemObjects.
44 * If no meters are detected an empty collection is returned.
46 * @param telegram The received telegram
47 * @return collection of detected {@link DSMRMeterDescriptor}
49 public Entry<Collection<DSMRMeterDescriptor>, Map<CosemObjectType, CosemObject>> detectMeters(P1Telegram telegram) {
50 final Map<DSMRMeterKind, DSMRMeterDescriptor> detectedMeters = new HashMap<>();
51 final Map<CosemObjectType, CosemObject> availableCosemObjects = new HashMap<>();
52 final Map<CosemObjectType, CosemObject> undetectedCosemObjects = new HashMap<>();
54 // Fill hashmap for fast comparing the set of received Cosem objects to the required set of Cosem Objects
55 telegram.getCosemObjects().forEach(msg -> availableCosemObjects.put(msg.getType(), msg));
56 undetectedCosemObjects.putAll(availableCosemObjects);
58 // Find compatible meters
59 for (DSMRMeterType meterType : DSMRMeterType.values()) {
60 logger.trace("Trying if meter type {} is compatible", meterType);
61 final DSMRMeterDescriptor meterDescriptor = meterType.isCompatible(availableCosemObjects);
63 if (meterDescriptor == null) {
64 logger.trace("Meter type {} is not compatible", meterType);
66 logger.debug("Meter type {} is compatible", meterType);
68 final DSMRMeterDescriptor prevDetectedMeter = detectedMeters.get(meterType.meterKind);
70 if (prevDetectedMeter == null // First meter of this kind, add it
71 || (prevDetectedMeter.getChannel() == meterDescriptor.getChannel())
72 && meterType.requiredCosemObjects.length > prevDetectedMeter
73 .getMeterType().requiredCosemObjects.length) {
74 logger.debug("New compatible meter: {}", meterDescriptor);
75 detectedMeters.put(meterType.meterKind, meterDescriptor);
76 for (CosemObjectType cot : meterDescriptor.getMeterType().supportedCosemObjects) {
77 undetectedCosemObjects.remove(cot);
82 logger.trace("Telegram as received from the device:\n{}\n", telegram.getRawTelegram());
83 return new SimpleEntry<>(detectedMeters.values(), undetectedCosemObjects);