]> git.basschouten.com Git - openhab-addons.git/blob
9aed6cf4252357b02e0dee212d7aa1e1c7309d7b
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2024 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.nibeuplink.internal.handler;
14
15 import java.util.HashSet;
16 import java.util.Map;
17 import java.util.Set;
18 import java.util.concurrent.Future;
19 import java.util.concurrent.TimeUnit;
20 import java.util.concurrent.atomic.AtomicReference;
21
22 import org.eclipse.jdt.annotation.NonNullByDefault;
23 import org.eclipse.jdt.annotation.Nullable;
24 import org.eclipse.jetty.client.HttpClient;
25 import org.openhab.binding.nibeuplink.internal.AtomicReferenceTrait;
26 import org.openhab.binding.nibeuplink.internal.NibeUplinkBindingConstants;
27 import org.openhab.binding.nibeuplink.internal.command.UpdateSetting;
28 import org.openhab.binding.nibeuplink.internal.config.NibeUplinkConfiguration;
29 import org.openhab.binding.nibeuplink.internal.connector.UplinkWebInterface;
30 import org.openhab.core.thing.Channel;
31 import org.openhab.core.thing.ChannelGroupUID;
32 import org.openhab.core.thing.ChannelUID;
33 import org.openhab.core.thing.Thing;
34 import org.openhab.core.thing.ThingStatus;
35 import org.openhab.core.thing.ThingStatusDetail;
36 import org.openhab.core.thing.ThingUID;
37 import org.openhab.core.thing.binding.BaseThingHandler;
38 import org.openhab.core.thing.type.ChannelTypeUID;
39 import org.openhab.core.types.Command;
40 import org.openhab.core.types.RefreshType;
41 import org.openhab.core.types.State;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45 /**
46  * The {@link UplinkBaseHandler} is responsible for handling commands, which are
47  * sent to one of the channels.
48  *
49  * @author Alexander Friese - initial contribution
50  */
51 @NonNullByDefault
52 public abstract class UplinkBaseHandler extends BaseThingHandler implements NibeUplinkHandler, AtomicReferenceTrait {
53     private final Logger logger = LoggerFactory.getLogger(UplinkBaseHandler.class);
54
55     private final long POLLING_INITIAL_DELAY = 30;
56     private final long HOUSE_KEEPING_INITIAL_DELAY = 300;
57
58     private final Set<Channel> deadChannels = new HashSet<>(100);
59     private final Set<ChannelGroupUID> registeredGroups = new HashSet<>(10);
60
61     /**
62      * Interface object for querying the NibeUplink web interface
63      */
64     private UplinkWebInterface webInterface;
65
66     /**
67      * Schedule for polling
68      */
69     private final AtomicReference<@Nullable Future<?>> pollingJobReference;
70
71     /**
72      * Schedule for periodic cleaning dead channel list
73      */
74     private final AtomicReference<@Nullable Future<?>> deadChannelHouseKeepingReference;
75
76     public UplinkBaseHandler(Thing thing, HttpClient httpClient) {
77         super(thing);
78         this.webInterface = new UplinkWebInterface(scheduler, this, httpClient);
79         this.pollingJobReference = new AtomicReference<>(null);
80         this.deadChannelHouseKeepingReference = new AtomicReference<>(null);
81     }
82
83     @Override
84     public void handleCommand(ChannelUID channelUID, Command command) {
85         if (!(command instanceof RefreshType)) {
86             logger.debug("command for {}: {}", channelUID.getIdWithoutGroup(), command.toString());
87             Channel channel = getSpecificChannel(channelUID.getIdWithoutGroup());
88             if (channel != null) {
89                 ChannelTypeUID typeUID = channel.getChannelTypeUID();
90                 if (typeUID != null && typeUID.getId().startsWith(NibeUplinkBindingConstants.RW_CHANNEL_PREFIX)) {
91                     webInterface.enqueueCommand(new UpdateSetting(this, channel, command));
92                 }
93             }
94         }
95     }
96
97     @Override
98     public void initialize() {
99         logger.debug("About to initialize NibeUplink");
100         NibeUplinkConfiguration config = getConfiguration();
101         logger.debug("NibeUplink initialized with configuration: {}", config);
102
103         registeredGroups.clear();
104         validateChannelsAndRegisterGroups();
105
106         startPolling();
107         webInterface.start();
108         updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.NONE, "waiting for web api login");
109     }
110
111     /**
112      * initialize the channels out of the configuration
113      *
114      */
115     private void validateChannelsAndRegisterGroups() {
116         logger.debug("Validating {} channels", getThing().getChannels().size());
117         for (Channel channel : getThing().getChannels()) {
118             if (!ChannelUtil.isValidNibeChannel(channel)) {
119                 logger.warn("Channel {} is not a valid Nibe channel ({})", channel.getUID().getIdWithoutGroup(),
120                         channel.getLabel());
121                 deadChannels.add(channel);
122             } else {
123                 logger.debug("Successfully validated channel {} ({})", channel.getUID().getIdWithoutGroup(),
124                         channel.getLabel());
125                 String groupId = channel.getUID().getGroupId();
126                 if (groupId != null) {
127                     ThingUID thingUID = this.getThing().getUID();
128                     if (registeredGroups.add(new ChannelGroupUID(thingUID, groupId))) {
129                         logger.debug("Successfully registered channel-group '{}'", groupId);
130                     }
131                 }
132             }
133         }
134     }
135
136     /**
137      * Start the polling.
138      */
139     private void startPolling() {
140         updateJobReference(pollingJobReference, scheduler.scheduleWithFixedDelay(new UplinkPolling(this),
141                 POLLING_INITIAL_DELAY, getConfiguration().getPollingInterval(), TimeUnit.SECONDS));
142         updateJobReference(deadChannelHouseKeepingReference, scheduler.scheduleWithFixedDelay(deadChannels::clear,
143                 HOUSE_KEEPING_INITIAL_DELAY, getConfiguration().getHouseKeepingInterval(), TimeUnit.SECONDS));
144     }
145
146     /**
147      * Disposes the bridge.
148      */
149     @Override
150     public void dispose() {
151         logger.debug("Handler disposed.");
152
153         cancelJobReference(pollingJobReference);
154         cancelJobReference(deadChannelHouseKeepingReference);
155
156         // the webinterface also makes use of the scheduler and must stop it's jobs
157         webInterface.dispose();
158     }
159
160     @Override
161     public UplinkWebInterface getWebInterface() {
162         return webInterface;
163     }
164
165     /**
166      * will update all channels provided in the map
167      *
168      * @param values map containing the data updates
169      */
170     @Override
171     public void updateChannelStatus(Map<Channel, State> values) {
172         logger.debug("Handling channel update. ({} Channels)", values.size());
173
174         for (Channel channel : values.keySet()) {
175             if (getChannels().contains(channel)) {
176                 State value = values.get(channel);
177                 if (value != null) {
178                     logger.debug("Channel is to be updated: {}: {}", channel.getUID().getAsString(), value);
179                     updateState(channel.getUID(), value);
180                 }
181             } else {
182                 logger.debug("Could not identify channel: {} for model {}", channel.getUID().getAsString(),
183                         getThing().getThingTypeUID().getAsString());
184             }
185         }
186     }
187
188     @Override
189     public Set<Channel> getDeadChannels() {
190         return deadChannels;
191     }
192
193     @Override
194     public void setStatusInfo(ThingStatus status, ThingStatusDetail statusDetail, @Nullable String description) {
195         super.updateStatus(status, statusDetail, description);
196     }
197
198     @Override
199     public NibeUplinkConfiguration getConfiguration() {
200         return this.getConfigAs(NibeUplinkConfiguration.class);
201     }
202
203     public Set<ChannelGroupUID> getRegisteredGroups() {
204         return registeredGroups;
205     }
206 }