]> git.basschouten.com Git - openhab-addons.git/blob
4c2e8f21cf8b59b03314d12a6d422dc279e0cab6
[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.netatmo.internal.handler;
14
15 import static org.openhab.binding.netatmo.internal.NetatmoBindingConstants.*;
16
17 import java.lang.reflect.InvocationTargetException;
18 import java.lang.reflect.Method;
19 import java.util.Optional;
20 import java.util.concurrent.ScheduledFuture;
21 import java.util.concurrent.TimeUnit;
22
23 import org.eclipse.jdt.annotation.NonNullByDefault;
24 import org.eclipse.jdt.annotation.Nullable;
25 import org.openhab.binding.netatmo.internal.ChannelTypeUtils;
26 import org.openhab.core.config.core.Configuration;
27 import org.openhab.core.i18n.TimeZoneProvider;
28 import org.openhab.core.thing.Thing;
29 import org.openhab.core.thing.ThingStatus;
30 import org.openhab.core.types.State;
31 import org.openhab.core.types.UnDefType;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 /**
36  * {@link NetatmoModuleHandler} is the handler for a given
37  * module device accessed through the Netatmo Device
38  *
39  * @author GaĆ«l L'hopital - Initial contribution
40  */
41 @NonNullByDefault
42 public class NetatmoModuleHandler<MODULE> extends AbstractNetatmoThingHandler {
43     private final Logger logger = LoggerFactory.getLogger(NetatmoModuleHandler.class);
44     private @Nullable ScheduledFuture<?> refreshJob;
45     private @Nullable MODULE module;
46     private boolean refreshRequired;
47
48     protected NetatmoModuleHandler(Thing thing, final TimeZoneProvider timeZoneProvider) {
49         super(thing, timeZoneProvider);
50     }
51
52     @Override
53     protected void initializeThing() {
54         refreshJob = scheduler.schedule(() -> {
55             requestParentRefresh();
56         }, 5, TimeUnit.SECONDS);
57     }
58
59     @Override
60     public void dispose() {
61         ScheduledFuture<?> job = refreshJob;
62         if (job != null) {
63             job.cancel(true);
64             refreshJob = null;
65         }
66     }
67
68     protected @Nullable String getParentId() {
69         Configuration conf = config;
70         Object parentId = conf != null ? conf.get(PARENT_ID) : null;
71         if (parentId instanceof String) {
72             return ((String) parentId).toLowerCase();
73         }
74         return null;
75     }
76
77     public boolean childOf(AbstractNetatmoThingHandler naThingHandler) {
78         return naThingHandler.matchesId(getParentId());
79     }
80
81     @Override
82     protected State getNAThingProperty(String channelId) {
83         try {
84             Optional<MODULE> mod = getModule();
85             if (channelId.equalsIgnoreCase(CHANNEL_LAST_MESSAGE) && mod.isPresent()) {
86                 Method getLastMessage = mod.get().getClass().getMethod("getLastMessage");
87                 Integer lastMessage = (Integer) getLastMessage.invoke(mod.get());
88                 return ChannelTypeUtils.toDateTimeType(lastMessage, timeZoneProvider.getTimeZone());
89             }
90         } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
91                 | InvocationTargetException e) {
92             logger.debug("The module has no method to access {} property ", channelId);
93             return UnDefType.NULL;
94         }
95
96         return super.getNAThingProperty(channelId);
97     }
98
99     protected void updateChannels(Object module) {
100         MODULE theModule = (MODULE) module;
101         setModule(theModule);
102         updateStatus(isReachable() ? ThingStatus.ONLINE : ThingStatus.OFFLINE);
103         getRadioHelper().ifPresent(helper -> helper.setModule(module));
104         getBatteryHelper().ifPresent(helper -> helper.setModule(module));
105         updateProperties(theModule);
106         super.updateChannels();
107     }
108
109     protected void invalidateParentCacheAndRefresh() {
110         setRefreshRequired(true);
111         // Leave a bit of time to Netatmo Server to get in sync with new values sent
112         scheduler.schedule(() -> {
113             invalidateParentCache();
114             requestParentRefresh();
115         }, 2, TimeUnit.SECONDS);
116     }
117
118     protected void requestParentRefresh() {
119         setRefreshRequired(true);
120         findNAThing(getParentId()).ifPresent(AbstractNetatmoThingHandler::updateChannels);
121     }
122
123     private void invalidateParentCache() {
124         findNAThing(getParentId()).map(NetatmoDeviceHandler.class::cast).ifPresent(NetatmoDeviceHandler::expireData);
125     }
126
127     protected void updateProperties(MODULE moduleData) {
128     }
129
130     protected boolean isRefreshRequired() {
131         return refreshRequired;
132     }
133
134     protected void setRefreshRequired(boolean refreshRequired) {
135         this.refreshRequired = refreshRequired;
136     }
137
138     protected Optional<MODULE> getModule() {
139         return Optional.ofNullable(module);
140     }
141
142     public void setModule(MODULE module) {
143         this.module = module;
144     }
145 }