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