]> git.basschouten.com Git - openhab-addons.git/blob
adf1bc6694f3483be81207f35596912dac63fd98
[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.text.ParseException;
16 import java.util.ArrayList;
17 import java.util.HashMap;
18 import java.util.List;
19 import java.util.Map;
20
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.eclipse.jdt.annotation.Nullable;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
25
26 /**
27  * Factory for constructing Cosem Objects from Strings
28  *
29  * @author M. Volaart - Initial contribution
30  */
31 @NonNullByDefault
32 public class CosemObjectFactory {
33     private final Logger logger = LoggerFactory.getLogger(CosemObjectFactory.class);
34
35     /**
36      * Lookup cache for fixed OBIS Identifiers
37      */
38     private final Map<OBISIdentifier, CosemObjectType> obisLookupTableFixed = new HashMap<>();
39
40     /**
41      * Lookup cache for fixed OBIS Identifiers that has the same id for different data types
42      */
43     private final Map<OBISIdentifier, List<CosemObjectType>> obisLookupTableMultipleFixed = new HashMap<>();
44
45     /**
46      * Lookup cache for dynamic OBIS Identifiers
47      */
48     private final Map<OBISIdentifier, CosemObjectType> obisLookupTableDynamic = new HashMap<>();
49
50     /**
51      * Lookup cache for wild card Cosem Object types
52      */
53     private final List<CosemObjectType> obisWildcardCosemTypeList = new ArrayList<>();
54
55     /**
56      * Creates a new CosemObjectFactory
57      */
58     public CosemObjectFactory() {
59         /*
60          * Fill lookup tables. There are 3 entities:
61          * - obisLookupTableFixed. This lookup table contains all CosemObjectType with a fixed OBISIdentifier
62          * (i.e. groupA != null && groupB != null && groupC != null).
63          * - obisLookupTableDynamic. This lookup table contains all CosemObjectType with a wildcard OBISIdentifier
64          * (i.e. groupA == null || groupB == null || groupC == null). This lookuptable will be filled
65          * dynamically with unique wildcard OBISIdentifiers when values are received and matches a particular real
66          * device (if the device is changed, this lookupTable must be cleared by removing the corresponding DSMRDevice
67          * Thing from the configuration.
68          * - obisWildCardCosemTypeList. This is the list of all wild card Cosem Object types. Multiple Cosem Object
69          * Types can have the same wild card OBISIdentifer.
70          *
71          * To facilitate autodiscovery the list has all supported CosemObjectTypes. To improve performance once the
72          * correct OBISIdentifier is discovered for a certain OBISMsgType this is added to the obisLookupTableDynamic.
73          */
74         for (CosemObjectType msgType : CosemObjectType.values()) {
75             if (msgType.obisId.reducedOBISIdentifierIsWildCard()) {
76                 obisWildcardCosemTypeList.add(msgType);
77             } else if (msgType.obisId.isConflict()) {
78                 obisLookupTableMultipleFixed.computeIfAbsent(msgType.obisId, r -> new ArrayList<>()).add(msgType);
79             } else {
80                 obisLookupTableFixed.put(msgType.obisId, msgType);
81             }
82         }
83     }
84
85     /**
86      * Return Cosem Object from specified string or null if string couldn't be
87      * parsed correctly or no corresponding Cosem Object was found
88      *
89      * @param obisIdString String containing the OBIS message identifier
90      * @param cosemStringValues String containing Cosem values
91      * @return CosemObject or null if parsing failed
92      */
93     public @Nullable CosemObject getCosemObject(String obisIdString, String cosemStringValues) {
94         OBISIdentifier obisId;
95         OBISIdentifier reducedObisId;
96         OBISIdentifier reducedObisIdGroupE;
97
98         try {
99             obisId = new OBISIdentifier(obisIdString);
100             reducedObisId = obisId.getReducedOBISIdentifier();
101             reducedObisIdGroupE = obisId.getReducedOBISIdentifierGroupE();
102         } catch (final ParseException pe) {
103             logger.debug("Received invalid OBIS identifier: {}", obisIdString);
104             return null;
105         }
106
107         logger.trace("Received obisIdString {}, obisId: {}, values: {}", obisIdString, obisId, cosemStringValues);
108
109         CosemObject cosemObject = null;
110
111         if (obisLookupTableFixed.containsKey(reducedObisId)) {
112             cosemObject = getCosemObjectInternal(obisLookupTableFixed.get(reducedObisId), obisId, cosemStringValues);
113             logger.trace("Found obisId {} in the fixed lookup table", reducedObisId);
114         } else if (obisLookupTableMultipleFixed.containsKey(reducedObisId)) {
115             for (CosemObjectType cosemObjectType : obisLookupTableMultipleFixed.get(reducedObisId)) {
116                 cosemObject = getCosemObjectInternal(cosemObjectType, obisId, cosemStringValues);
117                 if (cosemObject != null) {
118                     logger.trace("Found obisId {} in the fixed lookup table", reducedObisId);
119                     break;
120                 }
121             }
122         } else if (obisLookupTableDynamic.containsKey(reducedObisId)) {
123             logger.trace("Found obisId {} in the dynamic lookup table", reducedObisId);
124             cosemObject = getCosemObjectInternal(obisLookupTableDynamic.get(reducedObisId), obisId, cosemStringValues);
125         } else if (obisLookupTableFixed.containsKey(reducedObisIdGroupE)) {
126             cosemObject = getCosemObjectInternal(obisLookupTableFixed.get(reducedObisIdGroupE), obisId,
127                     cosemStringValues);
128         } else {
129             for (CosemObjectType obisMsgType : obisWildcardCosemTypeList) {
130                 if (obisMsgType.obisId.equalsWildCard(reducedObisId)) {
131                     cosemObject = getCosemObjectInternal(obisMsgType, obisId, cosemStringValues);
132                     if (cosemObject != null) {
133                         logger.trace("Searched reducedObisId {} in the wild card type list, result: {}", reducedObisId,
134                                 cosemObject);
135                         obisLookupTableDynamic.put(reducedObisId, obisMsgType);
136                         break;
137                     }
138                 }
139             }
140         }
141
142         if (cosemObject == null) {
143             logger.debug("Received unknown Cosem Object(OBIS id: {})", obisId);
144         }
145
146         return cosemObject;
147     }
148
149     /**
150      * Constructs a CosemObject from the given type, OBISIdentifier and the values
151      *
152      * @param cosemObjectType the type of the CosemObject
153      * @param obisIdentifier the actual OBISIdentifier how this cosemObjectType is identified
154      * @param cosemStringValues the values of the CosemObject
155      *
156      * @return a CosemObject or null if parsing failed
157      */
158     private @Nullable CosemObject getCosemObjectInternal(CosemObjectType cosemObjectType, OBISIdentifier obisIdentifier,
159             String cosemStringValues) {
160         CosemObject obj = new CosemObject(cosemObjectType, obisIdentifier);
161
162         try {
163             logger.trace("Parse values for Cosem Object type: {}", cosemObjectType);
164             obj.parseCosemValues(cosemStringValues);
165
166             return obj;
167         } catch (ParseException pe) {
168             logger.trace("Failed to construct Cosem Object for type {}, values: {}", cosemObjectType, cosemStringValues,
169                     pe);
170         }
171         return null;
172     }
173 }