]> git.basschouten.com Git - openhab-addons.git/blob
95880ccbff964c6f09a12aa34ef3ab86f52f7852
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2024 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.siemenshvac.internal.metadata;
14
15 import java.io.File;
16 import java.io.FileOutputStream;
17 import java.io.IOException;
18 import java.math.BigDecimal;
19 import java.net.URI;
20 import java.nio.charset.StandardCharsets;
21 import java.nio.file.Files;
22 import java.time.Duration;
23 import java.time.Instant;
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.Hashtable;
27 import java.util.List;
28 import java.util.Locale;
29 import java.util.Map;
30 import java.util.regex.Matcher;
31 import java.util.regex.Pattern;
32
33 import org.eclipse.jdt.annotation.NonNullByDefault;
34 import org.eclipse.jdt.annotation.Nullable;
35 import org.openhab.binding.siemenshvac.internal.constants.SiemensHvacBindingConstants;
36 import org.openhab.binding.siemenshvac.internal.converter.ConverterFactory;
37 import org.openhab.binding.siemenshvac.internal.converter.ConverterTypeException;
38 import org.openhab.binding.siemenshvac.internal.converter.TypeConverter;
39 import org.openhab.binding.siemenshvac.internal.handler.SiemensHvacBridgeConfig;
40 import org.openhab.binding.siemenshvac.internal.network.SiemensHvacCallback;
41 import org.openhab.binding.siemenshvac.internal.network.SiemensHvacConnector;
42 import org.openhab.binding.siemenshvac.internal.type.SiemensHvacChannelGroupTypeProvider;
43 import org.openhab.binding.siemenshvac.internal.type.SiemensHvacChannelTypeProvider;
44 import org.openhab.binding.siemenshvac.internal.type.SiemensHvacConfigDescriptionProvider;
45 import org.openhab.binding.siemenshvac.internal.type.SiemensHvacException;
46 import org.openhab.binding.siemenshvac.internal.type.SiemensHvacThingTypeProvider;
47 import org.openhab.binding.siemenshvac.internal.type.UidUtils;
48 import org.openhab.core.OpenHAB;
49 import org.openhab.core.config.core.ConfigDescriptionBuilder;
50 import org.openhab.core.config.core.ConfigDescriptionParameter;
51 import org.openhab.core.config.core.ConfigDescriptionParameterGroup;
52 import org.openhab.core.thing.Thing;
53 import org.openhab.core.thing.ThingTypeUID;
54 import org.openhab.core.thing.type.ChannelDefinition;
55 import org.openhab.core.thing.type.ChannelDefinitionBuilder;
56 import org.openhab.core.thing.type.ChannelGroupDefinition;
57 import org.openhab.core.thing.type.ChannelGroupType;
58 import org.openhab.core.thing.type.ChannelGroupTypeBuilder;
59 import org.openhab.core.thing.type.ChannelGroupTypeUID;
60 import org.openhab.core.thing.type.ChannelType;
61 import org.openhab.core.thing.type.ChannelTypeBuilder;
62 import org.openhab.core.thing.type.ChannelTypeUID;
63 import org.openhab.core.thing.type.StateChannelTypeBuilder;
64 import org.openhab.core.thing.type.ThingType;
65 import org.openhab.core.thing.type.ThingTypeBuilder;
66 import org.openhab.core.types.StateDescriptionFragmentBuilder;
67 import org.openhab.core.types.StateOption;
68 import org.osgi.service.component.annotations.Activate;
69 import org.osgi.service.component.annotations.Component;
70 import org.osgi.service.component.annotations.Reference;
71 import org.slf4j.Logger;
72 import org.slf4j.LoggerFactory;
73
74 import com.google.gson.JsonArray;
75 import com.google.gson.JsonElement;
76 import com.google.gson.JsonObject;
77
78 /**
79  *
80  * @author Laurent Arnal - Initial contribution
81  */
82 @NonNullByDefault
83 @Component(immediate = true)
84 public class SiemensHvacMetadataRegistryImpl implements SiemensHvacMetadataRegistry {
85
86     private final Logger logger = LoggerFactory.getLogger(SiemensHvacMetadataRegistryImpl.class);
87
88     // A map contains data point config read from Api and/or WebPages
89     private Map<String, SiemensHvacMetadata> dptMap = new Hashtable<String, SiemensHvacMetadata>();
90     private @Nullable SiemensHvacMetadata root = null;
91     private @Nullable ArrayList<SiemensHvacMetadataDevice> devices = null;
92
93     private static final String JSON_DIR = OpenHAB.getUserDataFolder() + File.separatorChar + "siemenshvac";
94
95     private @Nullable SiemensHvacThingTypeProvider thingTypeProvider;
96     private @Nullable SiemensHvacChannelTypeProvider channelTypeProvider;
97     private @Nullable SiemensHvacChannelGroupTypeProvider channelGroupTypeProvider;
98     private @Nullable SiemensHvacConfigDescriptionProvider configDescriptionProvider;
99     private @Nullable SiemensHvacConnector hvacConnector;
100     private @Nullable SiemensHvacMetadataUser user;
101     private @Nullable Locale userLocale;
102
103     private final HashMap<String, SiemensHvacMetadataUser> userList;
104
105     public SiemensHvacMetadataRegistryImpl() {
106         userList = new HashMap<String, SiemensHvacMetadataUser>();
107     }
108
109     @Reference
110     protected void setSiemensHvacConnector(SiemensHvacConnector hvacConnector) {
111         this.hvacConnector = hvacConnector;
112     }
113
114     protected void unsetSiemensHvacConnector(SiemensHvacConnector hvacConnector) {
115         this.hvacConnector = null;
116     }
117
118     @Reference
119     protected void setThingTypeProvider(SiemensHvacThingTypeProvider thingTypeProvider) {
120         this.thingTypeProvider = thingTypeProvider;
121     }
122
123     protected void unsetThingTypeProvider(SiemensHvacThingTypeProvider thingTypeProvider) {
124         this.thingTypeProvider = null;
125     }
126
127     @Reference
128     protected void setChannelTypeProvider(SiemensHvacChannelTypeProvider channelTypeProvider) {
129         this.channelTypeProvider = channelTypeProvider;
130     }
131
132     protected void unsetChannelTypeProvider(SiemensHvacChannelTypeProvider channelTypeProvider) {
133         this.channelTypeProvider = null;
134     }
135
136     //
137     @Reference
138     protected void setChannelGroupTypeProvider(SiemensHvacChannelGroupTypeProvider channelGroupTypeProvider) {
139         this.channelGroupTypeProvider = channelGroupTypeProvider;
140     }
141
142     protected void unsetChannelGroupTypeProvider(SiemensHvacChannelGroupTypeProvider channelGroupTypeProvider) {
143         this.channelGroupTypeProvider = null;
144     }
145
146     @Reference
147     protected void setConfigDescriptionProvider(SiemensHvacConfigDescriptionProvider configDescriptionProvider) {
148         this.configDescriptionProvider = configDescriptionProvider;
149     }
150
151     protected void unsetConfigDescriptionProvider(SiemensHvacConfigDescriptionProvider configDescriptionProvider) {
152         this.configDescriptionProvider = null;
153     }
154
155     @Override
156     public @Nullable SiemensHvacConnector getSiemensHvacConnector() {
157         return this.hvacConnector;
158     }
159
160     @Override
161     public @Nullable SiemensHvacChannelTypeProvider getChannelTypeProvider() {
162         return this.channelTypeProvider;
163     }
164
165     @Override
166     public @Nullable ArrayList<SiemensHvacMetadataDevice> getDevices() {
167         return devices;
168     }
169
170     /**
171      * Initializes the type generator.
172      */
173     @Override
174     @Activate
175     public void initialize() {
176     }
177
178     public void initDptMap(@Nullable SiemensHvacMetadata node) {
179         if (node == null) {
180             return;
181         }
182
183         if (node.getClass() == SiemensHvacMetadataMenu.class) {
184             SiemensHvacMetadataMenu mInformation = (SiemensHvacMetadataMenu) node;
185
186             for (SiemensHvacMetadata child : mInformation.getChilds().values()) {
187                 initDptMap(child);
188             }
189         }
190
191         if (!node.getLongDesc().isEmpty()) {
192             dptMap.put("byName" + node.getLongDesc(), node);
193         }
194         if (!node.getShortDesc().isEmpty()) {
195             dptMap.put("byName" + node.getShortDesc(), node);
196         }
197
198         dptMap.put("byId" + node.getId(), node);
199         dptMap.put("bySubId" + node.getSubId(), node);
200
201         if (node.getClass() == SiemensHvacMetadataDataPoint.class) {
202             SiemensHvacMetadataDataPoint dpi = (SiemensHvacMetadataDataPoint) node;
203             dptMap.put("byDptId" + dpi.getDptId(), node);
204         }
205     }
206
207     class ResolveCount {
208         private int resolveCount = 0;
209
210         public ResolveCount(int count) {
211             resolveCount = count;
212         }
213
214         public void decreaseResolveCount() {
215             resolveCount--;
216         }
217
218         public int getResolveCount() {
219             return resolveCount;
220         }
221     }
222
223     public void resolveDetails(int unresolveCountP) {
224         ResolveCount rv = new ResolveCount(unresolveCountP);
225
226         for (String key : dptMap.keySet()) {
227             if (key.indexOf("byId") < 0) {
228                 continue;
229             }
230
231             SiemensHvacMetadata node = dptMap.get(key);
232             if (node != null) {
233                 if (node.getClass() == SiemensHvacMetadataDataPoint.class) {
234                     SiemensHvacMetadataDataPoint dpi = (SiemensHvacMetadataDataPoint) node;
235                     if (!dpi.getDetailsResolved()) {
236                         resolveDptDetails(dpi, rv);
237                     }
238                 }
239             }
240         }
241     }
242
243     public int unresolveCount() {
244         int count = 0;
245         for (String key : dptMap.keySet()) {
246             if (key.indexOf("byId") < 0) {
247                 continue;
248             }
249
250             SiemensHvacMetadata node = dptMap.get(key);
251             if (node != null) {
252                 if (node instanceof SiemensHvacMetadataDataPoint dpi) {
253                     if (!dpi.getDetailsResolved()) {
254                         count++;
255                     }
256                 }
257             }
258
259         }
260
261         return count;
262     }
263
264     @Override
265     public @Nullable SiemensHvacMetadataMenu getRoot() {
266         return (SiemensHvacMetadataMenu) root;
267     }
268
269     @Override
270     public void readMeta() throws SiemensHvacException {
271         ArrayList<SiemensHvacMetadataDevice> lcDevices = devices;
272         SiemensHvacConnector lcHvacConnector = hvacConnector;
273
274         if (root != null) {
275             return;
276         }
277
278         if (lcHvacConnector == null) {
279             logger.debug("SiemensHvacMetadataRegistryImpl:ReadMeta(): lHvacConnector not initialize.");
280             return;
281         }
282
283         readUserInfo();
284
285         SiemensHvacBridgeConfig config = lcHvacConnector.getBridgeConfiguration();
286         if (config == null) {
287             throw new SiemensHvacException("@offline.config-not-init");
288         }
289
290         SiemensHvacMetadataUser lcUser = null;
291
292         String userName = config.userName;
293         if (userList.containsKey(userName)) {
294             lcUser = userList.get(userName);
295         }
296
297         if (lcUser == null) {
298             throw new SiemensHvacException("@offline.user-not-find");
299         }
300
301         Map<String, Locale> map = new HashMap<String, Locale>();
302         map.put("English", Locale.forLanguageTag("en-UK"));
303         map.put("Deutsch", Locale.forLanguageTag("de-DE"));
304         map.put("Francais", Locale.forLanguageTag("fr-FR"));
305         map.put("Italiano", Locale.forLanguageTag("it-IT"));
306         map.put("Nederlands", Locale.forLanguageTag("nl-NL"));
307         map.put("Polski", Locale.forLanguageTag("pl-PL"));
308         map.put("Ceski", Locale.forLanguageTag("cs-CZ"));
309         map.put("Magyar", Locale.forLanguageTag("hu-HU"));
310         map.put("Espagnol", Locale.forLanguageTag("es-ES"));
311         map.put("Dansk", Locale.forLanguageTag("da-DK"));
312         map.put("Svenska", Locale.forLanguageTag("sv-SE"));
313         map.put("Suomi", Locale.forLanguageTag("fi-FI"));
314         map.put("Portugues", Locale.forLanguageTag("pt-PT"));
315         map.put("Russkij", Locale.forLanguageTag("ru-RU"));
316         map.put("Turkce", Locale.forLanguageTag("tr-TR"));
317         map.put("Slovensky", Locale.forLanguageTag("sl-SV"));
318
319         this.user = lcUser;
320         if (map.containsKey(lcUser.getLanguage())) {
321             this.userLocale = map.get(lcUser.getLanguage());
322         } else {
323             this.userLocale = Locale.getDefault();
324         }
325
326         logger.trace("siemensHvac:Initialization():Begin_0001");
327
328         File folder = new File(JSON_DIR);
329
330         if (!folder.exists()) {
331             logger.debug("Creating directory {}", folder);
332             folder.mkdirs();
333         }
334
335         logger.trace("siemensHvac:Initialization():ReadCache");
336         loadMetaDataFromCache();
337
338         // increase the timeout during this phase
339         // because we queued a lot of request
340         // and timeout start to run when request is queued (not executed)
341
342         Instant start = Instant.now();
343         lcHvacConnector.setTimeOut(600);
344
345         logger.trace("siemensHvac:Initialization():ReadDeviceList");
346         readDeviceList();
347
348         if (root == null) {
349             logger.trace("siemensHvac:Initialization():No cache information, root==null, reading metadata from device");
350
351             logger.trace("siemensHvac:Initialization():BeginReadMenu");
352             root = new SiemensHvacMetadataMenu();
353
354             changeLanguage(lcUser, 1);
355             readMetaData(root, -1, false);
356             lcHvacConnector.waitNoNewRequest();
357             lcHvacConnector.waitAllPendingRequest();
358
359             changeLanguage(lcUser, lcUser.getLanguageId());
360             readMetaData(root, -1, true);
361             lcHvacConnector.waitNoNewRequest();
362             lcHvacConnector.waitAllPendingRequest();
363
364             logger.trace("siemensHvac:Initialization():EndReadMenu");
365         }
366
367         if (root != null) {
368             logger.trace("siemensHvac:Initialization():BeginInitDptMap");
369             initDptMap(root);
370             logger.trace("siemensHvac:Initialization():EndInitDptMap");
371         }
372
373         int unresolveCount = unresolveCount();
374
375         while (unresolveCount > 0) {
376             logger.trace("siemensHvac:Initialization():BeginResolveDtpMap {}", unresolveCount);
377             resolveDetails(unresolveCount);
378             lcHvacConnector.waitAllPendingRequest();
379             unresolveCount = unresolveCount();
380         }
381
382         Instant end = Instant.now();
383         lcHvacConnector.setTimeOut(30);
384
385         long elapseTime = Duration.between(start, end).toSeconds();
386         logger.trace("siemensHvac:Initialization():ReadMetadata in {} s", elapseTime);
387
388         logger.trace("siemensHvac:Initialization():SaveCache");
389         saveMetaDataToCache();
390
391         logger.trace("siemensHvac:Initialization():InitThing");
392         getRoot();
393         lcDevices = devices;
394         if (lcDevices != null) {
395             for (SiemensHvacMetadataDevice device : lcDevices) {
396                 generateThingsType(device);
397             }
398         }
399
400         logger.trace("siemensHvac:InitDptMap():end");
401     }
402
403     @Override
404     public @Nullable SiemensHvacMetadataUser getUser() {
405         return user;
406     }
407
408     @Override
409     public @Nullable Locale getUserLocale() {
410         return userLocale;
411     }
412
413     private void generateThingsType(SiemensHvacMetadataDevice device) {
414         SiemensHvacThingTypeProvider lcThingTypeProvider = thingTypeProvider;
415         logger.debug("Generate thing types for device: {} / {}", device.getName(), device.getSerialNr());
416         if (lcThingTypeProvider != null) {
417             ThingTypeUID thingTypeUID = UidUtils.generateThingTypeUID(device);
418             ThingType tt = null;
419
420             tt = lcThingTypeProvider.getInternalThingType(thingTypeUID);
421
422             if (tt == null) {
423                 List<ChannelGroupType> groupTypes = new ArrayList<>();
424
425                 int treeId = device.getTreeId();
426                 if (dptMap.containsKey("byId" + treeId)) {
427                     SiemensHvacMetadataMenu menu = (SiemensHvacMetadataMenu) dptMap.get("byId" + treeId);
428
429                     if (menu != null) {
430                         var childs = menu.getChilds().values();
431                         for (SiemensHvacMetadata child : childs) {
432                             generateThingsType(child, groupTypes, menu);
433                         }
434
435                     }
436
437                 }
438
439                 tt = createThingType(device, groupTypes);
440                 lcThingTypeProvider.addThingType(tt);
441             }
442         }
443     }
444
445     private void generateThingsType(SiemensHvacMetadata child, List<ChannelGroupType> groupTypes,
446             SiemensHvacMetadataMenu menu) {
447         SiemensHvacChannelTypeProvider lcChannelTypeProvider = channelTypeProvider;
448         SiemensHvacChannelGroupTypeProvider lcChannelGroupTypeProvider = channelGroupTypeProvider;
449
450         if (child instanceof SiemensHvacMetadataMenu subMenu) {
451             List<ChannelDefinition> channelDefinitions = new ArrayList<>();
452
453             for (SiemensHvacMetadata childDt : subMenu.getChilds().values()) {
454
455                 try {
456                     if (childDt instanceof SiemensHvacMetadataMenu) {
457                         generateThingsType(childDt, groupTypes, menu);
458                     }
459                     if (childDt instanceof SiemensHvacMetadataDataPoint metadataDataPoint) {
460                         if (metadataDataPoint.getDptType().isEmpty()) {
461                             continue;
462                         }
463
464                         ChannelTypeUID channelTypeUID = UidUtils.generateChannelTypeUID(metadataDataPoint);
465
466                         ChannelType channelType = null;
467
468                         if (channelTypeProvider != null && lcChannelTypeProvider != null) {
469                             channelType = lcChannelTypeProvider.getInternalChannelType(channelTypeUID);
470                             if (channelType == null) {
471                                 channelType = createChannelType(metadataDataPoint, channelTypeUID);
472                                 lcChannelTypeProvider.addChannelType(channelType);
473                             }
474                         }
475
476                         Map<String, String> props = new Hashtable<String, String>();
477                         props.put("dptId", "" + metadataDataPoint.getDptId());
478                         props.put("id", "" + metadataDataPoint.getId());
479                         props.put("subId", "" + metadataDataPoint.getSubId());
480                         props.put("groupdId", "" + metadataDataPoint.getGroupId());
481
482                         String id = metadataDataPoint.getId() + "-"
483                                 + UidUtils.sanetizeId(metadataDataPoint.getShortDesc());
484
485                         if (channelType != null) {
486                             ChannelDefinition channelDef = new ChannelDefinitionBuilder(id, channelType.getUID())
487                                     .withLabel(metadataDataPoint.getShortDesc())
488                                     .withDescription(metadataDataPoint.getLongDesc()).withProperties(props).build();
489
490                             channelDefinitions.add(channelDef);
491                         }
492                     }
493                 } catch (SiemensHvacException ex) {
494                     logger.warn("Unable to create channel for: {}", childDt);
495                 }
496             }
497
498             // generate group
499             ChannelGroupTypeUID groupTypeUID = UidUtils.generateChannelGroupTypeUID(subMenu);
500             ChannelGroupType groupType = null;
501
502             if (lcChannelGroupTypeProvider != null) {
503                 groupType = lcChannelGroupTypeProvider.getInternalChannelGroupType(groupTypeUID);
504
505                 if (groupType == null) {
506                     String groupLabel = subMenu.getShortDesc();
507                     groupType = ChannelGroupTypeBuilder.instance(groupTypeUID, groupLabel)
508                             .withChannelDefinitions(channelDefinitions).withCategory("")
509                             .withDescription(menu.getLongDesc()).build();
510                     lcChannelGroupTypeProvider.addChannelGroupType(groupType);
511                     groupTypes.add(groupType);
512                 }
513             }
514
515         }
516     }
517
518     private ChannelType createChannelType(SiemensHvacMetadataDataPoint dpt, ChannelTypeUID channelTypeUID)
519             throws SiemensHvacException {
520         ChannelType channelType;
521
522         String itemType = getItemType(dpt);
523         String category = getCategory(dpt);
524         String label = itemType;
525         String description = "";
526
527         StateDescriptionFragmentBuilder stateFragment = StateDescriptionFragmentBuilder.create();
528
529         List<StateOption> options = new ArrayList<StateOption>();
530         if (dpt.getDptType().equals(SiemensHvacBindingConstants.DPT_TYPE_ENUM)) {
531             StringBuilder descBuilder = new StringBuilder();
532             descBuilder.append("Enum:");
533             List<SiemensHvacMetadataPointChild> childs = dpt.getChild();
534             int idx = 0;
535
536             for (SiemensHvacMetadataPointChild opt : childs) {
537                 StateOption stOpt = new StateOption(opt.getValue(), opt.getText());
538                 options.add(stOpt);
539                 if (idx > 0) {
540                     descBuilder.append("_");
541                 }
542
543                 descBuilder.append(String.format("(%s:%s)", opt.getValue(), opt.getText()));
544                 idx++;
545             }
546             description = descBuilder.toString();
547             label = channelTypeUID.getId();
548         } else if (dpt.getDptType().equals(SiemensHvacBindingConstants.DPT_TYPE_RADIO)) {
549             StringBuilder descBuilder = new StringBuilder();
550             descBuilder.append("Radio:");
551             SiemensHvacMetadataPointChild child = dpt.getChild().get(0);
552
553             if (dpt.getWriteAccess()) {
554                 StateOption stOpt0 = new StateOption("OFF", child.getOpt0());
555                 descBuilder.append(String.format("(%s:%s)", "OFF", child.getOpt0()));
556                 options.add(stOpt0);
557
558                 StateOption stOpt1 = new StateOption("ON", child.getOpt1());
559                 descBuilder.append(String.format("(%s:%s)", "ON", child.getOpt1()));
560                 options.add(stOpt1);
561             } else {
562                 StateOption stOpt0 = new StateOption("CLOSED", child.getOpt0());
563                 descBuilder.append(String.format("(%s:%s)", "OFF", child.getOpt0()));
564                 options.add(stOpt0);
565
566                 StateOption stOpt1 = new StateOption("OPEN", child.getOpt1());
567                 descBuilder.append(String.format("(%s:%s)", "ON", child.getOpt1()));
568                 options.add(stOpt1);
569             }
570
571             description = descBuilder.toString();
572             label = channelTypeUID.getId();
573         } else if (dpt.getDptType().equals(SiemensHvacBindingConstants.DPT_TYPE_NUMERIC)) {
574             BigDecimal min = new BigDecimal(dpt.getMin());
575             BigDecimal max = new BigDecimal(dpt.getMax());
576             BigDecimal step = new BigDecimal(dpt.getResolution());
577
578             stateFragment = stateFragment.withPattern(getStatePattern(dpt)).withMinimum(min).withMaximum(max)
579                     .withStep(step).withReadOnly(false);
580
581             description = channelTypeUID.toString();
582             label = channelTypeUID.getId();
583         } else {
584             stateFragment = stateFragment.withPattern(getStatePattern(dpt)).withReadOnly(!dpt.getWriteAccess());
585         }
586
587         if (!options.isEmpty()) {
588             stateFragment = stateFragment.withOptions(options);
589         }
590
591         boolean isAdvanced = false;
592         if (channelTypeUID.getId().contains("-y")) {
593             isAdvanced = true;
594         }
595         if (channelTypeUID.getId().contains("-k")) {
596             isAdvanced = true;
597         }
598         if (channelTypeUID.getId().contains("histo")) {
599             isAdvanced = true;
600         }
601         if (channelTypeUID.getId().contains("-qx")) {
602             isAdvanced = true;
603         }
604
605         final StateChannelTypeBuilder channelTypeBuilder = ChannelTypeBuilder.state(channelTypeUID, label, itemType)
606                 .withStateDescriptionFragment(stateFragment.build());
607
608         channelType = channelTypeBuilder.isAdvanced(isAdvanced).withDescription(description).withCategory(category)
609                 .build();
610
611         return channelType;
612     }
613
614     /**
615      * Creates the ThingType for the given device.
616      */
617     private ThingType createThingType(SiemensHvacMetadataDevice device, List<ChannelGroupType> groupTypes) {
618         SiemensHvacConfigDescriptionProvider lcConfigDescriptionProvider = configDescriptionProvider;
619         String name = device.getName();
620         String description = device.getName();
621
622         List<String> supportedBridgeTypeUids = new ArrayList<>();
623         supportedBridgeTypeUids.add(SiemensHvacBindingConstants.THING_TYPE_OZW.toString());
624         ThingTypeUID thingTypeUID = UidUtils.generateThingTypeUID(device);
625
626         Map<String, String> properties = new HashMap<>();
627         properties.put(Thing.PROPERTY_VENDOR, SiemensHvacBindingConstants.PROPERTY_VENDOR_NAME);
628         properties.put(Thing.PROPERTY_MODEL_ID, device.getType());
629
630         URI configDescriptionURI = getConfigDescriptionURI(device);
631         if (lcConfigDescriptionProvider != null
632                 && lcConfigDescriptionProvider.getInternalConfigDescription(configDescriptionURI) == null) {
633             generateConfigDescription(device, groupTypes, configDescriptionURI);
634         }
635
636         List<ChannelGroupDefinition> groupDefinitions = new ArrayList<>();
637         for (ChannelGroupType groupType : groupTypes) {
638             String id = groupType.getUID().getId();
639             groupDefinitions.add(new ChannelGroupDefinition(id, groupType.getUID()));
640         }
641
642         return ThingTypeBuilder.instance(thingTypeUID, name).withSupportedBridgeTypeUIDs(supportedBridgeTypeUids)
643                 .withDescription(description).withChannelGroupDefinitions(groupDefinitions).withProperties(properties)
644                 .withRepresentationProperty(Thing.PROPERTY_MODEL_ID).withConfigDescriptionURI(configDescriptionURI)
645                 .withCategory(SiemensHvacBindingConstants.CATEGORY_THING_HVAC).build();
646     }
647
648     private URI getConfigDescriptionURI(SiemensHvacMetadataDevice device) {
649         return URI.create((String.format("%s:%s", SiemensHvacBindingConstants.CONFIG_DESCRIPTION_URI_THING_PREFIX,
650                 UidUtils.generateThingTypeUID(device))));
651     }
652
653     private void generateConfigDescription(SiemensHvacMetadataDevice device, List<ChannelGroupType> groupTypes,
654             URI configDescriptionURI) {
655         SiemensHvacConfigDescriptionProvider lcConfigDescriptionProvider = configDescriptionProvider;
656         List<ConfigDescriptionParameter> parms = new ArrayList<>();
657         List<ConfigDescriptionParameterGroup> groups = new ArrayList<>();
658
659         if (lcConfigDescriptionProvider != null) {
660             lcConfigDescriptionProvider.addConfigDescription(ConfigDescriptionBuilder.create(configDescriptionURI)
661                     .withParameters(parms).withParameterGroups(groups).build());
662         }
663     }
664
665     public String getItemType(SiemensHvacMetadataDataPoint dpt) throws SiemensHvacException {
666         try {
667             TypeConverter tp = ConverterFactory.getConverter(dpt.getDptType());
668             return tp.getItemType(dpt);
669         } catch (ConverterTypeException ex) {
670             throw new SiemensHvacException(String.format("Can't find convertor for type: %s", dpt.getDptType()), ex);
671         }
672     }
673
674     /**
675      * Determines the category for the given Datapoint.
676      */
677     public static String getCategory(SiemensHvacMetadataDataPoint dp) {
678         String dpType = dp.getDptType();
679         String dptUnit = dp.getDptUnit();
680
681         if (dptUnit == null) {
682             return "";
683         } else if (dptUnit.contains("°C")) {
684             return SiemensHvacBindingConstants.CATEGORY_CHANNEL_TEMP;
685         } else if (dptUnit.contains("°F")) {
686             return SiemensHvacBindingConstants.CATEGORY_CHANNEL_TEMP;
687         } else if (dpType.contains(SiemensHvacBindingConstants.DPT_TYPE_DATE_TIME)) {
688             return SiemensHvacBindingConstants.CATEGORY_CHANNEL_TIME;
689         } else if (dpType.contains(SiemensHvacBindingConstants.DPT_TYPE_TIMEOFDAY)) {
690             return SiemensHvacBindingConstants.CATEGORY_CHANNEL_TIME;
691         } else if (dpType.contains(SiemensHvacBindingConstants.DPT_TYPE_ENUM)) {
692             return SiemensHvacBindingConstants.CATEGORY_CHANNEL_SWITCH;
693         } else if (dpType.contains(SiemensHvacBindingConstants.DPT_TYPE_RADIO)) {
694             return SiemensHvacBindingConstants.CATEGORY_CHANNEL_SWITCH;
695         } else if (dpType.contains(SiemensHvacBindingConstants.DPT_TYPE_NUMERIC)) {
696             return SiemensHvacBindingConstants.CATEGORY_CHANNEL_NUMBER;
697         } else {
698             return SiemensHvacBindingConstants.CATEGORY_CHANNEL_CONTROL_HEATING;
699         }
700     }
701
702     /**
703      * Returns the state pattern metadata string with unit for the given Datapoint.
704      */
705     public static String getStatePattern(SiemensHvacMetadataDataPoint dpt) {
706         String unit = dpt.getDptUnit();
707
708         if ("%".equals(unit)) {
709             return "%d %%";
710         }
711
712         int digits = 0;
713         if (dpt.getDptType().equals(SiemensHvacBindingConstants.DPT_TYPE_NUMERIC)) {
714             String digitSt = dpt.getDecimalDigits();
715             if (digitSt != null && !"".equals(digitSt)) {
716                 digits = Integer.parseInt(digitSt);
717             }
718         }
719
720         if (unit != null && !unit.isEmpty()) {
721             return String.format("%s %s", "%." + digits + "f", "%unit%");
722         } else {
723             return String.format("%s", "%." + digits + "f");
724         }
725     }
726
727     public void readUserInfo() throws SiemensHvacException {
728         SiemensHvacConnector lcHvacConnector = hvacConnector;
729         String request = "main.app?section=settings&subsection=user";
730
731         if (lcHvacConnector != null) {
732             String response = lcHvacConnector.doBasicRequest(request);
733
734             if (response != null) {
735                 String st = response;
736                 st = st.replace("\n", "");
737
738                 Pattern pattern1 = Pattern.compile("table class=\\\"user_table\\\".*?>(.*?)<\\/table>");
739                 Matcher matcher1 = pattern1.matcher(st);
740
741                 if (matcher1.find()) {
742                     String userTable = matcher1.group(1);
743
744                     Pattern pattern2 = Pattern.compile("<tr.*?>(.*?)<\\/tr>");
745                     Matcher matcher2 = pattern2.matcher(userTable);
746
747                     int idx = 0;
748                     while (matcher2.find()) {
749                         String line = matcher2.group(1);
750
751                         if (idx > 0) {
752                             Pattern pattern3 = Pattern.compile("<td(.*?)>(.*?)<\\/td>");
753                             Matcher matcher3 = pattern3.matcher(line);
754
755                             int idxCell = 0;
756                             String userName = "";
757                             String userEdit = "";
758                             String userId = "";
759                             while (matcher3.find()) {
760                                 String cell = matcher3.group(2);
761                                 String header = matcher3.group(1);
762
763                                 if (idxCell == 0) {
764                                     userName = cell;
765                                 } else if (idxCell == 5) {
766                                     userEdit = header;
767                                 }
768                                 idxCell++;
769                             }
770
771                             if ("".equals(userName)) {
772                                 continue;
773                             }
774
775                             Pattern pattern4 = Pattern.compile("userid=(.+?)");
776                             Matcher matcher4 = pattern4.matcher(userEdit);
777
778                             SiemensHvacMetadataUser user = new SiemensHvacMetadataUser();
779                             user.setName(userName);
780
781                             if (matcher4.find()) {
782                                 userId = matcher4.group(1);
783                                 user.setId(Integer.parseInt(userId));
784                             } else {
785                                 userId = null;
786                                 user.setId(-1);
787                             }
788
789                             request = "main.app?section=settings&subsection=user&action=modify";
790                             if (userId != null) {
791                                 request = request + "&userid=" + userId;
792                             }
793                             response = lcHvacConnector.doBasicRequest(request);
794
795                             Pattern pattern5 = Pattern.compile("<select name=\\\"language\\\".*>((.*|\\n)*?)</select>",
796                                     Pattern.MULTILINE);
797                             Matcher matcher5 = pattern5.matcher(response);
798
799                             if (matcher5.find()) {
800                                 String optionsList = matcher5.group(1);
801
802                                 Pattern pattern6 = java.util.regex.Pattern
803                                         .compile("<option value=\\\"([^ ]*)\\\"(.*)>(.*)</option>", Pattern.MULTILINE);
804                                 Matcher matcher6 = pattern6.matcher(optionsList);
805
806                                 while (matcher6.find()) {
807                                     String id = matcher6.group(1);
808                                     String opt = matcher6.group(2);
809                                     String lang = matcher6.group(3);
810
811                                     if (opt.indexOf("selected") >= 0) {
812                                         user.setLanguage(lang);
813                                         user.setLanguageId(Integer.parseInt(id));
814                                     }
815                                 }
816                             }
817
818                             userList.put(userName, user);
819                         }
820
821                         idx++;
822
823                     }
824                 }
825             }
826         }
827     }
828
829     public void changeLanguage(SiemensHvacMetadataUser user, int lang) {
830         try {
831             SiemensHvacConnector lcHvacConnector = hvacConnector;
832             String request = "main.app?section=settings&subsection=user&action=modify";
833             if (user.getId() != -1) {
834                 request = request + "&userid=" + user.getId();
835             }
836             request = request + "&language=" + lang + "&submit=OK";
837             if (lcHvacConnector != null) {
838                 lcHvacConnector.doBasicRequest(request);
839                 lcHvacConnector.resetSessionId(null, false);
840                 lcHvacConnector.resetSessionId(null, true);
841             }
842
843         } catch (
844
845         Exception e) {
846             logger.error("siemensHvac:ResolveDpt:Error during dp reading: {}", e.getLocalizedMessage());
847             // Reset sessionId so we redone _auth on error
848         }
849     }
850
851     public void readDeviceList() {
852         try {
853             SiemensHvacConnector lcHvacConnector = hvacConnector;
854             ArrayList<SiemensHvacMetadataDevice> lcDevices = devices;
855
856             lcDevices = new ArrayList<SiemensHvacMetadataDevice>();
857             devices = lcDevices;
858             String request = "api/devicelist/list.json?";
859
860             JsonObject response = null;
861             if (lcHvacConnector != null) {
862                 response = lcHvacConnector.doRequest(request);
863             }
864             JsonArray devicesList = null;
865             if (response != null) {
866                 devicesList = response.getAsJsonArray("Devices");
867             }
868
869             if (devicesList == null) {
870                 return;
871             }
872
873             for (JsonElement device : devicesList) {
874
875                 JsonObject obj = (JsonObject) device;
876                 String name = "";
877                 String addr = "";
878                 String type = "";
879                 String serialNr = "";
880                 String treeDate = "";
881                 String treeTime = "";
882                 boolean treeGenerated = false;
883
884                 if (obj.has("Name")) {
885                     name = obj.get("Name").getAsString();
886                 }
887
888                 if (obj.has("Addr")) {
889                     addr = obj.get("Addr").getAsString();
890                 }
891
892                 if (obj.has("Type")) {
893                     type = obj.get("Type").getAsString();
894                 }
895
896                 if (obj.has("SerialNr")) {
897                     serialNr = obj.get("SerialNr").getAsString();
898                 }
899
900                 if (obj.has("TreeDate")) {
901                     treeDate = obj.get("TreeDate").getAsString();
902                 }
903
904                 if (obj.has("TreeTime")) {
905                     treeTime = obj.get("TreeTime").getAsString();
906                 }
907
908                 if (obj.has("TreeGenerated")) {
909                     treeGenerated = obj.get("TreeGenerated").getAsBoolean();
910                 }
911
912                 SiemensHvacMetadataDevice deviceObj = new SiemensHvacMetadataDevice();
913                 deviceObj.setName(name);
914                 deviceObj.setAddr(addr);
915                 deviceObj.setSerialNr(serialNr);
916                 deviceObj.setType(type);
917                 deviceObj.setTreeDate(treeDate);
918                 deviceObj.setTreeTime(treeTime);
919                 deviceObj.setTreeGenerated(treeGenerated);
920
921                 String request2 = "api/menutree/device_root.json?TreeName=Web&SerialNumber=" + serialNr;
922                 if (lcHvacConnector != null) {
923                     JsonObject response2 = lcHvacConnector.doRequest(request2);
924
925                     if (response2 != null && response2.has("TreeItem")) {
926                         JsonObject tree = response2.getAsJsonObject("TreeItem");
927                         if (tree.has("Id")) {
928                             int treeId = tree.get("Id").getAsInt();
929                             deviceObj.setTreeId(treeId);
930                         }
931                     }
932                 }
933
934                 lcDevices.add(deviceObj);
935             }
936
937         } catch (Exception e) {
938             logger.error("siemensHvac:ResolveDpt:Error during dp reading: {}", e.getLocalizedMessage());
939             // Reset sessionId so we redone _auth on error
940         }
941     }
942
943     public void readMetaData(@Nullable SiemensHvacMetadata parent, int id, boolean localized) {
944         SiemensHvacConnector lcHvacConnector = hvacConnector;
945         String request = "api/menutree/list.json?";
946         if (id != -1) {
947             request = request + "&Id=" + id;
948         }
949
950         if (lcHvacConnector != null) {
951             lcHvacConnector.doRequest(request, new SiemensHvacCallback() {
952
953                 @Override
954                 public void execute(URI uri, int status, @Nullable Object response) {
955                     logger.debug("response for {}, status {}:", uri, status);
956                     if (response instanceof JsonObject jsonResponse) {
957                         decodeMetaDataResult(jsonResponse, parent, id, localized);
958                     } else {
959                         logger.debug("error status {}: {}", uri, status);
960                     }
961                 }
962             });
963         }
964     }
965
966     public void decodeMetaDataResult(JsonObject resultObj, @Nullable SiemensHvacMetadata parent, int id,
967             boolean localized) {
968         SiemensHvacConnector lcHvacConnector = hvacConnector;
969         if (resultObj.has("MenuItems")) {
970             if (parent != null) {
971                 logger.debug("Decode menuItem for: {}", parent.getShortDesc());
972             }
973             SiemensHvacMetadata childNode;
974             JsonArray menuItems = resultObj.getAsJsonArray("MenuItems");
975
976             for (JsonElement child : menuItems) {
977                 JsonObject menuItem = child.getAsJsonObject();
978
979                 int itemId = -1;
980                 if (menuItem.has("Id")) {
981                     itemId = menuItem.get("Id").getAsInt();
982                 }
983
984                 SiemensHvacMetadataMenu menu = (SiemensHvacMetadataMenu) parent;
985
986                 if (menu.hasChild(itemId)) {
987                     childNode = menu.getChild(itemId);
988                 } else {
989                     childNode = new SiemensHvacMetadataMenu();
990                     childNode.setId(itemId);
991                     childNode.setParent(parent);
992
993                     if (parent != null) {
994                         menu.addChild(childNode);
995                     }
996                 }
997
998                 if (menuItem.has("Text")) {
999                     JsonObject descObj = menuItem.getAsJsonObject("Text");
1000
1001                     int catId = -1;
1002                     int groupId = -1;
1003                     int subItemId = -1;
1004                     String longDesc = "";
1005                     String shortDesc = "";
1006
1007                     if (descObj.has("CatId")) {
1008                         catId = descObj.get("CatId").getAsInt();
1009                     }
1010                     if (descObj.has("GroupId")) {
1011                         groupId = descObj.get("GroupId").getAsInt();
1012                     }
1013                     if (descObj.has("Id")) {
1014                         subItemId = descObj.get("Id").getAsInt();
1015                     }
1016
1017                     if (descObj.has("Long")) {
1018                         longDesc = descObj.get("Long").getAsString();
1019                     }
1020                     if (descObj.has("Short")) {
1021                         shortDesc = descObj.get("Short").getAsString();
1022                     }
1023
1024                     childNode.setSubId(subItemId);
1025                     childNode.setCatId(catId);
1026                     childNode.setGroupId(groupId);
1027                     if (!localized) {
1028                         childNode.setShortDescEn(shortDesc);
1029                         childNode.setLongDescEn(longDesc);
1030                     } else {
1031                         childNode.setShortDesc(shortDesc);
1032                         childNode.setLongDesc(longDesc);
1033                     }
1034
1035                     readMetaData(childNode, itemId, localized);
1036                 }
1037
1038             }
1039         }
1040         if (resultObj.has("DatapointItems"))
1041
1042         {
1043             if (parent != null) {
1044                 logger.debug("Decode dp for: {}", parent.getShortDesc());
1045             }
1046
1047             SiemensHvacMetadata childNode;
1048             JsonArray dptItems = resultObj.getAsJsonArray("DatapointItems");
1049
1050             Map<String, SiemensHvacMetadataDataPoint> idMap = new Hashtable<String, SiemensHvacMetadataDataPoint>();
1051
1052             for (JsonElement child : dptItems) {
1053                 JsonObject dptItem = child.getAsJsonObject();
1054
1055                 int nodeId = -1;
1056                 int dpSubKey = -1;
1057                 boolean hasWriteAccess = false;
1058                 String address = "";
1059
1060                 if (dptItem.has("Id")) {
1061                     nodeId = dptItem.get("Id").getAsInt();
1062                 }
1063
1064                 SiemensHvacMetadataMenu menu = (SiemensHvacMetadataMenu) parent;
1065
1066                 if (menu.hasChild(nodeId)) {
1067                     childNode = menu.getChild(nodeId);
1068                 } else {
1069                     childNode = new SiemensHvacMetadataDataPoint();
1070                     childNode.setId(nodeId);
1071                     childNode.setParent(parent);
1072
1073                     menu.addChild(childNode);
1074                 }
1075
1076                 if (dptItem.has("Address")) {
1077                     address = dptItem.get("Address").getAsString();
1078                 }
1079                 if (dptItem.has("DpSubKey")) {
1080                     dpSubKey = dptItem.get("DpSubKey").getAsInt();
1081                 }
1082                 if (dptItem.has("WriteAccess")) {
1083                     hasWriteAccess = dptItem.get("WriteAccess").getAsBoolean();
1084                 }
1085
1086                 SiemensHvacMetadataDataPoint dptChild = (SiemensHvacMetadataDataPoint) childNode;
1087
1088                 dptChild.setId(nodeId);
1089                 dptChild.setAddress(address);
1090                 dptChild.setDptSubKey(dpSubKey);
1091                 dptChild.setWriteAccess(hasWriteAccess);
1092
1093                 idMap.put("" + nodeId, dptChild);
1094
1095                 if (dptItem.has("Text")) {
1096                     JsonObject descObj = dptItem.getAsJsonObject("Text");
1097
1098                     int catId = -1;
1099                     int groupId = -1;
1100                     int subItemId = -1;
1101                     String longDesc = "";
1102                     String shortDesc = "";
1103
1104                     if (descObj.has("CatId")) {
1105                         catId = descObj.get("CatId").getAsInt();
1106                     }
1107                     if (descObj.has("GroupId")) {
1108                         groupId = descObj.get("GroupId").getAsInt();
1109                     }
1110                     if (descObj.has("Id")) {
1111                         subItemId = descObj.get("Id").getAsInt();
1112                     }
1113                     if (descObj.has("Long")) {
1114                         longDesc = descObj.get("Long").getAsString();
1115                     }
1116                     if (descObj.has("Short")) {
1117                         shortDesc = descObj.get("Short").getAsString();
1118                     }
1119
1120                     childNode.setSubId(subItemId);
1121                     childNode.setCatId(catId);
1122                     childNode.setGroupId(groupId);
1123
1124                     if (!localized) {
1125                         childNode.setShortDescEn(shortDesc);
1126                         childNode.setLongDescEn(longDesc);
1127                     } else {
1128                         childNode.setShortDesc(shortDesc);
1129                         childNode.setLongDesc(longDesc);
1130                     }
1131                 }
1132
1133             }
1134
1135             String request2 = "main.app?section=popcard&idtype=4";
1136             if (id != -1) {
1137                 request2 = request2 + "&id=" + id;
1138             }
1139
1140             if (lcHvacConnector != null) {
1141                 lcHvacConnector.doRequest(request2, new SiemensHvacCallback() {
1142
1143                     @Override
1144                     public void execute(URI uri, int status, @Nullable Object response) {
1145                         if (response != null) {
1146                             String st = (String) response;
1147                             st = st.replace("\n", "");
1148
1149                             Pattern pattern = Pattern
1150                                     .compile("td class=\\\"dp_linenumber\\\".*?>(.*?)<\\/td>.+?(?=id)id=\"dp(.+?)\"");
1151                             Matcher matcher = pattern.matcher(st);
1152
1153                             while (matcher.find()) {
1154                                 String id = matcher.group(2);
1155                                 String dptId = matcher.group(1);
1156
1157                                 if (id != null && dptId != null && !id.isEmpty() && !dptId.isEmpty()) {
1158                                     if (idMap.containsKey(id)) {
1159                                         SiemensHvacMetadataDataPoint child = idMap.get(id);
1160                                         if (child != null) {
1161                                             child.setDptId(dptId);
1162                                         }
1163                                     }
1164
1165                                 }
1166                             }
1167                         }
1168                     }
1169                 });
1170             }
1171
1172         }
1173     }
1174
1175     @Override
1176     public @Nullable SiemensHvacMetadata getDptMap(@Nullable String key) {
1177         if (key == null) {
1178             return null;
1179         }
1180
1181         if (dptMap.containsKey("byMenu" + key)) {
1182             return dptMap.get("byMenu" + key);
1183         }
1184         if (dptMap.containsKey("byName" + key)) {
1185             return dptMap.get("byName" + key);
1186         }
1187         if (dptMap.containsKey("byDptId" + key)) {
1188             return dptMap.get("byDptId" + key);
1189         }
1190         if (dptMap.containsKey("byId" + key)) {
1191             return dptMap.get("byId" + key);
1192         }
1193
1194         return null;
1195     }
1196
1197     public void loadMetaDataFromCache() {
1198         SiemensHvacConnector lcHvacConnector = hvacConnector;
1199         File file = null;
1200
1201         try {
1202             file = new File(JSON_DIR + File.separator + "siemens.json");
1203
1204             if (!file.exists()) {
1205                 return;
1206             }
1207
1208             byte[] bytes = Files.readAllBytes(file.toPath());
1209             String js = new String(bytes, StandardCharsets.UTF_8);
1210
1211             if (lcHvacConnector != null) {
1212                 root = lcHvacConnector.getGsonWithAdapter().fromJson(js, SiemensHvacMetadataMenu.class);
1213             }
1214         } catch (IOException ioe) {
1215             logger.warn("Couldn't read Siemens MetaData information from file '{}'.", file.getAbsolutePath());
1216
1217         }
1218     }
1219
1220     public void saveMetaDataToCache() {
1221         SiemensHvacConnector lcHvacConnector = hvacConnector;
1222         File file = null;
1223
1224         try {
1225             file = new File(JSON_DIR + File.separator + "siemens.json");
1226
1227             if (!file.exists()) {
1228                 file.getParentFile().mkdirs();
1229                 file.createNewFile();
1230             }
1231
1232             try (FileOutputStream os = new FileOutputStream(file)) {
1233                 if (lcHvacConnector != null) {
1234                     String js = lcHvacConnector.getGsonWithAdapter().toJson(root);
1235
1236                     byte[] bt = js.getBytes();
1237                     os.write(bt);
1238                     os.flush();
1239                 }
1240             }
1241
1242         } catch (IOException ioe) {
1243             logger.warn("Couldn't write Siemens MetaData information to file '{}'.", file.getAbsolutePath());
1244
1245         }
1246     }
1247
1248     public void resolveDptDetails(SiemensHvacMetadataDataPoint dpt, ResolveCount rv) {
1249         SiemensHvacConnector lcHvacConnector = hvacConnector;
1250         if (dpt.getDetailsResolved()) {
1251             return;
1252         }
1253
1254         String request = "api/menutree/datapoint_desc.json?Id=" + dpt.getId();
1255         if (lcHvacConnector != null) {
1256             lcHvacConnector.doRequest(request, new SiemensHvacCallback() {
1257
1258                 @Override
1259                 public void execute(URI uri, int status, @Nullable Object response) {
1260                     if (response instanceof JsonObject) {
1261                         rv.decreaseResolveCount();
1262                         logger.debug("siemensHvac:Initialization():ToResolve() {}", rv.getResolveCount());
1263                         dpt.resolveDptDetails((JsonObject) response);
1264                     } else {
1265                         logger.debug("Invalid response from Siemens gateway, result is not a JsonObject");
1266                     }
1267                 }
1268             });
1269         }
1270     }
1271
1272     @Override
1273     public void invalidate() {
1274         root = null;
1275         SiemensHvacConnector lcHavConnector = hvacConnector;
1276         SiemensHvacChannelGroupTypeProvider lcChannelGroupTypeProvider = channelGroupTypeProvider;
1277         SiemensHvacThingTypeProvider lcThingTypeProvider = thingTypeProvider;
1278         SiemensHvacChannelTypeProvider lcChannelTypeProvider = channelTypeProvider;
1279         SiemensHvacConfigDescriptionProvider lcConfigDescriptionProvider = configDescriptionProvider;
1280
1281         if (lcHavConnector != null) {
1282             lcHavConnector.invalidate();
1283         }
1284
1285         if (lcChannelGroupTypeProvider != null) {
1286             lcChannelGroupTypeProvider.invalidate();
1287         }
1288
1289         if (lcThingTypeProvider != null) {
1290             lcThingTypeProvider.invalidate();
1291         }
1292
1293         if (lcChannelTypeProvider != null) {
1294             lcChannelTypeProvider.invalidate();
1295         }
1296
1297         if (lcConfigDescriptionProvider != null) {
1298             lcConfigDescriptionProvider.invalidate();
1299         }
1300     }
1301 }