]> git.basschouten.com Git - openhab-addons.git/blob
476d5e3a0ba3c6e91051772c1fadf4fc5f8feac9
[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.souliss.internal.handler;
14
15 import java.util.Collection;
16 import java.util.Collections;
17 import java.util.concurrent.ExecutorService;
18 import java.util.concurrent.Executors;
19 import java.util.concurrent.Future;
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.souliss.internal.SoulissBindingConstants;
26 import org.openhab.binding.souliss.internal.config.GatewayConfig;
27 import org.openhab.binding.souliss.internal.discovery.DiscoverResult;
28 import org.openhab.binding.souliss.internal.discovery.SoulissGatewayDiscovery;
29 import org.openhab.binding.souliss.internal.protocol.CommonCommands;
30 import org.openhab.binding.souliss.internal.protocol.SendDispatcherRunnable;
31 import org.openhab.binding.souliss.internal.protocol.UDPListenDiscoverRunnable;
32 import org.openhab.core.common.NamedThreadFactory;
33 import org.openhab.core.thing.Bridge;
34 import org.openhab.core.thing.ChannelUID;
35 import org.openhab.core.thing.Thing;
36 import org.openhab.core.thing.ThingStatus;
37 import org.openhab.core.thing.ThingStatusDetail;
38 import org.openhab.core.thing.binding.BaseBridgeHandler;
39 import org.openhab.core.thing.binding.ThingHandlerService;
40 import org.openhab.core.types.Command;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43
44 /**
45  * The {@link SoulissGatewayHandler} is responsible for handling commands, which are
46  * sent to one of the channels.
47  *
48  * @author Tonino Fazio - Initial contribution
49  * @author Luca Calcaterra - Refactor for OH3
50  */
51 @NonNullByDefault
52 public class SoulissGatewayHandler extends BaseBridgeHandler {
53
54     private final Logger logger = LoggerFactory.getLogger(SoulissGatewayHandler.class);
55
56     private final CommonCommands commonCommands = new CommonCommands();
57
58     private @Nullable ExecutorService udpExecutorService;
59
60     private @Nullable Future<?> udpListenerJob;
61     private @Nullable ScheduledFuture<?> pingScheduler;
62     private @Nullable ScheduledFuture<?> subscriptionScheduler;
63     private @Nullable ScheduledFuture<?> healthScheduler;
64
65     boolean bGatewayDetected = false;
66
67     private @Nullable SoulissGatewayDiscovery discoveryService;
68
69     public @Nullable DiscoverResult discoverResult = null;
70
71     public boolean thereIsAThingDetection = true;
72
73     private Bridge bridge;
74
75     private int nodes = 0;
76     private int maxTypicalXnode = 24;
77     private int countPingKo = 0;
78
79     private GatewayConfig gwConfig = new GatewayConfig();
80
81     public GatewayConfig getGwConfig() {
82         return gwConfig;
83     }
84
85     public SoulissGatewayHandler(Bridge br) {
86         super(br);
87         bridge = br;
88     }
89
90     @Override
91     public void handleCommand(ChannelUID channelUID, Command command) {
92         // do nothing
93     }
94
95     @Override
96     public Collection<Class<? extends ThingHandlerService>> getServices() {
97         return Collections.singleton(SoulissGatewayDiscovery.class);
98     }
99
100     @Override
101     public void initialize() {
102         gwConfig = getConfigAs(GatewayConfig.class);
103
104         logger.debug("Starting UDP server on Souliss Default Port for Topics (Publish&Subcribe)");
105
106         // new runnable udp listener
107         var udpServerDefaultPortRunnableClass = new UDPListenDiscoverRunnable(this.bridge, this.discoverResult);
108         // and exec on thread
109         var localUdpListenerJob = this.udpListenerJob;
110         if (localUdpListenerJob == null || localUdpListenerJob.isCancelled()) {
111             var localUdpExecutorService = this.udpExecutorService;
112             localUdpExecutorService = Executors
113                     .newSingleThreadExecutor(new NamedThreadFactory(getThing().getUID().getAsString()));
114             localUdpExecutorService.submit(udpServerDefaultPortRunnableClass);
115         }
116
117         // JOB PING
118         var soulissGatewayJobPingRunnable = new SoulissGatewayJobPing(this.bridge);
119         pingScheduler = scheduler.scheduleWithFixedDelay(soulissGatewayJobPingRunnable, 2, this.gwConfig.pingInterval,
120                 TimeUnit.SECONDS);
121         // JOB SUBSCRIPTION
122         var soulissGatewayJobSubscriptionRunnable = new SoulissGatewayJobSubscription(bridge);
123         subscriptionScheduler = scheduler.scheduleWithFixedDelay(soulissGatewayJobSubscriptionRunnable, 5,
124                 this.gwConfig.subscriptionInterval, TimeUnit.SECONDS);
125
126         // JOB HEALTH OF NODES
127         var soulissGatewayJobHealthyRunnable = new SoulissGatewayJobHealthy(this.bridge);
128         healthScheduler = scheduler.scheduleWithFixedDelay(soulissGatewayJobHealthyRunnable, 5,
129                 this.gwConfig.healthyInterval, TimeUnit.SECONDS);
130
131         var soulissSendDispatcherRunnable = new SendDispatcherRunnable(this.bridge);
132         scheduler.scheduleWithFixedDelay(soulissSendDispatcherRunnable, 15,
133                 SoulissBindingConstants.SEND_DISPATCHER_MIN_DELAY_CYCLE_IN_MILLIS, TimeUnit.MILLISECONDS);
134     }
135
136     public void dbStructAnswerReceived() {
137         commonCommands.sendTypicalRequestFrame(this.gwConfig, nodes);
138     }
139
140     public void setNodes(int nodes) {
141         this.nodes = nodes;
142     }
143
144     public int getNodes() {
145         var maxNode = 0;
146         for (Thing thing : getThing().getThings()) {
147             if (thing.getThingTypeUID().equals(SoulissBindingConstants.TOPICS_THING_TYPE)) {
148                 continue;
149             }
150             var cfg = thing.getConfiguration();
151             var props = cfg.getProperties();
152             var pNode = props.get("node");
153             if (pNode != null) {
154                 var thingNode = Integer.parseInt(pNode.toString());
155
156                 if (thingNode > maxNode) {
157                     maxNode = thingNode;
158                 }
159             }
160             // at the end the length of the list will be equal to the number of present nodes
161         }
162         return maxNode + 1;
163     }
164
165     public void setMaxTypicalXnode(int maxTypicalXnode) {
166         this.maxTypicalXnode = maxTypicalXnode;
167     }
168
169     public int getMaxTypicalXnode() {
170         return maxTypicalXnode;
171     }
172
173     /**
174      * The {@link gatewayDetected} is used to notify that UDPServer decoded a Ping Response from gateway
175      */
176
177     public void gatewayDetected() {
178         updateStatus(ThingStatus.ONLINE);
179         // reset counter
180         countPingKo = 0;
181     }
182
183     public void pingSent() {
184         if (++countPingKo > 3) {
185             var bridgeHandler = bridge.getHandler();
186             if (bridgeHandler != null) {
187                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
188                         "Gateway " + bridgeHandler.getThing().getUID() + " do not respond to " + countPingKo + " ping");
189             }
190         }
191     }
192
193     public void sendSubscription() {
194         if (this.gwConfig.gatewayLanAddress.length() > 0) {
195             int totNodes = getNodes();
196             commonCommands.sendSUBSCRIPTIONframe(this.gwConfig, totNodes);
197         }
198         logger.debug("Sent subscription packet");
199     }
200
201     public void setThereIsAThingDetection() {
202         thereIsAThingDetection = true;
203     }
204
205     public void resetThereIsAThingDetection() {
206         thereIsAThingDetection = false;
207     }
208
209     public @Nullable SoulissGatewayDiscovery getDiscoveryService() {
210         return this.discoveryService;
211     }
212
213     public void setDiscoveryService(SoulissGatewayDiscovery discoveryService) {
214         this.discoveryService = discoveryService;
215     }
216
217     @Override
218     public void dispose() {
219         var localPingScheduler = this.pingScheduler;
220         if (localPingScheduler != null) {
221             localPingScheduler.cancel(true);
222         }
223         var localSubscriptionScheduler = this.subscriptionScheduler;
224         if (localSubscriptionScheduler != null) {
225             localSubscriptionScheduler.cancel(true);
226         }
227         var localHealthScheduler = this.healthScheduler;
228         if (localHealthScheduler != null) {
229             localHealthScheduler.cancel(true);
230         }
231         var localUdpListenerJob = this.udpListenerJob;
232         if (localUdpListenerJob != null) {
233             localUdpListenerJob.cancel(true);
234         }
235         var localUdpExecutorService = this.udpExecutorService;
236         if (localUdpExecutorService != null) {
237             localUdpExecutorService.shutdownNow();
238         }
239
240         super.dispose();
241     }
242
243     public void setBridgeStatus(boolean isOnline) {
244         logger.debug("setBridgeStatus(): Setting Bridge to {}", isOnline ? ThingStatus.ONLINE : ThingStatus.OFFLINE);
245
246         updateStatus(isOnline ? ThingStatus.ONLINE : ThingStatus.OFFLINE);
247     }
248 }