]> git.basschouten.com Git - openhab-addons.git/blob
ab29c91b42c4a455f6d6681d4d9c32d974231b29
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2021 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.remoteopenhab.internal.handler;
14
15 import static org.openhab.binding.remoteopenhab.internal.RemoteopenhabBindingConstants.*;
16 import static org.openhab.binding.remoteopenhab.internal.config.RemoteopenhabTriggerChannelConfiguration.CHANNEL_UID;
17
18 import java.util.ArrayList;
19 import java.util.List;
20
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.eclipse.jdt.annotation.Nullable;
23 import org.openhab.binding.remoteopenhab.internal.config.RemoteopenhabThingConfiguration;
24 import org.openhab.binding.remoteopenhab.internal.data.RemoteopenhabChannel;
25 import org.openhab.binding.remoteopenhab.internal.data.RemoteopenhabStatusInfo;
26 import org.openhab.binding.remoteopenhab.internal.data.RemoteopenhabThing;
27 import org.openhab.binding.remoteopenhab.internal.exceptions.RemoteopenhabException;
28 import org.openhab.binding.remoteopenhab.internal.listener.RemoteopenhabThingsDataListener;
29 import org.openhab.binding.remoteopenhab.internal.rest.RemoteopenhabRestClient;
30 import org.openhab.core.config.core.Configuration;
31 import org.openhab.core.thing.Bridge;
32 import org.openhab.core.thing.Channel;
33 import org.openhab.core.thing.ChannelUID;
34 import org.openhab.core.thing.Thing;
35 import org.openhab.core.thing.ThingStatus;
36 import org.openhab.core.thing.ThingStatusDetail;
37 import org.openhab.core.thing.ThingStatusInfo;
38 import org.openhab.core.thing.binding.BaseThingHandler;
39 import org.openhab.core.thing.binding.BridgeHandler;
40 import org.openhab.core.thing.binding.builder.ChannelBuilder;
41 import org.openhab.core.thing.binding.builder.ThingBuilder;
42 import org.openhab.core.thing.type.ChannelKind;
43 import org.openhab.core.thing.type.ChannelTypeUID;
44 import org.openhab.core.types.Command;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47
48 /**
49  * The {@link RemoteopenhabThingHandler} is responsible for handling status updates associated to
50  * any remote thing.
51  *
52  * @author Laurent Garnier - Initial contribution
53  */
54 @NonNullByDefault
55 public class RemoteopenhabThingHandler extends BaseThingHandler implements RemoteopenhabThingsDataListener {
56
57     private final Logger logger = LoggerFactory.getLogger(RemoteopenhabThingHandler.class);
58
59     private @Nullable RemoteopenhabRestClient restClient;
60
61     private @NonNullByDefault({}) RemoteopenhabThingConfiguration config;
62
63     public RemoteopenhabThingHandler(Thing thing) {
64         super(thing);
65     }
66
67     @Override
68     public void handleCommand(ChannelUID channelUID, Command command) {
69         // No state channel defined for this thing type and so no command to handle
70     }
71
72     @Override
73     public void initialize() {
74         logger.debug("initializing remote openHAB handler for thing {}", getThing().getUID());
75         Bridge bridge = getBridge();
76         initializeThing(bridge != null ? bridge.getStatus() : null);
77     }
78
79     @Override
80     public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
81         logger.debug("bridgeStatusChanged {} for thing {}", bridgeStatusInfo, getThing().getUID());
82         initializeThing(bridgeStatusInfo.getStatus());
83     }
84
85     private void initializeThing(@Nullable ThingStatus bridgeStatus) {
86         Bridge bridge = getBridge();
87         BridgeHandler bridgeHandler = bridge != null ? bridge.getHandler() : null;
88         RemoteopenhabRestClient oldClient = this.restClient;
89         if (oldClient != null) {
90             oldClient.removeThingsDataListener(this);
91             this.restClient = null;
92         }
93         if (bridgeHandler != null && bridgeStatus != null) {
94             if (bridgeStatus == ThingStatus.ONLINE) {
95                 config = getConfigAs(RemoteopenhabThingConfiguration.class);
96
97                 String uid = getConfigThingUID();
98                 if (uid.length() == 0) {
99                     updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
100                             "Undefined thing UID setting in the thing configuration");
101                 } else {
102                     RemoteopenhabRestClient client = ((RemoteopenhabBridgeHandler) bridgeHandler).gestRestClient();
103                     client.addThingsDataListener(this);
104                     this.restClient = client;
105
106                     updateStatus(ThingStatus.UNKNOWN);
107
108                     scheduler.execute(() -> {
109                         try {
110                             RemoteopenhabThing thing = client.getRemoteThing(uid);
111                             createTriggerChannels(thing, config.buildTriggerChannels);
112                             RemoteopenhabStatusInfo statusInfo = thing.statusInfo;
113                             if (statusInfo != null) {
114                                 updateThingStatus(uid, statusInfo);
115                             }
116                         } catch (RemoteopenhabException e) {
117                             logger.debug("{}", e.getMessage());
118                             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
119                         }
120                     });
121                 }
122             } else {
123                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
124             }
125         } else {
126             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
127         }
128     }
129
130     @Override
131     public void dispose() {
132         logger.debug("Disposing remote openHAB handler for thing {}", getThing().getUID());
133         RemoteopenhabRestClient client = this.restClient;
134         if (client != null) {
135             client.removeThingsDataListener(this);
136             this.restClient = null;
137         }
138         super.dispose();
139     }
140
141     private String getConfigThingUID() {
142         return config.thingUID.trim();
143     }
144
145     private void createTriggerChannels(RemoteopenhabThing thing, boolean addNewChannels) {
146         List<Channel> channels = new ArrayList<>();
147         for (RemoteopenhabChannel channelDTO : thing.channels) {
148             if (!"TRIGGER".equals(channelDTO.kind)) {
149                 continue;
150             }
151             ChannelTypeUID channelTypeUID = new ChannelTypeUID(BINDING_ID, CHANNEL_TYPE_TRIGGER);
152             ChannelUID channelUID = new ChannelUID(getThing().getUID(),
153                     channelDTO.uid.replaceAll("[^A-Za-z0-9_]", "_"));
154             Configuration channelConfig = new Configuration();
155             channelConfig.put(CHANNEL_UID, channelDTO.uid);
156             logger.trace("Create the channel {} of type {}", channelUID, channelTypeUID);
157             channels.add(ChannelBuilder.create(channelUID, null).withType(channelTypeUID).withKind(ChannelKind.TRIGGER)
158                     .withLabel(channelDTO.label).withDescription(channelDTO.description)
159                     .withConfiguration(channelConfig).build());
160         }
161         if (!channels.isEmpty()) {
162             ThingBuilder thingBuilder = editThing();
163             int nbRemoved = 0;
164             for (Channel channel : channels) {
165                 if (getThing().getChannel(channel.getUID()) != null) {
166                     thingBuilder.withoutChannel(channel.getUID());
167                     nbRemoved++;
168                 }
169             }
170             if (nbRemoved > 0) {
171                 logger.debug("{} trigger channels removed for the thing {}", nbRemoved, getThing().getUID());
172             }
173             int nbAdded = 0;
174             if (addNewChannels) {
175                 for (Channel channel : channels) {
176                     thingBuilder.withChannel(channel);
177                 }
178                 nbAdded = channels.size();
179                 logger.debug("{} trigger channels added for the thing {}", nbAdded, getThing().getUID());
180             }
181             if (nbRemoved > 0 || nbAdded > 0) {
182                 updateThing(thingBuilder.build());
183             }
184         }
185     }
186
187     @Override
188     public void onThingStatusUpdated(String thingUID, RemoteopenhabStatusInfo statusInfo) {
189         if (thingUID.equals(getConfigThingUID())) {
190             updateThingStatus(thingUID, statusInfo);
191         }
192     }
193
194     @Override
195     public void onThingAdded(RemoteopenhabThing thing) {
196         // Nothing to do
197     }
198
199     @Override
200     public void onThingRemoved(RemoteopenhabThing thing) {
201         // Nothing to do
202     }
203
204     @Override
205     public void onChannelTriggered(String channelUID, @Nullable String event) {
206         String thingUID = channelUID.substring(0, channelUID.lastIndexOf(":"));
207         if (thingUID.equals(getConfigThingUID())) {
208             for (Channel channel : getThing().getChannels()) {
209                 if (channel.getKind() == ChannelKind.TRIGGER
210                         && channelUID.equals(channel.getConfiguration().get(CHANNEL_UID))) {
211                     if (event == null) {
212                         triggerChannel(channel.getUID());
213                         logger.debug("triggerChannel {}", channel.getUID());
214                     } else {
215                         triggerChannel(channel.getUID(), event);
216                         logger.debug("triggerChannel {} with event {}", channel.getUID(), event);
217                     }
218                 }
219             }
220         }
221     }
222
223     private void updateThingStatus(String thingUID, RemoteopenhabStatusInfo statusInfo) {
224         ThingStatus status = ThingStatus.valueOf(statusInfo.status);
225         // All remote status different from UNKNOWN or ONLINE or OFFLINE is considered as OFFLINE
226         if (status != ThingStatus.UNKNOWN && status != ThingStatus.ONLINE && status != ThingStatus.OFFLINE) {
227             status = ThingStatus.OFFLINE;
228         }
229         ThingStatusDetail detail = ThingStatusDetail.valueOf(statusInfo.statusDetail);
230         updateStatus(status, detail, statusInfo.description);
231         logger.debug("updateStatus {} with status {} detail {} description {}", thingUID, status, detail,
232                 statusInfo.description);
233     }
234 }