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.device.cosem;
15 import java.text.ParseException;
16 import java.util.ArrayList;
17 import java.util.HashMap;
18 import java.util.List;
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.eclipse.jdt.annotation.Nullable;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
27 * Factory for constructing Cosem Objects from Strings
29 * @author M. Volaart - Initial contribution
32 public class CosemObjectFactory {
33 private final Logger logger = LoggerFactory.getLogger(CosemObjectFactory.class);
36 * Lookup cache for fixed OBIS Identifiers
38 private final Map<OBISIdentifier, CosemObjectType> obisLookupTableFixed = new HashMap<>();
41 * Lookup cache for fixed OBIS Identifiers that has the same id for different data types
43 private final Map<OBISIdentifier, List<CosemObjectType>> obisLookupTableMultipleFixed = new HashMap<>();
46 * Creates a new CosemObjectFactory
48 public CosemObjectFactory() {
50 * Fill lookup tables. There are 3 entities:
51 * - obisLookupTableFixed. This lookup table contains all CosemObjectType with a fixed OBISIdentifier
52 * (i.e. groupA != null && groupB != null && groupC != null).
53 * - obisLookupTableDynamic. This lookup table contains all CosemObjectType with a wildcard OBISIdentifier
54 * (i.e. groupA == null || groupB == null || groupC == null). This lookuptable will be filled
55 * dynamically with unique wildcard OBISIdentifiers when values are received and matches a particular real
56 * device (if the device is changed, this lookupTable must be cleared by removing the corresponding DSMRDevice
57 * Thing from the configuration.)
58 * - obisWildCardCosemTypeList. This is the list of all wild card Cosem Object types. Multiple Cosem Object
59 * Types can have the same wild card OBISIdentifer.
61 * To facilitate autodiscovery the list has all supported CosemObjectTypes. To improve performance once the
62 * correct OBISIdentifier is discovered for a certain OBISMsgType this is added to the obisLookupTableDynamic.
64 for (CosemObjectType msgType : CosemObjectType.values()) {
65 if (msgType.obisId.isConflict()) {
66 obisLookupTableMultipleFixed.computeIfAbsent(msgType.obisId, r -> new ArrayList<>()).add(msgType);
68 obisLookupTableFixed.put(msgType.obisId, msgType);
74 * Return Cosem Object from specified string or null if string couldn't be
75 * parsed correctly or no corresponding Cosem Object was found
77 * @param obisIdString String containing the OBIS message identifier
78 * @param cosemStringValues String containing Cosem values
79 * @return CosemObject or null if parsing failed
81 public @Nullable CosemObject getCosemObject(String obisIdString, String cosemStringValues) {
82 OBISIdentifier obisId;
83 OBISIdentifier reducedObisId;
84 OBISIdentifier reducedObisIdGroupE;
87 obisId = new OBISIdentifier(obisIdString);
88 reducedObisId = obisId.getReducedOBISIdentifier();
89 reducedObisIdGroupE = obisId.getReducedOBISIdentifierGroupE();
90 } catch (final ParseException pe) {
91 logger.debug("Received invalid OBIS identifier: {}", obisIdString);
95 logger.trace("Received obisIdString {}, obisId: {}, values: {}", obisIdString, obisId, cosemStringValues);
97 CosemObjectType objectType = obisLookupTableFixed.get(reducedObisId);
98 if (objectType != null) {
99 logger.trace("Found obisId {} in the fixed lookup table", reducedObisId);
100 return getCosemObjectInternal(objectType, obisId, cosemStringValues);
103 List<CosemObjectType> objectTypeList = obisLookupTableMultipleFixed.get(reducedObisId);
104 if (objectTypeList != null) {
105 for (CosemObjectType cosemObjectType : objectTypeList) {
106 CosemObject cosemObject = getCosemObjectInternal(cosemObjectType, obisId, cosemStringValues);
107 if (cosemObject != null) {
108 logger.trace("Found obisId {} in the fixed lookup table", reducedObisId);
114 objectType = obisLookupTableFixed.get(reducedObisIdGroupE);
115 if (objectType != null) {
116 return getCosemObjectInternal(objectType, obisId, cosemStringValues);
119 logger.debug("Received unknown Cosem Object(OBIS id: {})", obisId);
125 * Constructs a CosemObject from the given type, OBISIdentifier and the values
127 * @param cosemObjectType the type of the CosemObject
128 * @param obisIdentifier the actual OBISIdentifier how this cosemObjectType is identified
129 * @param cosemStringValues the values of the CosemObject
131 * @return a CosemObject or null if parsing failed
133 private @Nullable CosemObject getCosemObjectInternal(CosemObjectType cosemObjectType, OBISIdentifier obisIdentifier,
134 String cosemStringValues) {
135 CosemObject obj = new CosemObject(cosemObjectType, obisIdentifier);
138 logger.trace("Parse values for Cosem Object type: {}", cosemObjectType);
139 obj.parseCosemValues(cosemStringValues);
142 } catch (ParseException pe) {
143 logger.trace("Failed to construct Cosem Object for type {}, values: {}", cosemObjectType, cosemStringValues,