]> git.basschouten.com Git - openhab-addons.git/blob
311acc1e403a5190511b3c4202aa6499187f0728
[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.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                             "@text/offline.config-error-undefined-thing-uid");
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                             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getRawMessage());
118                         }
119                     });
120                 }
121             } else {
122                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
123             }
124         } else {
125             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
126         }
127     }
128
129     @Override
130     public void dispose() {
131         logger.debug("Disposing remote openHAB handler for thing {}", getThing().getUID());
132         RemoteopenhabRestClient client = this.restClient;
133         if (client != null) {
134             client.removeThingsDataListener(this);
135             this.restClient = null;
136         }
137         super.dispose();
138     }
139
140     private String getConfigThingUID() {
141         return config.thingUID.trim();
142     }
143
144     private void createTriggerChannels(RemoteopenhabThing thing, boolean addNewChannels) {
145         List<Channel> channels = new ArrayList<>();
146         for (RemoteopenhabChannel channelDTO : thing.channels) {
147             if (!"TRIGGER".equals(channelDTO.kind)) {
148                 continue;
149             }
150             ChannelTypeUID channelTypeUID = new ChannelTypeUID(BINDING_ID, CHANNEL_TYPE_TRIGGER);
151             ChannelUID channelUID = new ChannelUID(getThing().getUID(),
152                     channelDTO.uid.replaceAll("[^A-Za-z0-9_]", "_"));
153             Configuration channelConfig = new Configuration();
154             channelConfig.put(CHANNEL_UID, channelDTO.uid);
155             logger.trace("Create the channel {} of type {}", channelUID, channelTypeUID);
156             channels.add(ChannelBuilder.create(channelUID, null).withType(channelTypeUID).withKind(ChannelKind.TRIGGER)
157                     .withLabel(channelDTO.label).withDescription(channelDTO.description)
158                     .withConfiguration(channelConfig).build());
159         }
160         if (!channels.isEmpty()) {
161             ThingBuilder thingBuilder = editThing();
162             int nbRemoved = 0;
163             for (Channel channel : channels) {
164                 if (getThing().getChannel(channel.getUID()) != null) {
165                     thingBuilder.withoutChannel(channel.getUID());
166                     nbRemoved++;
167                 }
168             }
169             if (nbRemoved > 0) {
170                 logger.debug("{} trigger channels removed for the thing {}", nbRemoved, getThing().getUID());
171             }
172             int nbAdded = 0;
173             if (addNewChannels) {
174                 for (Channel channel : channels) {
175                     thingBuilder.withChannel(channel);
176                 }
177                 nbAdded = channels.size();
178                 logger.debug("{} trigger channels added for the thing {}", nbAdded, getThing().getUID());
179             }
180             if (nbRemoved > 0 || nbAdded > 0) {
181                 updateThing(thingBuilder.build());
182             }
183         }
184     }
185
186     @Override
187     public void onThingStatusUpdated(String thingUID, RemoteopenhabStatusInfo statusInfo) {
188         if (thingUID.equals(getConfigThingUID())) {
189             updateThingStatus(thingUID, statusInfo);
190         }
191     }
192
193     @Override
194     public void onThingAdded(RemoteopenhabThing thing) {
195         // Nothing to do
196     }
197
198     @Override
199     public void onThingRemoved(RemoteopenhabThing thing) {
200         // Nothing to do
201     }
202
203     @Override
204     public void onChannelTriggered(String channelUID, @Nullable String event) {
205         String thingUID = channelUID.substring(0, channelUID.lastIndexOf(":"));
206         if (thingUID.equals(getConfigThingUID())) {
207             for (Channel channel : getThing().getChannels()) {
208                 if (channel.getKind() == ChannelKind.TRIGGER
209                         && channelUID.equals(channel.getConfiguration().get(CHANNEL_UID))) {
210                     if (event == null) {
211                         triggerChannel(channel.getUID());
212                         logger.debug("triggerChannel {}", channel.getUID());
213                     } else {
214                         triggerChannel(channel.getUID(), event);
215                         logger.debug("triggerChannel {} with event {}", channel.getUID(), event);
216                     }
217                 }
218             }
219         }
220     }
221
222     private void updateThingStatus(String thingUID, RemoteopenhabStatusInfo statusInfo) {
223         ThingStatus status = ThingStatus.valueOf(statusInfo.status);
224         // All remote status different from UNKNOWN or ONLINE or OFFLINE is considered as OFFLINE
225         if (status != ThingStatus.UNKNOWN && status != ThingStatus.ONLINE && status != ThingStatus.OFFLINE) {
226             status = ThingStatus.OFFLINE;
227         }
228         ThingStatusDetail detail = ThingStatusDetail.valueOf(statusInfo.statusDetail);
229         updateStatus(status, detail, statusInfo.description);
230         logger.debug("updateStatus {} with status {} detail {} description {}", thingUID, status, detail,
231                 statusInfo.description);
232     }
233 }