]> git.basschouten.com Git - openhab-addons.git/blob
f06ba231c0089e9f46527f4f342e45d8c488152b
[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.satel.internal.handler;
14
15 import java.nio.charset.Charset;
16 import java.time.ZoneId;
17 import java.util.concurrent.ScheduledFuture;
18 import java.util.concurrent.TimeUnit;
19
20 import org.eclipse.jdt.annotation.NonNullByDefault;
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.openhab.binding.satel.internal.command.NewStatesCommand;
23 import org.openhab.binding.satel.internal.command.SatelCommand;
24 import org.openhab.binding.satel.internal.config.SatelBridgeConfig;
25 import org.openhab.binding.satel.internal.event.ConnectionStatusEvent;
26 import org.openhab.binding.satel.internal.event.SatelEventListener;
27 import org.openhab.binding.satel.internal.protocol.SatelModule;
28 import org.openhab.binding.satel.internal.types.IntegraType;
29 import org.openhab.binding.satel.internal.util.StringUtils;
30 import org.openhab.core.thing.Bridge;
31 import org.openhab.core.thing.ChannelUID;
32 import org.openhab.core.thing.ThingStatus;
33 import org.openhab.core.thing.ThingStatusDetail;
34 import org.openhab.core.thing.binding.ConfigStatusBridgeHandler;
35 import org.openhab.core.types.Command;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39 /**
40  * The {@link SatelBridgeHandler} is base class for all bridge handlers.
41  *
42  * @author Krzysztof Goworek - Initial contribution
43  */
44 @NonNullByDefault
45 public abstract class SatelBridgeHandler extends ConfigStatusBridgeHandler implements SatelEventListener {
46
47     private final Logger logger = LoggerFactory.getLogger(SatelBridgeHandler.class);
48
49     private SatelBridgeConfig config = new SatelBridgeConfig();
50     private @Nullable SatelModule satelModule;
51     private @Nullable ScheduledFuture<?> pollingJob;
52     private String userCodeOverride = "";
53     private final ZoneId integraZone = ZoneId.systemDefault();
54
55     public SatelBridgeHandler(Bridge bridge) {
56         super(bridge);
57     }
58
59     @Override
60     public void incomingEvent(ConnectionStatusEvent event) {
61         final SatelModule satelModule = this.satelModule;
62         if (satelModule != null) {
63             // update bridge status and get new states from the system
64             if (event.isConnected()) {
65                 updateStatus(ThingStatus.ONLINE);
66                 satelModule.sendCommand(new NewStatesCommand(satelModule.hasExtPayloadSupport()));
67             } else {
68                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, event.getReason());
69             }
70         }
71     }
72
73     @Override
74     public void handleCommand(ChannelUID channelUID, Command command) {
75         // the bridge does not support any command at the moment
76         logger.debug("New command for {}: {}", channelUID, command);
77     }
78
79     protected void initialize(final SatelModule satelModule) {
80         logger.debug("Initializing bridge handler");
81
82         final SatelBridgeConfig config = getConfigAs(SatelBridgeConfig.class);
83         this.config = config;
84         this.satelModule = satelModule;
85         satelModule.addEventListener(this);
86         satelModule.open();
87         logger.debug("Satel module opened");
88
89         final ScheduledFuture<?> pollingJob = this.pollingJob;
90         if (pollingJob == null || pollingJob.isCancelled()) {
91             Runnable pollingCommand = () -> {
92                 if (!satelModule.isInitialized()) {
93                     logger.debug("Module not initialized yet, skipping refresh");
94                     return;
95                 }
96
97                 // get list of states that have changed
98                 logger.trace("Sending 'get new states' command");
99                 satelModule.sendCommand(new NewStatesCommand(satelModule.hasExtPayloadSupport()));
100             };
101             this.pollingJob = scheduler.scheduleWithFixedDelay(pollingCommand, 0, config.getRefresh(),
102                     TimeUnit.MILLISECONDS);
103         }
104     }
105
106     @Override
107     public void dispose() {
108         logger.debug("Disposing bridge handler.");
109
110         final ScheduledFuture<?> pollingJob = this.pollingJob;
111         if (pollingJob != null && !pollingJob.isCancelled()) {
112             pollingJob.cancel(true);
113             this.pollingJob = null;
114         }
115
116         final SatelModule satelModule = this.satelModule;
117         if (satelModule != null) {
118             satelModule.close();
119             this.satelModule = null;
120             logger.debug("Satel module closed.");
121         }
122     }
123
124     /**
125      * Adds given listener to list of event receivers.
126      *
127      * @param listener listener object to add
128      */
129     public void addEventListener(SatelEventListener listener) {
130         final SatelModule satelModule = this.satelModule;
131         if (satelModule != null) {
132             satelModule.addEventListener(listener);
133         }
134     }
135
136     /**
137      * Removes given listener from list of event receivers.
138      *
139      * @param listener listener object to remove
140      */
141     public void removeEventListener(SatelEventListener listener) {
142         final SatelModule satelModule = this.satelModule;
143         if (satelModule != null) {
144             satelModule.removeEventListener(listener);
145         }
146     }
147
148     @Override
149     public boolean isInitialized() {
150         final SatelModule satelModule = this.satelModule;
151         return satelModule != null && satelModule.isInitialized();
152     }
153
154     /**
155      * @return type of Integra system
156      * @see IntegraType
157      */
158     public IntegraType getIntegraType() {
159         final SatelModule satelModule = this.satelModule;
160         return satelModule != null ? satelModule.getIntegraType() : IntegraType.UNKNOWN;
161     }
162
163     /**
164      * @return current user code, either from the configuration or set later using {@link #setUserCode(String)}
165      */
166     public String getUserCode() {
167         if (StringUtils.isNotEmpty(userCodeOverride)) {
168             return userCodeOverride;
169         } else {
170             return config.getUserCode();
171         }
172     }
173
174     /**
175      * @param userCode new use code that overrides the one in the configuration
176      */
177     public void setUserCode(String userCode) {
178         this.userCodeOverride = userCode;
179     }
180
181     /**
182      * @return encoding for texts
183      */
184     public Charset getEncoding() {
185         try {
186             return config.getEncoding();
187         } catch (Exception e) {
188             logger.info("Invalid or unsupported encoding configured for {}", getThing().getUID());
189             return Charset.defaultCharset();
190         }
191     }
192
193     /**
194      * @return zone for Integra date and time values
195      */
196     public ZoneId getZoneId() {
197         return integraZone;
198     }
199
200     /**
201      * Sends given command to communication module.
202      *
203      * @param command a command to send
204      * @param async if <code>false</code> method waits for the response
205      * @return <code>true</code> if send succeeded
206      */
207     public boolean sendCommand(SatelCommand command, boolean async) {
208         final SatelModule satelModule = this.satelModule;
209         if (satelModule == null) {
210             return false;
211         }
212         if (async) {
213             return satelModule.sendCommand(command);
214         } else if (!satelModule.sendCommand(command, true)) {
215             return false;
216         }
217
218         boolean interrupted = false;
219         while (!interrupted) {
220             // wait for command state change
221             try {
222                 synchronized (command) {
223                     command.wait(satelModule.getTimeout());
224                 }
225             } catch (InterruptedException e) {
226                 // ignore, we will leave the loop on next interruption state check
227                 interrupted = true;
228             }
229             // check current state
230             switch (command.getState()) {
231                 case SUCCEEDED:
232                     return true;
233                 case FAILED:
234                     return false;
235                 default:
236                     // wait for next change unless interrupted
237             }
238         }
239         return false;
240     }
241 }