]> git.basschouten.com Git - openhab-addons.git/blob
c4db1111c44fc1a9ea34c12a9d27dcdca0a1de70
[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.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() != null
91                         && typeUID.getId().startsWith(NibeUplinkBindingConstants.RW_CHANNEL_PREFIX)) {
92                     webInterface.enqueueCommand(new UpdateSetting(this, channel, command));
93                 }
94             }
95         }
96     }
97
98     @Override
99     public void initialize() {
100         logger.debug("About to initialize NibeUplink");
101         NibeUplinkConfiguration config = getConfiguration();
102         logger.debug("NibeUplink initialized with configuration: {}", config);
103
104         registeredGroups.clear();
105         validateChannelsAndRegisterGroups();
106
107         startPolling();
108         webInterface.start();
109         updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.NONE, "waiting for web api login");
110     }
111
112     /**
113      * initialize the channels out of the configuration
114      *
115      */
116     private void validateChannelsAndRegisterGroups() {
117         logger.debug("Validating {} channels", getThing().getChannels().size());
118         for (Channel channel : getThing().getChannels()) {
119             if (!ChannelUtil.isValidNibeChannel(channel)) {
120                 logger.warn("Channel {} is not a valid Nibe channel ({})", channel.getUID().getIdWithoutGroup(),
121                         channel.getLabel());
122                 deadChannels.add(channel);
123             } else {
124                 logger.debug("Successfully validated channel {} ({})", channel.getUID().getIdWithoutGroup(),
125                         channel.getLabel());
126                 String groupId = channel.getUID().getGroupId();
127                 if (groupId != null) {
128                     ThingUID thingUID = this.getThing().getUID();
129                     if (registeredGroups.add(new ChannelGroupUID(thingUID, groupId))) {
130                         logger.debug("Successfully registered channel-group '{}'", groupId);
131                     }
132                 }
133             }
134         }
135     }
136
137     /**
138      * Start the polling.
139      */
140     private void startPolling() {
141         updateJobReference(pollingJobReference, scheduler.scheduleWithFixedDelay(new UplinkPolling(this),
142                 POLLING_INITIAL_DELAY, getConfiguration().getPollingInterval(), TimeUnit.SECONDS));
143         updateJobReference(deadChannelHouseKeepingReference, scheduler.scheduleWithFixedDelay(deadChannels::clear,
144                 HOUSE_KEEPING_INITIAL_DELAY, getConfiguration().getHouseKeepingInterval(), TimeUnit.SECONDS));
145     }
146
147     /**
148      * Disposes the bridge.
149      */
150     @Override
151     public void dispose() {
152         logger.debug("Handler disposed.");
153
154         cancelJobReference(pollingJobReference);
155         cancelJobReference(deadChannelHouseKeepingReference);
156
157         // the webinterface also makes use of the scheduler and must stop it's jobs
158         webInterface.dispose();
159     }
160
161     @Override
162     public UplinkWebInterface getWebInterface() {
163         return webInterface;
164     }
165
166     /**
167      * will update all channels provided in the map
168      *
169      * @param values map containing the data updates
170      */
171     @Override
172     public void updateChannelStatus(Map<Channel, State> values) {
173         logger.debug("Handling channel update. ({} Channels)", values.size());
174
175         for (Channel channel : values.keySet()) {
176             if (getChannels().contains(channel)) {
177                 State value = values.get(channel);
178                 if (value != null) {
179                     logger.debug("Channel is to be updated: {}: {}", channel.getUID().getAsString(), value);
180                     updateState(channel.getUID(), value);
181                 }
182             } else {
183                 logger.debug("Could not identify channel: {} for model {}", channel.getUID().getAsString(),
184                         getThing().getThingTypeUID().getAsString());
185             }
186         }
187     }
188
189     @Override
190     public Set<Channel> getDeadChannels() {
191         return deadChannels;
192     }
193
194     @Override
195     public void setStatusInfo(ThingStatus status, ThingStatusDetail statusDetail, String description) {
196         super.updateStatus(status, statusDetail, description);
197     }
198
199     @Override
200     public NibeUplinkConfiguration getConfiguration() {
201         return this.getConfigAs(NibeUplinkConfiguration.class);
202     }
203
204     public Set<ChannelGroupUID> getRegisteredGroups() {
205         return registeredGroups;
206     }
207 }