]> git.basschouten.com Git - openhab-addons.git/blob
80cb4e39a9c5fede52e8871973e1c72a96d81ca1
[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.wolfsmartset.internal.handler;
14
15 import static org.openhab.binding.wolfsmartset.internal.WolfSmartsetBindingConstants.*;
16
17 import java.time.Instant;
18 import java.util.Map;
19 import java.util.concurrent.ConcurrentHashMap;
20
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.eclipse.jdt.annotation.Nullable;
23 import org.openhab.binding.wolfsmartset.internal.config.WolfSmartsetUnitConfiguration;
24 import org.openhab.binding.wolfsmartset.internal.dto.GetParameterValuesDTO;
25 import org.openhab.binding.wolfsmartset.internal.dto.MenuItemTabViewDTO;
26 import org.openhab.binding.wolfsmartset.internal.dto.ParameterDescriptorDTO;
27 import org.openhab.binding.wolfsmartset.internal.dto.SubMenuEntryDTO;
28 import org.openhab.core.thing.Channel;
29 import org.openhab.core.thing.ChannelUID;
30 import org.openhab.core.thing.Thing;
31 import org.openhab.core.thing.ThingStatus;
32 import org.openhab.core.thing.ThingStatusDetail;
33 import org.openhab.core.thing.ThingStatusInfo;
34 import org.openhab.core.thing.binding.BaseThingHandler;
35 import org.openhab.core.thing.binding.builder.ChannelBuilder;
36 import org.openhab.core.thing.binding.builder.ThingBuilder;
37 import org.openhab.core.thing.type.ChannelTypeUID;
38 import org.openhab.core.types.Command;
39 import org.openhab.core.types.RefreshType;
40 import org.openhab.core.types.State;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43
44 /**
45  * The {@link WolfSmartsetUnitThingHandler} is responsible for updating the channels associated
46  * with a WolfSmartset unit.
47  *
48  * @author Bo Biene - Initial contribution
49  */
50 @NonNullByDefault
51 public class WolfSmartsetUnitThingHandler extends BaseThingHandler {
52
53     public static final String CAPABILITY_ADC = "adc";
54     public static final String CAPABILITY_CO2 = "co2";
55     public static final String CAPABILITY_DRY_CONTACT = "dryContact";
56     public static final String CAPABILITY_HUMIDITY = "humidity";
57     public static final String CAPABILITY_OCCUPANCY = "occupancy";
58     public static final String CAPABILITY_TEMPERATURE = "temperature";
59     public static final String CAPABILITY_UNKNOWN = "unknown";
60
61     private final Logger logger = LoggerFactory.getLogger(WolfSmartsetUnitThingHandler.class);
62
63     private @NonNullByDefault({}) String unitId;
64     private @Nullable Instant lastRefreshTime;
65
66     private Map<String, State> stateCache = new ConcurrentHashMap<>();
67     private Map<Long, ParameterDescriptorDTO> paramDescriptionMap = new ConcurrentHashMap<>();
68     private @Nullable SubMenuEntryDTO submenu;
69     private @Nullable MenuItemTabViewDTO tabmenu;
70
71     public WolfSmartsetUnitThingHandler(Thing thing) {
72         super(thing);
73     }
74
75     @Override
76     public void initialize() {
77         unitId = getConfigAs(WolfSmartsetUnitConfiguration.class).unitId;
78         logger.debug("UnitThing: Initializing unit '{}'", unitId);
79         clearSavedState();
80         var bridgeHandler = getBridge();
81         if (bridgeHandler != null) {
82             bridgeStatusChanged(bridgeHandler.getStatusInfo());
83         }
84     }
85
86     @Override
87     public void dispose() {
88         logger.debug("UnitThing: Disposing unit '{}'", unitId);
89     }
90
91     @Override
92     public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
93         if (bridgeStatusInfo.getStatus() == ThingStatus.ONLINE) {
94             if (this.submenu != null && this.tabmenu != null) {
95                 updateStatus(ThingStatus.ONLINE);
96             } else {
97                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_PENDING);
98             }
99
100         } else {
101             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
102         }
103     }
104
105     @Override
106     public void handleCommand(ChannelUID channelUID, Command command) {
107         if (command instanceof RefreshType) {
108             State state = stateCache.get(channelUID.getId());
109             if (state != null) {
110                 updateState(channelUID.getId(), state);
111             }
112         }
113     }
114
115     /**
116      * Get the {@link SubMenuEntryDTO} for this unit
117      * 
118      * @return the {@link SubMenuEntryDTO} for this unit
119      */
120     public @Nullable SubMenuEntryDTO getSubMenu() {
121         return this.submenu;
122     }
123
124     /**
125      * Get the {@link MenuItemTabViewDTO} for this unit
126      * 
127      * @return the {@link MenuItemTabViewDTO} for this unit
128      */
129     public @Nullable MenuItemTabViewDTO getTabMenu() {
130         return this.tabmenu;
131     }
132
133     /**
134      * Get the {@link Instant} of the last valid call of updateValues
135      * 
136      * @return the getInstallationDate of the last valid call of updateValues
137      */
138     public @Nullable Instant getLastRefreshTime() {
139         return this.lastRefreshTime;
140     }
141
142     /**
143      * Update the configuration of this unit and create / update the related channels
144      * 
145      * @param submenu the {@link SubMenuEntryDTO} for this unit
146      * @param tabmenu the {@link MenuItemTabViewDTO} for this unit
147      */
148     public void updateConfiguration(SubMenuEntryDTO submenu, MenuItemTabViewDTO tabmenu) {
149         this.submenu = submenu;
150         this.tabmenu = tabmenu;
151         var bridgeHandler = getBridge();
152         if (bridgeHandler != null) {
153             bridgeStatusChanged(bridgeHandler.getStatusInfo());
154         }
155         lastRefreshTime = null;
156
157         ThingBuilder thingBuilder = editThing();
158         var thingId = thing.getUID();
159
160         paramDescriptionMap.clear();
161         for (var param : tabmenu.parameterDescriptors) {
162             paramDescriptionMap.put(param.valueId, param);
163             var channelId = new ChannelUID(thingId, param.parameterId.toString()); // "bindingId:type:thingId:1")
164             if (thing.getChannel(channelId) == null) {
165                 logger.debug("UnitThing: Create channel '{}'", channelId);
166                 Channel channel = ChannelBuilder.create(channelId, getItemType(param.controlType)).withLabel(param.name)
167                         .withType(getChannelType(param)).build();
168                 thingBuilder.withChannel(channel);
169             }
170         }
171
172         updateThing(thingBuilder.build());
173
174         for (var param : tabmenu.parameterDescriptors) {
175             var channelId = new ChannelUID(thingId, param.parameterId.toString());
176             setState(channelId, WolfSmartsetUtils.undefOrString(param.value));
177         }
178     }
179
180     /**
181      * Update the values of the channels
182      * 
183      * @param values {@link GetParameterValuesDTO} representing the new values
184      */
185     public void updateValues(@Nullable GetParameterValuesDTO values) {
186         var thingId = thing.getUID();
187         if (values != null && values.getValues() != null && !values.getValues().isEmpty()) {
188             if (!values.getIsNewJobCreated()) {
189                 lastRefreshTime = Instant.now();
190             }
191
192             for (var value : values.getValues()) {
193                 var param = paramDescriptionMap.get(value.getValueId());
194                 if (param != null) {
195                     var channelId = new ChannelUID(thingId, param.parameterId.toString());
196                     setState(channelId, WolfSmartsetUtils.undefOrString(value.getValue()));
197                 }
198             }
199         }
200     }
201
202     /**
203      * Stores the state for the channel in stateCache and calls updateState of this Thing
204      * 
205      * @param channelId {@link ChannelUID} the id of the channel to update
206      * @param state {@link State} the new state for the channel
207      */
208     private void setState(ChannelUID channelId, State state) {
209         stateCache.put(channelId.getId(), state);
210         updateState(channelId, state);
211     }
212
213     private ChannelTypeUID getChannelType(ParameterDescriptorDTO parmeter) {
214         if (parmeter.unit == null || parmeter.unit.isBlank()) {
215             if (parmeter.controlType == null) {
216                 return new ChannelTypeUID(BINDING_ID, CH_STRING);
217             } else {
218                 switch (parmeter.controlType) {
219                     case 1:
220                     case 3:
221                     case 6:
222                     case 8:
223                         return new ChannelTypeUID(BINDING_ID, CH_NUMBER);
224                     case 5:
225                         return new ChannelTypeUID(BINDING_ID, CH_CONTACT);
226                     case 9:
227                     case 10:
228                         return new ChannelTypeUID(BINDING_ID, CH_DATETIME);
229                     default:
230                         return new ChannelTypeUID(BINDING_ID, CH_STRING);
231                 }
232             }
233         } else {
234             switch (parmeter.unit) {
235                 case "bar":
236                     return new ChannelTypeUID(BINDING_ID, CH_PRESSURE);
237                 case "%":
238                 case "Std":
239                     return new ChannelTypeUID(BINDING_ID, CH_NUMBER);
240                 case "°C":
241                     return new ChannelTypeUID(BINDING_ID, CH_TEMPERATURE);
242                 default:
243                     return new ChannelTypeUID(BINDING_ID, CH_STRING);
244             }
245         }
246     }
247
248     private String getItemType(Integer controlType) {
249         switch (controlType) {
250             case 1:
251             case 3:
252             case 6:
253             case 8:
254                 return "Number";
255             case 5:
256                 return "Contact";
257             case 9:
258             case 10:
259                 return "DateTime";
260             default:
261                 return "String";
262         }
263     }
264
265     private void clearSavedState() {
266         stateCache.clear();
267     }
268 }