]> git.basschouten.com Git - openhab-addons.git/blob
6ce53c586c0c7bfc2fe0e703e619da4c9f235190
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 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.onewire.internal.handler;
14
15 import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
16
17 import java.util.Arrays;
18 import java.util.Collections;
19 import java.util.HashMap;
20 import java.util.HashSet;
21 import java.util.Map;
22 import java.util.Set;
23 import java.util.stream.Collectors;
24 import java.util.stream.Stream;
25
26 import org.eclipse.jdt.annotation.NonNullByDefault;
27 import org.openhab.binding.onewire.internal.DS2438Configuration;
28 import org.openhab.binding.onewire.internal.OwDynamicStateDescriptionProvider;
29 import org.openhab.binding.onewire.internal.OwException;
30 import org.openhab.binding.onewire.internal.SensorId;
31 import org.openhab.binding.onewire.internal.config.AMSHandlerConfiguration;
32 import org.openhab.binding.onewire.internal.device.AbstractOwDevice;
33 import org.openhab.binding.onewire.internal.device.DS18x20;
34 import org.openhab.binding.onewire.internal.device.DS2406_DS2413;
35 import org.openhab.binding.onewire.internal.device.DS2438;
36 import org.openhab.binding.onewire.internal.device.DS2438.LightSensorType;
37 import org.openhab.binding.onewire.internal.device.OwChannelConfig;
38 import org.openhab.binding.onewire.internal.device.OwSensorType;
39 import org.openhab.core.config.core.Configuration;
40 import org.openhab.core.thing.Thing;
41 import org.openhab.core.thing.ThingStatus;
42 import org.openhab.core.thing.ThingStatusDetail;
43 import org.openhab.core.thing.ThingTypeUID;
44 import org.openhab.core.thing.binding.builder.ThingBuilder;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47
48 /**
49  * The {@link AdvancedMultisensorThingHandler} is responsible for handling DS2438 based multisensors (modules)
50  *
51  * @author Jan N. Klug - Initial contribution
52  */
53 @NonNullByDefault
54 public class AdvancedMultisensorThingHandler extends OwBaseThingHandler {
55     public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = new HashSet<>(
56             Arrays.asList(THING_TYPE_AMS, THING_TYPE_BMS));
57     public static final Set<OwSensorType> SUPPORTED_SENSOR_TYPES = Collections
58             .unmodifiableSet(Stream.of(OwSensorType.AMS, OwSensorType.AMS_S, OwSensorType.BMS, OwSensorType.BMS_S)
59                     .collect(Collectors.toSet()));
60
61     private static final String PROPERTY_DS18B20 = "ds18b20";
62     private static final String PROPERTY_DS2413 = "ds2413";
63     private static final String PROPERTY_DS2438 = "ds2438";
64     private static final Set<String> REQUIRED_PROPERTIES_AMS = Collections.unmodifiableSet(
65             Stream.of(PROPERTY_HW_REVISION, PROPERTY_PROD_DATE, PROPERTY_DS18B20, PROPERTY_DS2438, PROPERTY_DS2413)
66                     .collect(Collectors.toSet()));
67     private static final Set<String> REQUIRED_PROPERTIES_BMS = Collections.unmodifiableSet(
68             Stream.of(PROPERTY_HW_REVISION, PROPERTY_PROD_DATE, PROPERTY_DS18B20).collect(Collectors.toSet()));
69
70     private final Logger logger = LoggerFactory.getLogger(AdvancedMultisensorThingHandler.class);
71
72     private final ThingTypeUID thingType = this.thing.getThingTypeUID();
73     private int hwRevision = 0;
74
75     private int digitalRefreshInterval = 10 * 1000;
76     private long digitalLastRefresh = 0;
77
78     public AdvancedMultisensorThingHandler(Thing thing,
79             OwDynamicStateDescriptionProvider dynamicStateDescriptionProvider) {
80         super(thing, dynamicStateDescriptionProvider, SUPPORTED_SENSOR_TYPES,
81                 getRequiredProperties(thing.getThingTypeUID()));
82     }
83
84     @Override
85     public void initialize() {
86         AMSHandlerConfiguration configuration = getConfig().as(AMSHandlerConfiguration.class);
87         Map<String, String> properties = editProperties();
88
89         if (!super.configureThingHandler()) {
90             return;
91         }
92
93         hwRevision = Integer.valueOf(properties.getOrDefault(PROPERTY_HW_REVISION, "0"));
94
95         try {
96             sensors.add(new DS2438(sensorId, this));
97             sensors.add(new DS18x20(new SensorId(properties.get(PROPERTY_DS18B20)), this));
98             if (THING_TYPE_AMS.equals(thingType)) {
99                 sensors.add(new DS2438(new SensorId(properties.get(PROPERTY_DS2438)), this));
100                 sensors.add(new DS2406_DS2413(new SensorId(properties.get(PROPERTY_DS2413)), this));
101                 digitalRefreshInterval = configuration.digitalRefresh * 1000;
102                 digitalLastRefresh = 0;
103             }
104         } catch (IllegalArgumentException e) {
105             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "properties invalid");
106         }
107         scheduler.execute(() -> {
108             configureThingChannels();
109         });
110     }
111
112     @Override
113     public void refresh(OwserverBridgeHandler bridgeHandler, long now) {
114         try {
115             if ((now >= (digitalLastRefresh + digitalRefreshInterval)) && (thingType.equals(THING_TYPE_AMS))) {
116                 logger.trace("refreshing digital {}", this.thing.getUID());
117
118                 Boolean forcedRefresh = digitalLastRefresh == 0;
119                 digitalLastRefresh = now;
120
121                 if (!sensors.get(3).checkPresence(bridgeHandler)) {
122                     return;
123                 }
124
125                 sensors.get(3).refresh(bridgeHandler, forcedRefresh);
126             }
127
128             if (now >= (lastRefresh + refreshInterval)) {
129                 if (!sensors.get(0).checkPresence(bridgeHandler)) {
130                     return;
131                 }
132
133                 logger.trace("refreshing analog {}", this.thing.getUID());
134
135                 Boolean forcedRefresh = lastRefresh == 0;
136                 lastRefresh = now;
137
138                 if (thingType.equals(THING_TYPE_AMS)) {
139                     for (int i = 0; i < sensors.size() - 1; i++) {
140                         sensors.get(i).refresh(bridgeHandler, forcedRefresh);
141                     }
142                 } else {
143                     for (int i = 0; i < sensors.size(); i++) {
144                         sensors.get(i).refresh(bridgeHandler, forcedRefresh);
145                     }
146                 }
147             }
148         } catch (OwException e) {
149             logger.debug("{}: refresh exception '{}'", this.thing.getUID(), e.getMessage());
150             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "refresh exception");
151         }
152     }
153
154     @Override
155     protected void configureThingChannels() {
156         Configuration configuration = getConfig();
157         ThingBuilder thingBuilder = editThing();
158
159         // delete unwanted channels
160         Set<String> existingChannelIds = thing.getChannels().stream().map(channel -> channel.getUID().getId())
161                 .collect(Collectors.toSet());
162         Set<String> wantedChannelIds = SENSOR_TYPE_CHANNEL_MAP.get(sensorType).stream()
163                 .map(channelConfig -> channelConfig.channelId).collect(Collectors.toSet());
164         wantedChannelIds.add(CHANNEL_TEMPERATURE);
165         wantedChannelIds.add(CHANNEL_HUMIDITY);
166         existingChannelIds.stream().filter(channelId -> !wantedChannelIds.contains(channelId))
167                 .forEach(channelId -> removeChannelIfExisting(thingBuilder, channelId));
168
169         // add or update wanted channels
170         SENSOR_TYPE_CHANNEL_MAP.get(sensorType).stream().forEach(channelConfig -> {
171             addChannelIfMissingAndEnable(thingBuilder, channelConfig);
172         });
173
174         // temperature channel
175         if (configuration.containsKey(CONFIG_TEMPERATURESENSOR)
176                 && configuration.get(CONFIG_TEMPERATURESENSOR).equals("DS18B20")) {
177             addChannelIfMissingAndEnable(thingBuilder,
178                     new OwChannelConfig(CHANNEL_TEMPERATURE, CHANNEL_TYPE_UID_TEMPERATURE_POR_RES), 1);
179         } else {
180             addChannelIfMissingAndEnable(thingBuilder,
181                     new OwChannelConfig(CHANNEL_TEMPERATURE, CHANNEL_TYPE_UID_TEMPERATURE));
182         }
183
184         // humidity channel
185
186         addChannelIfMissingAndEnable(thingBuilder, new OwChannelConfig(CHANNEL_HUMIDITY, CHANNEL_TYPE_UID_HUMIDITY),
187                 new Configuration(new HashMap<String, Object>() {
188                     private static final long serialVersionUID = 1L;
189                     {
190                         put(CONFIG_HUMIDITY, "/HIH4000/humidity");
191                     }
192                 }));
193
194         // configure light channel
195         if (sensorType == OwSensorType.AMS_S || sensorType == OwSensorType.BMS_S) {
196             if (hwRevision <= 13) {
197                 ((DS2438) sensors.get(0)).setLightSensorType(LightSensorType.ELABNET_V1);
198             } else {
199                 ((DS2438) sensors.get(0)).setLightSensorType(LightSensorType.ELABNET_V2);
200             }
201         }
202
203         updateThing(thingBuilder.build());
204
205         try {
206             for (AbstractOwDevice sensor : sensors) {
207                 sensor.configureChannels();
208             }
209         } catch (OwException e) {
210             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
211             return;
212         }
213
214         validConfig = true;
215         updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.NONE);
216     }
217
218     @Override
219     public void updateSensorProperties(OwserverBridgeHandler bridgeHandler) throws OwException {
220         Map<String, String> properties = editProperties();
221         DS2438Configuration ds2438configuration = new DS2438Configuration(bridgeHandler, sensorId);
222
223         sensorType = DS2438Configuration.getMultisensorType(ds2438configuration.getSensorSubType(),
224                 ds2438configuration.getAssociatedSensorTypes());
225
226         properties.put(PROPERTY_MODELID, sensorType.toString());
227         properties.put(PROPERTY_VENDOR, ds2438configuration.getVendor());
228
229         properties.put(PROPERTY_PROD_DATE, ds2438configuration.getProductionDate());
230         properties.put(PROPERTY_HW_REVISION, ds2438configuration.getHardwareRevision());
231
232         switch (sensorType) {
233             case BMS:
234             case BMS_S:
235                 properties.put(PROPERTY_DS18B20,
236                         ds2438configuration.getAssociatedSensorIds(OwSensorType.DS18B20).get(0).getFullPath());
237                 break;
238             case AMS:
239             case AMS_S:
240                 properties.put(PROPERTY_DS18B20,
241                         ds2438configuration.getAssociatedSensorIds(OwSensorType.DS18B20).get(0).getFullPath());
242                 properties.put(PROPERTY_DS2413,
243                         ds2438configuration.getAssociatedSensorIds(OwSensorType.DS2413).get(0).getFullPath());
244                 properties.put(PROPERTY_DS2438,
245                         ds2438configuration.getAssociatedSensorIds(OwSensorType.MS_TV).get(0).getFullPath());
246
247                 break;
248             default:
249                 throw new OwException("sensorType " + sensorType.toString() + " not supported by this thing handler");
250         }
251
252         updateProperties(properties);
253     }
254
255     /**
256      * used to determine the correct set of required properties
257      *
258      * @param thingType
259      * @return
260      */
261     private static Set<String> getRequiredProperties(ThingTypeUID thingType) {
262         if (THING_TYPE_AMS.equals(thingType)) {
263             return REQUIRED_PROPERTIES_AMS;
264         } else {
265             return REQUIRED_PROPERTIES_BMS;
266         }
267     }
268 }