]> git.basschouten.com Git - openhab-addons.git/blob
60655d7e9c22d5d473f2be1e698c98e34aa0bd2d
[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         CosemObjectType objectType = obisLookupTableFixed.get(reducedObisId);
110         if (objectType != null) {
111             logger.trace("Found obisId {} in the fixed lookup table", reducedObisId);
112             return getCosemObjectInternal(objectType, obisId, cosemStringValues);
113         }
114
115         List<CosemObjectType> objectTypeList = obisLookupTableMultipleFixed.get(reducedObisId);
116         if (objectTypeList != null) {
117             for (CosemObjectType cosemObjectType : objectTypeList) {
118                 CosemObject cosemObject = getCosemObjectInternal(cosemObjectType, obisId, cosemStringValues);
119                 if (cosemObject != null) {
120                     logger.trace("Found obisId {} in the fixed lookup table", reducedObisId);
121                     return cosemObject;
122                 }
123             }
124         }
125
126         objectType = obisLookupTableDynamic.get(reducedObisId);
127         if (objectType != null) {
128             logger.trace("Found obisId {} in the dynamic lookup table", reducedObisId);
129             return getCosemObjectInternal(objectType, obisId, cosemStringValues);
130         }
131
132         objectType = obisLookupTableFixed.get(reducedObisIdGroupE);
133         if (objectType != null) {
134             return getCosemObjectInternal(objectType, obisId, cosemStringValues);
135         }
136
137         for (CosemObjectType obisMsgType : obisWildcardCosemTypeList) {
138             if (obisMsgType.obisId.equalsWildCard(reducedObisId)) {
139                 CosemObject cosemObject = getCosemObjectInternal(obisMsgType, obisId, cosemStringValues);
140                 if (cosemObject != null) {
141                     logger.trace("Searched reducedObisId {} in the wild card type list, result: {}", reducedObisId,
142                             cosemObject);
143                     obisLookupTableDynamic.put(reducedObisId, obisMsgType);
144                     return cosemObject;
145                 }
146             }
147         }
148
149         logger.debug("Received unknown Cosem Object(OBIS id: {})", obisId);
150
151         return null;
152     }
153
154     /**
155      * Constructs a CosemObject from the given type, OBISIdentifier and the values
156      *
157      * @param cosemObjectType the type of the CosemObject
158      * @param obisIdentifier the actual OBISIdentifier how this cosemObjectType is identified
159      * @param cosemStringValues the values of the CosemObject
160      *
161      * @return a CosemObject or null if parsing failed
162      */
163     private @Nullable CosemObject getCosemObjectInternal(CosemObjectType cosemObjectType, OBISIdentifier obisIdentifier,
164             String cosemStringValues) {
165         CosemObject obj = new CosemObject(cosemObjectType, obisIdentifier);
166
167         try {
168             logger.trace("Parse values for Cosem Object type: {}", cosemObjectType);
169             obj.parseCosemValues(cosemStringValues);
170
171             return obj;
172         } catch (ParseException pe) {
173             logger.trace("Failed to construct Cosem Object for type {}, values: {}", cosemObjectType, cosemStringValues,
174                     pe);
175         }
176         return null;
177     }
178 }