2 * Copyright (c) 2010-2023 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.ArrayList;
17 import java.util.Collection;
18 import java.util.HashMap;
19 import java.util.List;
21 import java.util.Map.Entry;
22 import java.util.stream.Collectors;
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.openhab.binding.dsmr.internal.device.cosem.CosemObject;
26 import org.openhab.binding.dsmr.internal.device.cosem.CosemObjectType;
27 import org.openhab.binding.dsmr.internal.device.p1telegram.P1Telegram;
28 import org.openhab.binding.dsmr.internal.meter.DSMRMeterDescriptor;
29 import org.openhab.binding.dsmr.internal.meter.DSMRMeterKind;
30 import org.openhab.binding.dsmr.internal.meter.DSMRMeterType;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
35 * The {@link DSMRMeterDetector} class contains the logic to discover DSMR Meters from a list of CosemObjects.
37 * @author M. Volaart - Initial contribution
38 * @author Hilbrand Bouwkamp - Refactored code to detect meters during actual discovery phase.
41 class DSMRMeterDetector {
42 private final Logger logger = LoggerFactory.getLogger(DSMRMeterDetector.class);
45 * Returns a collection of {@link DSMRMeterDescriptor} that can handle the supplied list of CosemObjects.
47 * If no meters are detected an empty collection is returned.
49 * @param telegram The received telegram
50 * @return collection of detected {@link DSMRMeterDescriptor}
52 public Entry<Collection<DSMRMeterDescriptor>, List<CosemObject>> detectMeters(P1Telegram telegram) {
53 final Map<DSMRMeterKind, DSMRMeterDescriptor> detectedMeters = new HashMap<>();
54 final List<CosemObject> availableCosemObjects = List.copyOf(telegram.getCosemObjects());
55 final List<CosemObject> undetectedCosemObjects = new ArrayList<>(telegram.getCosemObjects());
57 // Find compatible meters
58 for (DSMRMeterType meterType : DSMRMeterType.values()) {
59 logger.trace("Trying if meter type {} is compatible", meterType);
60 final DSMRMeterDescriptor meterDescriptor = meterType.findCompatible(availableCosemObjects);
62 if (meterDescriptor == null) {
63 logger.trace("Meter type {} is not compatible", meterType);
65 logger.debug("Meter type {} is compatible", meterType);
67 final DSMRMeterDescriptor prevDetectedMeter = detectedMeters.get(meterType.meterKind);
69 if (prevDetectedMeter == null // First meter of this kind, add it
70 || (prevDetectedMeter.getChannel() == meterDescriptor.getChannel())
71 && meterType.requiredCosemObjects.length > prevDetectedMeter
72 .getMeterType().requiredCosemObjects.length) {
73 logger.debug("New compatible meter: {}", meterDescriptor);
74 detectedMeters.put(meterType.meterKind, meterDescriptor);
75 for (CosemObjectType cot : meterDescriptor.getMeterType().supportedCosemObjects) {
76 List<CosemObject> collect = undetectedCosemObjects.stream().filter(u -> cot == u.getType())
77 .collect(Collectors.toList());
78 collect.forEach(undetectedCosemObjects::remove);
83 logger.trace("Telegram as received from the device:\n{}\n", telegram.getRawTelegram());
84 return new SimpleEntry<>(detectedMeters.values(), undetectedCosemObjects);