2 * Copyright (c) 2010-2024 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
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
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.souliss.internal.discovery;
15 import java.net.InetAddress;
17 import java.util.TreeMap;
18 import java.util.concurrent.ScheduledFuture;
19 import java.util.concurrent.TimeUnit;
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.eclipse.jdt.annotation.Nullable;
23 import org.openhab.binding.souliss.internal.SoulissBindingConstants;
24 import org.openhab.binding.souliss.internal.SoulissProtocolConstants;
25 import org.openhab.binding.souliss.internal.handler.SoulissGatewayHandler;
26 import org.openhab.core.config.discovery.AbstractDiscoveryService;
27 import org.openhab.core.config.discovery.DiscoveryResult;
28 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
29 import org.openhab.core.config.discovery.DiscoveryService;
30 import org.openhab.core.thing.ThingUID;
31 import org.openhab.core.thing.binding.ThingHandler;
32 import org.openhab.core.thing.binding.ThingHandlerService;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
37 * The {@link org.openhab.binding.souliss.internal.SoulissHandlerFactory} is responsible for creating
38 * things and thingGeneric handlers.
40 * @author Tonino Fazio - Initial contribution
41 * @author Luca Calcaterra - Refactor for OH3
44 public class SoulissGatewayDiscovery extends AbstractDiscoveryService
45 implements DiscoverResult, DiscoveryService, ThingHandlerService {
46 private @Nullable ScheduledFuture<?> discoveryJob = null;
47 private final Logger logger = LoggerFactory.getLogger(SoulissGatewayDiscovery.class);
49 private @Nullable SoulissDiscoverJob soulissDiscoverRunnableClass;
50 private @Nullable SoulissGatewayHandler soulissGwHandler;
52 public SoulissGatewayDiscovery() {
53 super(SoulissBindingConstants.SUPPORTED_THING_TYPES_UIDS, SoulissBindingConstants.DISCOVERY_TIMEOUT_IN_SECONDS,
58 public void deactivate() {
63 * The {@link gatewayDetected} callback used to create the Gateway
66 public void gatewayDetected(InetAddress addr, String id) {
67 logger.debug("Souliss gateway found: {} ", addr.getHostName());
69 String label = "Souliss Gateway " + (Byte.parseByte(id) & 0xFF);
70 Map<String, Object> properties = new TreeMap<>();
71 properties.put(SoulissBindingConstants.CONFIG_IP_ADDRESS, addr.getHostAddress());
72 var gatewayUID = new ThingUID(SoulissBindingConstants.GATEWAY_THING_TYPE,
73 Integer.toString((Byte.parseByte(id) & 0xFF)));
74 var discoveryResult = DiscoveryResultBuilder.create(gatewayUID).withLabel(label)
75 .withRepresentationProperty(SoulissBindingConstants.CONFIG_IP_ADDRESS).withProperties(properties)
77 thingDiscovered(discoveryResult);
81 protected void startScan() {
82 logger.debug("Starting Scan Service");
84 // create discovery class
85 if (soulissDiscoverRunnableClass == null) {
86 soulissDiscoverRunnableClass = new SoulissDiscoverJob(this.soulissGwHandler);
88 // send command for gw struct (typicals).. must be not soo much quick..
89 discoveryJob = scheduler.scheduleWithFixedDelay(soulissDiscoverRunnableClass, 2,
90 SoulissBindingConstants.DISCOVERY_RESEND_TIMEOUT_IN_SECONDS, TimeUnit.SECONDS);
91 logger.debug("Start Discovery Job");
96 protected synchronized void stopScan() {
97 ScheduledFuture<?> localDiscoveryJob = this.discoveryJob;
98 if (localDiscoveryJob != null) {
99 localDiscoveryJob.cancel(false);
100 soulissDiscoverRunnableClass = null;
101 logger.debug("Discovery Job Stopped");
107 public void thingDetectedActionMessages(String topicNumber, String sTopicVariant) {
108 ThingUID thingUID = null;
110 DiscoveryResult discoveryResult;
111 String sNodeID = topicNumber + SoulissBindingConstants.UUID_NODE_SLOT_SEPARATOR + sTopicVariant;
113 var localGwHandler = this.soulissGwHandler;
114 if (localGwHandler != null) {
115 var gatewayUID = localGwHandler.getThing().getUID();
116 thingUID = new ThingUID(SoulissBindingConstants.TOPICS_THING_TYPE, gatewayUID, sNodeID);
117 label = "Topic. Number: " + topicNumber + ", Variant: " + sTopicVariant;
119 discoveryResult = DiscoveryResultBuilder.create(thingUID).withLabel(label)
120 .withProperty("number", topicNumber).withProperty("variant", sTopicVariant)
121 .withRepresentationProperty("number").withBridge(gatewayUID).build();
122 thingDiscovered(discoveryResult);
127 public void thingDetectedTypicals(byte lastByteGatewayIP, byte typical, byte node, byte slot) {
128 ThingUID thingUID = null;
130 DiscoveryResult discoveryResult;
131 var gwHandler = this.soulissGwHandler;
132 if ((gwHandler != null) && (lastByteGatewayIP == (byte) Integer
133 .parseInt(gwHandler.getGwConfig().gatewayLanAddress.split("\\.")[3]))) {
134 String sNodeId = node + SoulissBindingConstants.UUID_NODE_SLOT_SEPARATOR + slot;
136 ThingUID gatewayUID = gwHandler.getThing().getUID();
137 var nodeLabel = "node";
138 var slotLabel = "slot";
141 case SoulissProtocolConstants.SOULISS_T11:
142 thingUID = new ThingUID(SoulissBindingConstants.T11_THING_TYPE, gatewayUID, sNodeId);
143 label = "T11: " + nodeLabel + " " + node + " " + slotLabel + " " + slot;
145 case SoulissProtocolConstants.SOULISS_T12:
146 thingUID = new ThingUID(SoulissBindingConstants.T12_THING_TYPE, gatewayUID, sNodeId);
147 label = "T12: " + nodeLabel + " " + " " + node + " " + " " + slotLabel + " " + slot;
149 case SoulissProtocolConstants.SOULISS_T13:
150 thingUID = new ThingUID(SoulissBindingConstants.T13_THING_TYPE, gatewayUID, sNodeId);
151 label = "T13: " + nodeLabel + " " + node + " " + slotLabel + " " + slot;
153 case SoulissProtocolConstants.SOULISS_T14:
154 thingUID = new ThingUID(SoulissBindingConstants.T14_THING_TYPE, gatewayUID, sNodeId);
155 label = "T14: " + nodeLabel + " " + node + " " + slotLabel + " " + slot;
157 case SoulissProtocolConstants.SOULISS_T16:
158 thingUID = new ThingUID(SoulissBindingConstants.T16_THING_TYPE, gatewayUID, sNodeId);
159 label = "T16: " + nodeLabel + " " + node + " " + slotLabel + " " + slot;
161 case SoulissProtocolConstants.SOULISS_T18:
162 thingUID = new ThingUID(SoulissBindingConstants.T18_THING_TYPE, gatewayUID, sNodeId);
163 label = "T18: " + nodeLabel + " " + node + " " + slotLabel + " " + slot;
165 case SoulissProtocolConstants.SOULISS_T19:
166 thingUID = new ThingUID(SoulissBindingConstants.T19_THING_TYPE, gatewayUID, sNodeId);
167 label = "T19: " + nodeLabel + " " + node + " " + slotLabel + " " + slot;
169 case SoulissProtocolConstants.SOULISS_T1A:
170 thingUID = new ThingUID(SoulissBindingConstants.T1A_THING_TYPE, gatewayUID, sNodeId);
171 label = "T1A: " + nodeLabel + " " + node + " " + slotLabel + " " + slot;
173 case SoulissProtocolConstants.SOULISS_T21:
174 thingUID = new ThingUID(SoulissBindingConstants.T21_THING_TYPE, gatewayUID, sNodeId);
175 label = "T21: " + nodeLabel + " " + node + " " + slotLabel + " " + slot;
177 case SoulissProtocolConstants.SOULISS_T22:
178 thingUID = new ThingUID(SoulissBindingConstants.T22_THING_TYPE, gatewayUID, sNodeId);
179 label = "T22: " + nodeLabel + " " + node + " " + slotLabel + " " + slot;
181 case SoulissProtocolConstants.SOULISS_T41_ANTITHEFT_MAIN:
182 thingUID = new ThingUID(SoulissBindingConstants.T41_THING_TYPE, gatewayUID, sNodeId);
183 label = "T41: " + nodeLabel + " " + node + " " + slotLabel + " " + slot;
185 case SoulissProtocolConstants.SOULISS_T42_ANTITHEFT_PEER:
186 thingUID = new ThingUID(SoulissBindingConstants.T42_THING_TYPE, gatewayUID, sNodeId);
187 label = "T42: " + nodeLabel + " " + node + " " + slotLabel + " " + slot;
189 case SoulissProtocolConstants.SOULISS_T31:
190 thingUID = new ThingUID(SoulissBindingConstants.T31_THING_TYPE, gatewayUID, sNodeId);
191 label = "T31: " + nodeLabel + " " + node + " " + slotLabel + " " + slot;
193 case SoulissProtocolConstants.SOULISS_T52_TEMPERATURE_SENSOR:
194 thingUID = new ThingUID(SoulissBindingConstants.T52_THING_TYPE, gatewayUID, sNodeId);
195 label = "T52: " + nodeLabel + " " + node + " " + slotLabel + " " + slot;
197 case SoulissProtocolConstants.SOULISS_T53_HUMIDITY_SENSOR:
198 thingUID = new ThingUID(SoulissBindingConstants.T53_THING_TYPE, gatewayUID, sNodeId);
199 label = "T53: " + nodeLabel + " " + node + " " + slotLabel + " " + slot;
201 case SoulissProtocolConstants.SOULISS_T54_LUX_SENSOR:
202 thingUID = new ThingUID(SoulissBindingConstants.T54_THING_TYPE, gatewayUID, sNodeId);
203 label = "T54: " + nodeLabel + " " + node + " " + slotLabel + " " + slot;
205 case SoulissProtocolConstants.SOULISS_T55_VOLTAGE_SENSOR:
206 thingUID = new ThingUID(SoulissBindingConstants.T55_THING_TYPE, gatewayUID, sNodeId);
207 label = "T55: " + nodeLabel + " " + node + " " + slotLabel + " " + slot;
209 case SoulissProtocolConstants.SOULISS_T56_CURRENT_SENSOR:
210 thingUID = new ThingUID(SoulissBindingConstants.T56_THING_TYPE, gatewayUID, sNodeId);
211 label = "T56: " + nodeLabel + " " + node + " " + slotLabel + " " + slot;
213 case SoulissProtocolConstants.SOULISS_T57_POWER_SENSOR:
214 thingUID = new ThingUID(SoulissBindingConstants.T57_THING_TYPE, gatewayUID, sNodeId);
215 label = "T57: " + nodeLabel + " " + node + " " + slotLabel + " " + slot;
217 case SoulissProtocolConstants.SOULISS_T61:
218 thingUID = new ThingUID(SoulissBindingConstants.T61_THING_TYPE, gatewayUID, sNodeId);
219 label = "T61: " + nodeLabel + " " + node + " " + slotLabel + " " + slot;
221 case SoulissProtocolConstants.SOULISS_T62_TEMPERATURE_SENSOR:
222 thingUID = new ThingUID(SoulissBindingConstants.T62_THING_TYPE, gatewayUID, sNodeId);
223 label = "T62: " + nodeLabel + " " + node + " " + slotLabel + " " + slot;
225 case SoulissProtocolConstants.SOULISS_T63_HUMIDITY_SENSOR:
226 thingUID = new ThingUID(SoulissBindingConstants.T63_THING_TYPE, gatewayUID, sNodeId);
227 label = "T63: " + nodeLabel + " " + node + " " + slotLabel + " " + slot;
229 case SoulissProtocolConstants.SOULISS_T64_LUX_SENSOR:
230 thingUID = new ThingUID(SoulissBindingConstants.T64_THING_TYPE, gatewayUID, sNodeId);
231 label = "T64: " + nodeLabel + " " + node + " " + slotLabel + " " + slot;
233 case SoulissProtocolConstants.SOULISS_T65_VOLTAGE_SENSOR:
234 thingUID = new ThingUID(SoulissBindingConstants.T65_THING_TYPE, gatewayUID, sNodeId);
235 label = "T65: " + nodeLabel + " " + node + " " + slotLabel + " " + slot;
237 case SoulissProtocolConstants.SOULISS_T66_CURRENT_SENSOR:
238 thingUID = new ThingUID(SoulissBindingConstants.T66_THING_TYPE, gatewayUID, sNodeId);
239 label = "T66: " + nodeLabel + " " + node + " " + slotLabel + " " + slot;
241 case SoulissProtocolConstants.SOULISS_T67_POWER_SENSOR:
242 thingUID = new ThingUID(SoulissBindingConstants.T67_THING_TYPE, gatewayUID, sNodeId);
243 label = "T67: " + nodeLabel + " " + node + " " + slotLabel + " " + slot;
246 logger.debug("no supported things found ...");
249 if (thingUID != null) {
250 label = "[" + gwHandler.getThing().getUID().getAsString() + "] " + label;
251 var uniqueId = "N" + Byte.toString(node) + "S" + Byte.toString(slot);
252 discoveryResult = DiscoveryResultBuilder.create(thingUID).withLabel(label)
253 .withProperty(SoulissBindingConstants.PROPERTY_NODE, node)
254 .withProperty(SoulissBindingConstants.PROPERTY_SLOT, slot)
255 .withProperty(SoulissBindingConstants.PROPERTY_UNIQUEID, uniqueId)
256 .withRepresentationProperty(SoulissBindingConstants.PROPERTY_UNIQUEID)
257 .withBridge(gwHandler.getThing().getUID()).build();
258 thingDiscovered(discoveryResult);
259 gwHandler.setThereIsAThingDetection();
265 public void setThingHandler(ThingHandler handler) {
266 if (handler instanceof SoulissGatewayHandler localGwHandler) {
267 this.soulissGwHandler = localGwHandler;
268 localGwHandler.discoverResult = this;
273 public @Nullable ThingHandler getThingHandler() {
274 return soulissGwHandler;