]> git.basschouten.com Git - openhab-addons.git/blob
d620431126fcfdf1be32bf95eb62273e326efab4
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2022 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.netatmo.internal.handler;
14
15 import java.util.ArrayList;
16 import java.util.List;
17 import java.util.Objects;
18 import java.util.Optional;
19 import java.util.concurrent.ScheduledExecutorService;
20 import java.util.concurrent.TimeUnit;
21 import java.util.stream.Collectors;
22 import java.util.stream.Stream;
23
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.eclipse.jdt.annotation.Nullable;
26 import org.openhab.binding.netatmo.internal.api.data.ModuleType;
27 import org.openhab.binding.netatmo.internal.api.dto.NAObject;
28 import org.openhab.binding.netatmo.internal.config.NAThingConfiguration;
29 import org.openhab.binding.netatmo.internal.handler.capability.Capability;
30 import org.openhab.binding.netatmo.internal.handler.capability.CapabilityMap;
31 import org.openhab.binding.netatmo.internal.handler.capability.HomeCapability;
32 import org.openhab.binding.netatmo.internal.handler.capability.RefreshCapability;
33 import org.openhab.binding.netatmo.internal.handler.capability.RestCapability;
34 import org.openhab.core.thing.Bridge;
35 import org.openhab.core.thing.Channel;
36 import org.openhab.core.thing.ChannelUID;
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.binding.BridgeHandler;
41 import org.openhab.core.thing.binding.builder.ThingBuilder;
42 import org.openhab.core.thing.type.ChannelKind;
43 import org.openhab.core.types.Command;
44 import org.openhab.core.types.RefreshType;
45 import org.openhab.core.types.State;
46 import org.slf4j.Logger;
47
48 /**
49  * {@link CommonInterface} defines common methods of AccountHandler and NAThingHandlers used by Capabilities
50  *
51  * @author GaĆ«l L'hopital - Initial contribution
52  *
53  */
54 @NonNullByDefault
55 public interface CommonInterface {
56     Thing getThing();
57
58     ThingBuilder editThing();
59
60     CapabilityMap getCapabilities();
61
62     Logger getLogger();
63
64     ScheduledExecutorService getScheduler();
65
66     boolean isLinked(ChannelUID channelUID);
67
68     void updateState(ChannelUID channelUID, State state);
69
70     void setThingStatus(ThingStatus thingStatus, ThingStatusDetail thingStatusDetail,
71             @Nullable String thingStatusReason);
72
73     void triggerChannel(String channelID, String event);
74
75     void updateThing(Thing thing);
76
77     @Nullable
78     Bridge getBridge();
79
80     default @Nullable CommonInterface getBridgeHandler() {
81         Bridge bridge = getBridge();
82         return bridge != null && bridge.getHandler() instanceof DeviceHandler ? (DeviceHandler) bridge.getHandler()
83                 : null;
84     }
85
86     default @Nullable ApiBridgeHandler getAccountHandler() {
87         Bridge bridge = getBridge();
88         BridgeHandler bridgeHandler = null;
89         if (bridge != null) {
90             bridgeHandler = bridge.getHandler();
91             while (bridgeHandler != null && !(bridgeHandler instanceof ApiBridgeHandler)) {
92                 bridge = ((CommonInterface) bridgeHandler).getBridge();
93                 bridgeHandler = bridge != null ? bridge.getHandler() : null;
94             }
95         }
96         return (ApiBridgeHandler) bridgeHandler;
97     }
98
99     default @Nullable String getBridgeId() {
100         CommonInterface bridge = getBridgeHandler();
101         return bridge != null ? bridge.getId() : null;
102     }
103
104     default void expireData() {
105         getCapabilities().values().forEach(cap -> cap.expireData());
106     }
107
108     default String getId() {
109         return (String) getThing().getConfiguration().get(NAThingConfiguration.ID);
110     }
111
112     default Stream<Channel> getActiveChannels() {
113         return getThing().getChannels().stream()
114                 .filter(channel -> ChannelKind.STATE.equals(channel.getKind()) && isLinked(channel.getUID()));
115     }
116
117     default Optional<CommonInterface> getHomeHandler() {
118         CommonInterface bridgeHandler = getBridgeHandler();
119         if (bridgeHandler != null) {
120             return bridgeHandler.getCapabilities().get(HomeCapability.class).isPresent() ? Optional.of(bridgeHandler)
121                     : Optional.empty();
122         }
123         return Optional.empty();
124     }
125
126     default List<CommonInterface> getActiveChildren() {
127         Thing thing = getThing();
128         if (thing instanceof Bridge) {
129             return ((Bridge) thing).getThings().stream().filter(Thing::isEnabled)
130                     .filter(th -> th.getStatusInfo().getStatusDetail() != ThingStatusDetail.BRIDGE_OFFLINE)
131                     .map(Thing::getHandler).filter(Objects::nonNull).map(CommonInterface.class::cast)
132                     .collect(Collectors.toList());
133         }
134         return List.of();
135     }
136
137     default <T extends RestCapability<?>> Optional<T> getHomeCapability(Class<T> clazz) {
138         return getHomeHandler().map(handler -> handler.getCapabilities().get(clazz)).orElse(Optional.empty());
139     }
140
141     default void setNewData(NAObject newData) {
142         String finalReason = null;
143         for (Capability cap : getCapabilities().values()) {
144             String thingStatusReason = cap.setNewData(newData);
145             if (thingStatusReason != null) {
146                 finalReason = thingStatusReason;
147             }
148         }
149         if (!newData.isIgnoredForThingUpdate()) {
150             setThingStatus(finalReason == null ? ThingStatus.ONLINE : ThingStatus.OFFLINE, ThingStatusDetail.NONE,
151                     finalReason);
152         }
153     }
154
155     default void commonHandleCommand(ChannelUID channelUID, Command command) {
156         if (ThingStatus.ONLINE.equals(getThing().getStatus())) {
157             if (command == RefreshType.REFRESH) {
158                 expireData();
159                 return;
160             }
161             String channelName = channelUID.getIdWithoutGroup();
162             getCapabilities().values().forEach(cap -> cap.handleCommand(channelName, command));
163         } else {
164             getLogger().debug("Command {}, on channel {} dropped - thing is not ONLINE", command, channelUID);
165         }
166     }
167
168     default void proceedWithUpdate() {
169         updateReadings().forEach(dataSet -> setNewData(dataSet));
170     }
171
172     default List<NAObject> updateReadings() {
173         List<NAObject> result = new ArrayList<>();
174         getCapabilities().values().forEach(cap -> result.addAll(cap.updateReadings()));
175         getActiveChildren().forEach(child -> result.addAll(child.updateReadings()));
176         return result;
177     }
178
179     default void commonInitialize() {
180         Bridge bridge = getBridge();
181         if (bridge == null || bridge.getHandler() == null) {
182             setThingStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED, null);
183         } else if (!ThingStatus.ONLINE.equals(bridge.getStatus())) {
184             setThingStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, null);
185             removeRefreshCapability();
186         } else {
187             setThingStatus(ThingStatus.UNKNOWN, ThingStatusDetail.NONE, null);
188             setRefreshCapability();
189             getCapabilities().values().forEach(cap -> cap.initialize());
190             getScheduler().schedule(() -> {
191                 CommonInterface bridgeHandler = getBridgeHandler();
192                 if (bridgeHandler != null) {
193                     bridgeHandler.expireData();
194                 }
195             }, 1, TimeUnit.SECONDS);
196         }
197     }
198
199     default void setRefreshCapability() {
200         ModuleType moduleType = ModuleType.from(getThing().getThingTypeUID());
201         if (ModuleType.ACCOUNT.equals(moduleType.getBridge())) {
202             NAThingConfiguration config = getThing().getConfiguration().as(NAThingConfiguration.class);
203             getCapabilities().put(new RefreshCapability(this, getScheduler(), config.refreshInterval));
204         }
205     }
206
207     default void removeRefreshCapability() {
208         Capability refreshCap = getCapabilities().remove(RefreshCapability.class);
209         if (refreshCap != null) {
210             refreshCap.dispose();
211         }
212     }
213
214     default void commonDispose() {
215         getCapabilities().values().forEach(Capability::dispose);
216     }
217
218     default void removeChannels(List<Channel> channels) {
219         ThingBuilder builder = editThing().withoutChannels(channels);
220         updateThing(builder.build());
221     }
222 }