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.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.AbstractThingHandlerDiscoveryService;
24 import org.openhab.core.config.discovery.DiscoveryResult;
25 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
26 import org.openhab.core.thing.ThingTypeUID;
27 import org.openhab.core.thing.ThingUID;
28 import org.openwebnet4j.OpenDeviceType;
29 import org.openwebnet4j.message.BaseOpenMessage;
30 import org.openwebnet4j.message.Where;
31 import org.openwebnet4j.message.WhereAlarm;
32 import org.openwebnet4j.message.WhereThermo;
33 import org.openwebnet4j.message.WhereZigBee;
34 import org.openwebnet4j.message.Who;
35 import org.osgi.service.component.annotations.Component;
36 import org.osgi.service.component.annotations.ServiceScope;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
41 * The {@link OpenWebNetDeviceDiscoveryService} is responsible for discovering
42 * OpenWebNet devices connected to a bridge/gateway
44 * @author Massimo Valla - Initial contribution
45 * @author Andrea Conte - Energy management, Thermoregulation
46 * @author Gilberto Cocchi - Thermoregulation
47 * @author Giovanni Fabiani - Aux support
49 @Component(scope = ServiceScope.PROTOTYPE, service = OpenWebNetDeviceDiscoveryService.class)
51 public class OpenWebNetDeviceDiscoveryService extends AbstractThingHandlerDiscoveryService<OpenWebNetBridgeHandler> {
52 private final Logger logger = LoggerFactory.getLogger(OpenWebNetDeviceDiscoveryService.class);
54 private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = OpenWebNetBindingConstants.DEVICE_SUPPORTED_THING_TYPES;
55 private static final int SEARCH_TIME_SEC = 60;
57 private @NonNullByDefault({}) ThingUID bridgeUID;
59 private boolean cuFound = false;
61 public OpenWebNetDeviceDiscoveryService() {
62 super(OpenWebNetBridgeHandler.class, SUPPORTED_THING_TYPES, SEARCH_TIME_SEC);
66 public Set<ThingTypeUID> getSupportedThingTypes() {
67 return SUPPORTED_THING_TYPES;
71 protected void startScan() {
72 logger.info("------ SEARCHING for DEVICES on bridge '{}' ({}) ...", thingHandler.getThing().getLabel(),
75 thingHandler.searchDevices();
79 protected void stopScan() {
80 logger.debug("------ stopScan() on bridge '{}'", bridgeUID);
81 thingHandler.scanStopped();
85 public void abortScan() {
86 logger.debug("------ abortScan() on bridge '{}'", bridgeUID);
87 thingHandler.scanStopped();
91 * Create and notify to Inbox a new DiscoveryResult based on WHERE,
92 * OpenDeviceType and BaseOpenMessage
94 * @param where the discovered device's address (WHERE)
95 * @param deviceType {@link OpenDeviceType} of the discovered device
96 * @param baseMsg the OWN message received that identified the device
99 public void newDiscoveryResult(@Nullable Where where, OpenDeviceType deviceType,
100 @Nullable BaseOpenMessage baseMsg) {
101 logger.debug("newDiscoveryResult() WHERE={}, deviceType={}", where, deviceType);
102 ThingTypeUID thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_GENERIC_DEVICE; // generic device
103 String thingLabel = OpenWebNetBindingConstants.THING_LABEL_GENERIC_DEVICE;
104 Who deviceWho = Who.UNKNOWN;
105 switch (deviceType) {
106 case ZIGBEE_ON_OFF_SWITCH:
107 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_ZB_ON_OFF_SWITCH;
108 thingLabel = OpenWebNetBindingConstants.THING_LABEL_ZB_ON_OFF_SWITCH;
109 deviceWho = Who.LIGHTING;
111 case ZIGBEE_DIMMER_SWITCH:
112 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_ZB_DIMMER;
113 thingLabel = OpenWebNetBindingConstants.THING_LABEL_ZB_DIMMER;
114 deviceWho = Who.LIGHTING;
116 case SCS_ON_OFF_SWITCH:
117 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_BUS_ON_OFF_SWITCH;
118 thingLabel = OpenWebNetBindingConstants.THING_LABEL_BUS_ON_OFF_SWITCH;
119 deviceWho = Who.LIGHTING;
121 case SCS_DIMMER_SWITCH:
122 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_BUS_DIMMER;
123 thingLabel = OpenWebNetBindingConstants.THING_LABEL_BUS_DIMMER;
124 deviceWho = Who.LIGHTING;
126 case SCS_SHUTTER_SWITCH:
127 case SCS_SHUTTER_CONTROL: {
128 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_BUS_AUTOMATION;
129 thingLabel = OpenWebNetBindingConstants.THING_LABEL_BUS_AUTOMATION;
130 deviceWho = Who.AUTOMATION;
133 case ZIGBEE_SHUTTER_SWITCH:
134 case ZIGBEE_SHUTTER_CONTROL: {
135 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_ZB_AUTOMATION;
136 thingLabel = OpenWebNetBindingConstants.THING_LABEL_ZB_AUTOMATION;
137 deviceWho = Who.AUTOMATION;
140 case SCS_THERMO_SENSOR: {
141 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_BUS_THERMO_SENSOR;
142 thingLabel = OpenWebNetBindingConstants.THING_LABEL_BUS_THERMO_SENSOR;
143 deviceWho = Who.THERMOREGULATION;
146 case SCS_THERMO_ZONE: {
147 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_BUS_THERMO_ZONE;
148 thingLabel = OpenWebNetBindingConstants.THING_LABEL_BUS_THERMO_ZONE;
149 deviceWho = Who.THERMOREGULATION;
152 case SCS_THERMO_CENTRAL_UNIT: {
153 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_BUS_THERMO_CU;
154 thingLabel = OpenWebNetBindingConstants.THING_LABEL_BUS_THERMO_CU;
155 deviceWho = Who.THERMOREGULATION;
158 case SCS_ENERGY_METER: {
159 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_BUS_ENERGY_METER;
160 thingLabel = OpenWebNetBindingConstants.THING_LABEL_BUS_ENERGY_METER;
161 deviceWho = Who.ENERGY_MANAGEMENT;
164 case BASIC_SCENARIO: {
165 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_BUS_SCENARIO;
166 thingLabel = OpenWebNetBindingConstants.THING_LABEL_BUS_SCENARIO;
167 deviceWho = Who.SCENARIO;
170 case SCENARIO_CONTROL: {
171 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_BUS_CEN_SCENARIO_CONTROL;
172 thingLabel = OpenWebNetBindingConstants.THING_LABEL_BUS_CEN_SCENARIO_CONTROL;
173 deviceWho = Who.CEN_SCENARIO_SCHEDULER;
176 case SCS_DRY_CONTACT_IR: {
177 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_BUS_DRY_CONTACT_IR;
178 thingLabel = OpenWebNetBindingConstants.THING_LABEL_BUS_DRY_CONTACT_IR;
179 deviceWho = Who.CEN_PLUS_SCENARIO_SCHEDULER;
182 case MULTIFUNCTION_SCENARIO_CONTROL: {
183 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_BUS_CENPLUS_SCENARIO_CONTROL;
184 thingLabel = OpenWebNetBindingConstants.THING_LABEL_BUS_CENPLUS_SCENARIO_CONTROL;
185 deviceWho = Who.CEN_PLUS_SCENARIO_SCHEDULER;
188 case SCS_AUXILIARY_TOGGLE_CONTROL: {
189 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_BUS_AUX;
190 thingLabel = OpenWebNetBindingConstants.THING_LABEL_BUS_AUX;
194 case SCS_ALARM_CENTRAL_UNIT: {
195 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_BUS_ALARM_SYSTEM;
196 thingLabel = OpenWebNetBindingConstants.THING_LABEL_BUS_ALARM_SYSTEM;
197 deviceWho = Who.BURGLAR_ALARM;
200 case SCS_ALARM_ZONE: {
201 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_BUS_ALARM_ZONE;
202 thingLabel = OpenWebNetBindingConstants.THING_LABEL_BUS_ALARM_ZONE;
203 deviceWho = Who.BURGLAR_ALARM;
207 logger.warn("Device type {} is not supported, default to GENERIC device (WHERE={})", deviceType, where);
208 if (where instanceof WhereZigBee) {
209 thingLabel = "Zigbee " + thingLabel;
211 if (baseMsg != null) {
212 deviceWho = baseMsg.getWho();
218 } else if (OpenWebNetBindingConstants.THING_TYPE_BUS_ALARM_SYSTEM.equals(thingTypeUID)) {
219 w = new WhereAlarm("0");
221 logger.debug("ignoring newDiscoveryResult with null where: {}", baseMsg);
225 String ownId = thingHandler.ownIdFromWhoWhere(deviceWho, w);
226 if (OpenWebNetBindingConstants.THING_TYPE_BUS_ON_OFF_SWITCH.equals(thingTypeUID)) {
227 if (thingHandler.getRegisteredDevice(ownId) != null) {
228 logger.debug("dimmer/switch with WHERE={} already registered, skipping this discovery result", w);
233 String tId = thingHandler.thingIdFromWhere(w);
234 ThingUID thingUID = new ThingUID(thingTypeUID, bridgeUID, tId);
236 DiscoveryResult discoveryResult = null;
238 String whereConfig = w.value();
240 // remove # from discovered alarm zone
241 if (OpenWebNetBindingConstants.THING_TYPE_BUS_ALARM_ZONE.equals(thingTypeUID)) {
242 whereConfig = "" + ((WhereAlarm) w).getZone();
245 Map<String, Object> properties = new HashMap<>(2);
247 // detect Thermo CU type
248 if (OpenWebNetBindingConstants.THING_TYPE_BUS_THERMO_CU.equals(thingTypeUID)) {
250 logger.debug("CU found: {}", w);
251 if (w.value().charAt(0) == '#') { // 99-zone CU
252 thingLabel += " 99-zone";
253 logger.debug("@@@@@ THERMO CU found 99-zone: where={}, ownId={}, whereConfig={}", w, ownId,
256 thingLabel += " 4-zone";
257 whereConfig = "#" + w.value();
258 logger.debug("@@@@ THERMO CU found 4-zone: where={}, ownId={}, whereConfig={}", w, ownId, whereConfig);
260 } else if (OpenWebNetBindingConstants.THING_TYPE_BUS_THERMO_ZONE.equals(thingTypeUID)) {
262 // set param standalone = false for thermo zone
263 properties.put(OpenWebNetBindingConstants.CONFIG_PROPERTY_STANDALONE, false);
265 whereConfig = "" + ((WhereThermo) w).getZone();
266 logger.debug("@@@@@ THERMO ZONE found: where={}, ownId={}, whereConfig={}, standalone={}", w, ownId,
267 whereConfig, properties.get(OpenWebNetBindingConstants.CONFIG_PROPERTY_STANDALONE));
270 if (w instanceof WhereZigBee whereZigBee && WhereZigBee.UNIT_02.equals(whereZigBee.getUnit())) {
271 logger.debug("UNIT=02 found (WHERE={}) -> will remove previous result if exists", w);
272 thingRemoved(thingUID); // remove previously discovered thing
273 // re-create thingUID with new type
274 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_ZB_ON_OFF_SWITCH_2UNITS;
275 thingLabel = OpenWebNetBindingConstants.THING_LABEL_ZB_ON_OFF_SWITCH_2UNITS;
276 thingUID = new ThingUID(thingTypeUID, bridgeUID, tId);
277 whereConfig = whereZigBee.valueWithUnit(WhereZigBee.UNIT_ALL); // replace unit '02' with '00'
278 logger.debug("UNIT=02, switching type from {} to {}",
279 OpenWebNetBindingConstants.THING_TYPE_ZB_ON_OFF_SWITCH,
280 OpenWebNetBindingConstants.THING_TYPE_ZB_ON_OFF_SWITCH_2UNITS);
282 properties.put(OpenWebNetBindingConstants.CONFIG_PROPERTY_WHERE, whereConfig);
283 properties.put(OpenWebNetBindingConstants.PROPERTY_OWNID, ownId);
284 if (OpenWebNetBindingConstants.THING_TYPE_GENERIC_DEVICE.equals(thingTypeUID)) {
285 thingLabel = thingLabel + " (WHO=" + deviceWho + ", WHERE=" + whereConfig + ")";
287 thingLabel = thingLabel + " (WHERE=" + whereConfig + ")";
289 discoveryResult = DiscoveryResultBuilder.create(thingUID).withThingType(thingTypeUID).withProperties(properties)
290 .withRepresentationProperty(OpenWebNetBindingConstants.PROPERTY_OWNID).withBridge(bridgeUID)
291 .withLabel(thingLabel).build();
292 thingDiscovered(discoveryResult);
296 public void initialize() {
297 thingHandler.deviceDiscoveryService = this;
298 bridgeUID = thingHandler.getThing().getUID();