2 * Copyright (c) 2010-2023 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.openwebnet.internal.discovery;
15 import java.util.HashMap;
19 import org.eclipse.jdt.annotation.NonNullByDefault;
20 import org.eclipse.jdt.annotation.Nullable;
21 import org.openhab.binding.openwebnet.internal.OpenWebNetBindingConstants;
22 import org.openhab.binding.openwebnet.internal.handler.OpenWebNetBridgeHandler;
23 import org.openhab.core.config.discovery.AbstractDiscoveryService;
24 import org.openhab.core.config.discovery.DiscoveryResult;
25 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
26 import org.openhab.core.config.discovery.DiscoveryService;
27 import org.openhab.core.thing.ThingTypeUID;
28 import org.openhab.core.thing.ThingUID;
29 import org.openhab.core.thing.binding.ThingHandler;
30 import org.openhab.core.thing.binding.ThingHandlerService;
31 import org.openwebnet4j.OpenDeviceType;
32 import org.openwebnet4j.message.BaseOpenMessage;
33 import org.openwebnet4j.message.Where;
34 import org.openwebnet4j.message.WhereAlarm;
35 import org.openwebnet4j.message.WhereThermo;
36 import org.openwebnet4j.message.WhereZigBee;
37 import org.openwebnet4j.message.Who;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
42 * The {@link OpenWebNetDeviceDiscoveryService} is responsible for discovering
43 * OpenWebNet devices connected to a bridge/gateway
45 * @author Massimo Valla - Initial contribution
46 * @author Andrea Conte - Energy management, Thermoregulation
47 * @author Gilberto Cocchi - Thermoregulation
48 * @author Giovanni Fabiani - Aux support
51 public class OpenWebNetDeviceDiscoveryService extends AbstractDiscoveryService
52 implements DiscoveryService, ThingHandlerService {
54 private final Logger logger = LoggerFactory.getLogger(OpenWebNetDeviceDiscoveryService.class);
56 private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = OpenWebNetBindingConstants.DEVICE_SUPPORTED_THING_TYPES;
57 private static final int SEARCH_TIME_SEC = 60;
59 private @NonNullByDefault({}) OpenWebNetBridgeHandler bridgeHandler;
60 private @NonNullByDefault({}) ThingUID bridgeUID;
62 private boolean cuFound = false;
64 public OpenWebNetDeviceDiscoveryService() {
65 super(SUPPORTED_THING_TYPES, SEARCH_TIME_SEC);
69 public Set<ThingTypeUID> getSupportedThingTypes() {
70 return SUPPORTED_THING_TYPES;
74 protected void startScan() {
75 logger.info("------ SEARCHING for DEVICES on bridge '{}' ({}) ...", bridgeHandler.getThing().getLabel(),
78 bridgeHandler.searchDevices();
82 protected void stopScan() {
83 logger.debug("------ stopScan() on bridge '{}'", bridgeUID);
84 bridgeHandler.scanStopped();
88 public void abortScan() {
89 logger.debug("------ abortScan() on bridge '{}'", bridgeUID);
90 bridgeHandler.scanStopped();
94 * Create and notify to Inbox a new DiscoveryResult based on WHERE,
95 * OpenDeviceType and BaseOpenMessage
97 * @param where the discovered device's address (WHERE)
98 * @param deviceType {@link OpenDeviceType} of the discovered device
99 * @param message the OWN message received that identified the device
102 public void newDiscoveryResult(@Nullable Where where, OpenDeviceType deviceType,
103 @Nullable BaseOpenMessage baseMsg) {
104 logger.debug("newDiscoveryResult() WHERE={}, deviceType={}", where, deviceType);
105 ThingTypeUID thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_GENERIC_DEVICE; // generic device
106 String thingLabel = OpenWebNetBindingConstants.THING_LABEL_GENERIC_DEVICE;
107 Who deviceWho = Who.UNKNOWN;
108 switch (deviceType) {
109 case ZIGBEE_ON_OFF_SWITCH:
110 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_ZB_ON_OFF_SWITCH;
111 thingLabel = OpenWebNetBindingConstants.THING_LABEL_ZB_ON_OFF_SWITCH;
112 deviceWho = Who.LIGHTING;
114 case ZIGBEE_DIMMER_SWITCH:
115 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_ZB_DIMMER;
116 thingLabel = OpenWebNetBindingConstants.THING_LABEL_ZB_DIMMER;
117 deviceWho = Who.LIGHTING;
119 case SCS_ON_OFF_SWITCH:
120 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_BUS_ON_OFF_SWITCH;
121 thingLabel = OpenWebNetBindingConstants.THING_LABEL_BUS_ON_OFF_SWITCH;
122 deviceWho = Who.LIGHTING;
124 case SCS_DIMMER_SWITCH:
125 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_BUS_DIMMER;
126 thingLabel = OpenWebNetBindingConstants.THING_LABEL_BUS_DIMMER;
127 deviceWho = Who.LIGHTING;
129 case SCS_SHUTTER_SWITCH:
130 case SCS_SHUTTER_CONTROL: {
131 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_BUS_AUTOMATION;
132 thingLabel = OpenWebNetBindingConstants.THING_LABEL_BUS_AUTOMATION;
133 deviceWho = Who.AUTOMATION;
136 case ZIGBEE_SHUTTER_SWITCH:
137 case ZIGBEE_SHUTTER_CONTROL: {
138 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_ZB_AUTOMATION;
139 thingLabel = OpenWebNetBindingConstants.THING_LABEL_ZB_AUTOMATION;
140 deviceWho = Who.AUTOMATION;
143 case SCS_THERMO_SENSOR: {
144 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_BUS_THERMO_SENSOR;
145 thingLabel = OpenWebNetBindingConstants.THING_LABEL_BUS_THERMO_SENSOR;
146 deviceWho = Who.THERMOREGULATION;
149 case SCS_THERMO_ZONE: {
150 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_BUS_THERMO_ZONE;
151 thingLabel = OpenWebNetBindingConstants.THING_LABEL_BUS_THERMO_ZONE;
152 deviceWho = Who.THERMOREGULATION;
155 case SCS_THERMO_CENTRAL_UNIT: {
156 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_BUS_THERMO_CU;
157 thingLabel = OpenWebNetBindingConstants.THING_LABEL_BUS_THERMO_CU;
158 deviceWho = Who.THERMOREGULATION;
161 case SCS_ENERGY_METER: {
162 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_BUS_ENERGY_METER;
163 thingLabel = OpenWebNetBindingConstants.THING_LABEL_BUS_ENERGY_METER;
164 deviceWho = Who.ENERGY_MANAGEMENT;
167 case BASIC_SCENARIO: {
168 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_BUS_SCENARIO;
169 thingLabel = OpenWebNetBindingConstants.THING_LABEL_BUS_SCENARIO;
170 deviceWho = Who.SCENARIO;
173 case SCENARIO_CONTROL: {
174 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_BUS_CEN_SCENARIO_CONTROL;
175 thingLabel = OpenWebNetBindingConstants.THING_LABEL_BUS_CEN_SCENARIO_CONTROL;
176 deviceWho = Who.CEN_SCENARIO_SCHEDULER;
179 case SCS_DRY_CONTACT_IR: {
180 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_BUS_DRY_CONTACT_IR;
181 thingLabel = OpenWebNetBindingConstants.THING_LABEL_BUS_DRY_CONTACT_IR;
182 deviceWho = Who.CEN_PLUS_SCENARIO_SCHEDULER;
185 case MULTIFUNCTION_SCENARIO_CONTROL: {
186 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_BUS_CENPLUS_SCENARIO_CONTROL;
187 thingLabel = OpenWebNetBindingConstants.THING_LABEL_BUS_CENPLUS_SCENARIO_CONTROL;
188 deviceWho = Who.CEN_PLUS_SCENARIO_SCHEDULER;
191 case SCS_AUXILIARY_TOGGLE_CONTROL: {
192 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_BUS_AUX;
193 thingLabel = OpenWebNetBindingConstants.THING_LABEL_BUS_AUX;
197 case SCS_ALARM_CENTRAL_UNIT: {
198 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_BUS_ALARM_SYSTEM;
199 thingLabel = OpenWebNetBindingConstants.THING_LABEL_BUS_ALARM_SYSTEM;
200 deviceWho = Who.BURGLAR_ALARM;
203 case SCS_ALARM_ZONE: {
204 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_BUS_ALARM_ZONE;
205 thingLabel = OpenWebNetBindingConstants.THING_LABEL_BUS_ALARM_ZONE;
206 deviceWho = Who.BURGLAR_ALARM;
210 logger.warn("Device type {} is not supported, default to GENERIC device (WHERE={})", deviceType, where);
211 if (where instanceof WhereZigBee) {
212 thingLabel = "Zigbee " + thingLabel;
214 if (baseMsg != null) {
215 deviceWho = baseMsg.getWho();
221 } else if (OpenWebNetBindingConstants.THING_TYPE_BUS_ALARM_SYSTEM.equals(thingTypeUID)) {
222 w = new WhereAlarm("0");
224 logger.debug("ignoring newDiscoveryResult with null where: {}", baseMsg);
228 String ownId = bridgeHandler.ownIdFromWhoWhere(deviceWho, w);
229 if (OpenWebNetBindingConstants.THING_TYPE_BUS_ON_OFF_SWITCH.equals(thingTypeUID)) {
230 if (bridgeHandler.getRegisteredDevice(ownId) != null) {
231 logger.debug("dimmer/switch with WHERE={} already registered, skipping this discovery result", w);
236 String tId = bridgeHandler.thingIdFromWhere(w);
237 ThingUID thingUID = new ThingUID(thingTypeUID, bridgeUID, tId);
239 DiscoveryResult discoveryResult = null;
241 String whereConfig = w.value();
243 // remove # from discovered alarm zone
244 if (OpenWebNetBindingConstants.THING_TYPE_BUS_ALARM_ZONE.equals(thingTypeUID)) {
245 whereConfig = "" + ((WhereAlarm) w).getZone();
248 Map<String, Object> properties = new HashMap<>(2);
250 // detect Thermo CU type
251 if (OpenWebNetBindingConstants.THING_TYPE_BUS_THERMO_CU.equals(thingTypeUID)) {
253 logger.debug("CU found: {}", w);
254 if (w.value().charAt(0) == '#') { // 99-zone CU
255 thingLabel += " 99-zone";
256 logger.debug("@@@@@ THERMO CU found 99-zone: where={}, ownId={}, whereConfig={}", w, ownId,
259 thingLabel += " 4-zone";
260 whereConfig = "#" + w.value();
261 logger.debug("@@@@ THERMO CU found 4-zone: where={}, ownId={}, whereConfig={}", w, ownId, whereConfig);
263 } else if (OpenWebNetBindingConstants.THING_TYPE_BUS_THERMO_ZONE.equals(thingTypeUID)) {
265 // set param standalone = false for thermo zone
266 properties.put(OpenWebNetBindingConstants.CONFIG_PROPERTY_STANDALONE, false);
268 whereConfig = "" + ((WhereThermo) w).getZone();
269 logger.debug("@@@@@ THERMO ZONE found: where={}, ownId={}, whereConfig={}, standalone={}", w, ownId,
270 whereConfig, properties.get(OpenWebNetBindingConstants.CONFIG_PROPERTY_STANDALONE));
273 if (w instanceof WhereZigBee whereZigBee && WhereZigBee.UNIT_02.equals(whereZigBee.getUnit())) {
274 logger.debug("UNIT=02 found (WHERE={}) -> will remove previous result if exists", w);
275 thingRemoved(thingUID); // remove previously discovered thing
276 // re-create thingUID with new type
277 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_ZB_ON_OFF_SWITCH_2UNITS;
278 thingLabel = OpenWebNetBindingConstants.THING_LABEL_ZB_ON_OFF_SWITCH_2UNITS;
279 thingUID = new ThingUID(thingTypeUID, bridgeUID, tId);
280 whereConfig = whereZigBee.valueWithUnit(WhereZigBee.UNIT_ALL); // replace unit '02' with '00'
281 logger.debug("UNIT=02, switching type from {} to {}",
282 OpenWebNetBindingConstants.THING_TYPE_ZB_ON_OFF_SWITCH,
283 OpenWebNetBindingConstants.THING_TYPE_ZB_ON_OFF_SWITCH_2UNITS);
285 properties.put(OpenWebNetBindingConstants.CONFIG_PROPERTY_WHERE, whereConfig);
286 properties.put(OpenWebNetBindingConstants.PROPERTY_OWNID, ownId);
287 if (OpenWebNetBindingConstants.THING_TYPE_GENERIC_DEVICE.equals(thingTypeUID)) {
288 thingLabel = thingLabel + " (WHO=" + deviceWho + ", WHERE=" + whereConfig + ")";
290 thingLabel = thingLabel + " (WHERE=" + whereConfig + ")";
292 discoveryResult = DiscoveryResultBuilder.create(thingUID).withThingType(thingTypeUID).withProperties(properties)
293 .withRepresentationProperty(OpenWebNetBindingConstants.PROPERTY_OWNID).withBridge(bridgeUID)
294 .withLabel(thingLabel).build();
295 thingDiscovered(discoveryResult);
299 public void deactivate() {
304 public void setThingHandler(@Nullable ThingHandler handler) {
305 if (handler instanceof OpenWebNetBridgeHandler openWebNetBridgeHandler) {
306 logger.debug("attaching {} to handler {} ", this, handler);
307 bridgeHandler = openWebNetBridgeHandler;
308 bridgeHandler.deviceDiscoveryService = this;
309 bridgeUID = bridgeHandler.getThing().getUID();
314 public @Nullable ThingHandler getThingHandler() {
315 return bridgeHandler;