2 * Copyright (c) 2010-2020 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.onewire.internal.handler;
15 import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
17 import java.util.Arrays;
18 import java.util.Collections;
19 import java.util.HashMap;
20 import java.util.HashSet;
23 import java.util.stream.Collectors;
24 import java.util.stream.Stream;
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;
49 * The {@link AdvancedMultisensorThingHandler} is responsible for handling DS2438 based multisensors (modules)
51 * @author Jan N. Klug - Initial contribution
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()));
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()));
70 private final Logger logger = LoggerFactory.getLogger(AdvancedMultisensorThingHandler.class);
72 private final ThingTypeUID thingType = this.thing.getThingTypeUID();
73 private int hwRevision = 0;
75 private int digitalRefreshInterval = 10 * 1000;
76 private long digitalLastRefresh = 0;
78 public AdvancedMultisensorThingHandler(Thing thing,
79 OwDynamicStateDescriptionProvider dynamicStateDescriptionProvider) {
80 super(thing, dynamicStateDescriptionProvider, SUPPORTED_SENSOR_TYPES,
81 getRequiredProperties(thing.getThingTypeUID()));
85 public void initialize() {
86 AMSHandlerConfiguration configuration = getConfig().as(AMSHandlerConfiguration.class);
87 Map<String, String> properties = editProperties();
89 if (!super.configureThingHandler()) {
93 hwRevision = Integer.valueOf(properties.get(PROPERTY_HW_REVISION));
95 sensors.add(new DS2438(sensorId, this));
96 sensors.add(new DS18x20(new SensorId(properties.get(PROPERTY_DS18B20)), this));
97 if (THING_TYPE_AMS.equals(thingType)) {
98 sensors.add(new DS2438(new SensorId(properties.get(PROPERTY_DS2438)), this));
99 sensors.add(new DS2406_DS2413(new SensorId(properties.get(PROPERTY_DS2413)), this));
100 digitalRefreshInterval = configuration.digitalRefresh * 1000;
101 digitalLastRefresh = 0;
104 scheduler.execute(() -> {
105 configureThingChannels();
110 public void refresh(OwserverBridgeHandler bridgeHandler, long now) {
112 if ((now >= (digitalLastRefresh + digitalRefreshInterval)) && (thingType.equals(THING_TYPE_AMS))) {
113 logger.trace("refreshing digital {}", this.thing.getUID());
115 Boolean forcedRefresh = digitalLastRefresh == 0;
116 digitalLastRefresh = now;
118 if (!sensors.get(3).checkPresence(bridgeHandler)) {
122 sensors.get(3).refresh(bridgeHandler, forcedRefresh);
125 if (now >= (lastRefresh + refreshInterval)) {
126 if (!sensors.get(0).checkPresence(bridgeHandler)) {
130 logger.trace("refreshing analog {}", this.thing.getUID());
132 Boolean forcedRefresh = lastRefresh == 0;
135 if (thingType.equals(THING_TYPE_AMS)) {
136 for (int i = 0; i < sensors.size() - 1; i++) {
137 sensors.get(i).refresh(bridgeHandler, forcedRefresh);
140 for (int i = 0; i < sensors.size(); i++) {
141 sensors.get(i).refresh(bridgeHandler, forcedRefresh);
145 } catch (OwException e) {
146 logger.debug("{}: refresh exception '{}'", this.thing.getUID(), e.getMessage());
147 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "refresh exception");
152 protected void configureThingChannels() {
153 Configuration configuration = getConfig();
154 ThingBuilder thingBuilder = editThing();
156 // delete unwanted channels
157 Set<String> existingChannelIds = thing.getChannels().stream().map(channel -> channel.getUID().getId())
158 .collect(Collectors.toSet());
159 Set<String> wantedChannelIds = SENSOR_TYPE_CHANNEL_MAP.get(sensorType).stream()
160 .map(channelConfig -> channelConfig.channelId).collect(Collectors.toSet());
161 wantedChannelIds.add(CHANNEL_TEMPERATURE);
162 wantedChannelIds.add(CHANNEL_HUMIDITY);
163 existingChannelIds.stream().filter(channelId -> !wantedChannelIds.contains(channelId))
164 .forEach(channelId -> removeChannelIfExisting(thingBuilder, channelId));
166 // add or update wanted channels
167 SENSOR_TYPE_CHANNEL_MAP.get(sensorType).stream().forEach(channelConfig -> {
168 addChannelIfMissingAndEnable(thingBuilder, channelConfig);
171 // temperature channel
172 if (configuration.containsKey(CONFIG_TEMPERATURESENSOR)
173 && configuration.get(CONFIG_TEMPERATURESENSOR).equals("DS18B20")) {
174 addChannelIfMissingAndEnable(thingBuilder,
175 new OwChannelConfig(CHANNEL_TEMPERATURE, CHANNEL_TYPE_UID_TEMPERATURE_POR_RES), 1);
177 addChannelIfMissingAndEnable(thingBuilder,
178 new OwChannelConfig(CHANNEL_TEMPERATURE, CHANNEL_TYPE_UID_TEMPERATURE));
183 addChannelIfMissingAndEnable(thingBuilder, new OwChannelConfig(CHANNEL_HUMIDITY, CHANNEL_TYPE_UID_HUMIDITY),
184 new Configuration(new HashMap<String, Object>() {
185 private static final long serialVersionUID = 1L;
187 put(CONFIG_HUMIDITY, "/HIH4000/humidity");
191 // configure light channel
192 if (sensorType == OwSensorType.AMS_S || sensorType == OwSensorType.BMS_S) {
193 if (hwRevision <= 13) {
194 ((DS2438) sensors.get(0)).setLightSensorType(LightSensorType.ELABNET_V1);
196 ((DS2438) sensors.get(0)).setLightSensorType(LightSensorType.ELABNET_V2);
200 updateThing(thingBuilder.build());
203 for (AbstractOwDevice sensor : sensors) {
204 sensor.configureChannels();
206 } catch (OwException e) {
207 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
212 updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.NONE);
216 public void updateSensorProperties(OwserverBridgeHandler bridgeHandler) throws OwException {
217 Map<String, String> properties = editProperties();
218 DS2438Configuration ds2438configuration = new DS2438Configuration(bridgeHandler, sensorId);
220 sensorType = DS2438Configuration.getMultisensorType(ds2438configuration.getSensorSubType(),
221 ds2438configuration.getAssociatedSensorTypes());
223 properties.put(PROPERTY_MODELID, sensorType.toString());
224 properties.put(PROPERTY_VENDOR, ds2438configuration.getVendor());
226 properties.put(PROPERTY_PROD_DATE, ds2438configuration.getProductionDate());
227 properties.put(PROPERTY_HW_REVISION, ds2438configuration.getHardwareRevision());
229 switch (sensorType) {
232 properties.put(PROPERTY_DS18B20,
233 ds2438configuration.getAssociatedSensorIds(OwSensorType.DS18B20).get(0).getFullPath());
237 properties.put(PROPERTY_DS18B20,
238 ds2438configuration.getAssociatedSensorIds(OwSensorType.DS18B20).get(0).getFullPath());
239 properties.put(PROPERTY_DS2413,
240 ds2438configuration.getAssociatedSensorIds(OwSensorType.DS2413).get(0).getFullPath());
241 properties.put(PROPERTY_DS2438,
242 ds2438configuration.getAssociatedSensorIds(OwSensorType.MS_TV).get(0).getFullPath());
246 throw new OwException("sensorType " + sensorType.toString() + " not supported by this thing handler");
249 updateProperties(properties);
253 * used to determine the correct set of required properties
258 private static Set<String> getRequiredProperties(ThingTypeUID thingType) {
259 if (THING_TYPE_AMS.equals(thingType)) {
260 return REQUIRED_PROPERTIES_AMS;
262 return REQUIRED_PROPERTIES_BMS;