]> git.basschouten.com Git - openhab-addons.git/blob
553335011393720f4b706c5608c70e8481f469b0
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2024 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.openwebnet.internal.discovery;
14
15 import java.util.HashMap;
16 import java.util.Map;
17 import java.util.Set;
18
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;
39
40 /**
41  * The {@link OpenWebNetDeviceDiscoveryService} is responsible for discovering
42  * OpenWebNet devices connected to a bridge/gateway
43  *
44  * @author Massimo Valla - Initial contribution
45  * @author Andrea Conte - Energy management, Thermoregulation
46  * @author Gilberto Cocchi - Thermoregulation
47  * @author Giovanni Fabiani - Aux support
48  */
49 @Component(scope = ServiceScope.PROTOTYPE, service = OpenWebNetDeviceDiscoveryService.class)
50 @NonNullByDefault
51 public class OpenWebNetDeviceDiscoveryService extends AbstractThingHandlerDiscoveryService<OpenWebNetBridgeHandler> {
52     private final Logger logger = LoggerFactory.getLogger(OpenWebNetDeviceDiscoveryService.class);
53
54     private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = OpenWebNetBindingConstants.DEVICE_SUPPORTED_THING_TYPES;
55     private static final int SEARCH_TIME_SEC = 60;
56
57     private @NonNullByDefault({}) ThingUID bridgeUID;
58
59     private boolean cuFound = false;
60
61     public OpenWebNetDeviceDiscoveryService() {
62         super(OpenWebNetBridgeHandler.class, SUPPORTED_THING_TYPES, SEARCH_TIME_SEC);
63     }
64
65     @Override
66     public Set<ThingTypeUID> getSupportedThingTypes() {
67         return SUPPORTED_THING_TYPES;
68     }
69
70     @Override
71     protected void startScan() {
72         logger.info("------ SEARCHING for DEVICES on bridge '{}' ({}) ...", thingHandler.getThing().getLabel(),
73                 bridgeUID);
74         cuFound = false;
75         thingHandler.searchDevices();
76     }
77
78     @Override
79     protected void stopScan() {
80         logger.debug("------ stopScan() on bridge '{}'", bridgeUID);
81         thingHandler.scanStopped();
82     }
83
84     @Override
85     public void abortScan() {
86         logger.debug("------ abortScan() on bridge '{}'", bridgeUID);
87         thingHandler.scanStopped();
88     }
89
90     /**
91      * Create and notify to Inbox a new DiscoveryResult based on WHERE,
92      * OpenDeviceType and BaseOpenMessage
93      *
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
97      *            (optional)
98      */
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;
110                 break;
111             case ZIGBEE_DIMMER_SWITCH:
112                 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_ZB_DIMMER;
113                 thingLabel = OpenWebNetBindingConstants.THING_LABEL_ZB_DIMMER;
114                 deviceWho = Who.LIGHTING;
115                 break;
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;
120                 break;
121             case SCS_DIMMER_SWITCH:
122                 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_BUS_DIMMER;
123                 thingLabel = OpenWebNetBindingConstants.THING_LABEL_BUS_DIMMER;
124                 deviceWho = Who.LIGHTING;
125                 break;
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;
131                 break;
132             }
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;
138                 break;
139             }
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;
144                 break;
145             }
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;
150                 break;
151             }
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;
156                 break;
157             }
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;
162                 break;
163             }
164             case BASIC_SCENARIO: {
165                 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_BUS_SCENARIO;
166                 thingLabel = OpenWebNetBindingConstants.THING_LABEL_BUS_SCENARIO;
167                 deviceWho = Who.SCENARIO;
168                 break;
169             }
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;
174                 break;
175             }
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;
180                 break;
181             }
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;
186                 break;
187             }
188             case SCS_AUXILIARY_TOGGLE_CONTROL: {
189                 thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_BUS_AUX;
190                 thingLabel = OpenWebNetBindingConstants.THING_LABEL_BUS_AUX;
191                 deviceWho = Who.AUX;
192                 break;
193             }
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;
198                 break;
199             }
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;
204                 break;
205             }
206             default:
207                 logger.warn("Device type {} is not supported, default to GENERIC device (WHERE={})", deviceType, where);
208                 if (where instanceof WhereZigBee) {
209                     thingLabel = "Zigbee " + thingLabel;
210                 }
211                 if (baseMsg != null) {
212                     deviceWho = baseMsg.getWho();
213                 }
214         }
215         Where w;
216         if (where != null) {
217             w = where;
218         } else if (OpenWebNetBindingConstants.THING_TYPE_BUS_ALARM_SYSTEM.equals(thingTypeUID)) {
219             w = new WhereAlarm("0");
220         } else {
221             logger.debug("ignoring newDiscoveryResult with null where: {}", baseMsg);
222             return;
223         }
224
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);
229                 return;
230             }
231         }
232
233         String tId = thingHandler.thingIdFromWhere(w);
234         ThingUID thingUID = new ThingUID(thingTypeUID, bridgeUID, tId);
235
236         DiscoveryResult discoveryResult = null;
237
238         String whereConfig = w.value();
239
240         // remove # from discovered alarm zone
241         if (OpenWebNetBindingConstants.THING_TYPE_BUS_ALARM_ZONE.equals(thingTypeUID)) {
242             whereConfig = "" + ((WhereAlarm) w).getZone();
243         }
244
245         Map<String, Object> properties = new HashMap<>(2);
246
247         // detect Thermo CU type
248         if (OpenWebNetBindingConstants.THING_TYPE_BUS_THERMO_CU.equals(thingTypeUID)) {
249             cuFound = true;
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,
254                         whereConfig);
255             } else {
256                 thingLabel += " 4-zone";
257                 whereConfig = "#" + w.value();
258                 logger.debug("@@@@ THERMO CU found 4-zone: where={}, ownId={}, whereConfig={}", w, ownId, whereConfig);
259             }
260         } else if (OpenWebNetBindingConstants.THING_TYPE_BUS_THERMO_ZONE.equals(thingTypeUID)) {
261             if (cuFound) {
262                 // set param standalone = false for thermo zone
263                 properties.put(OpenWebNetBindingConstants.CONFIG_PROPERTY_STANDALONE, false);
264             }
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));
268         }
269
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);
281         }
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 + ")";
286         } else {
287             thingLabel = thingLabel + " (WHERE=" + whereConfig + ")";
288         }
289         discoveryResult = DiscoveryResultBuilder.create(thingUID).withThingType(thingTypeUID).withProperties(properties)
290                 .withRepresentationProperty(OpenWebNetBindingConstants.PROPERTY_OWNID).withBridge(bridgeUID)
291                 .withLabel(thingLabel).build();
292         thingDiscovered(discoveryResult);
293     }
294
295     @Override
296     public void initialize() {
297         thingHandler.deviceDiscoveryService = this;
298         bridgeUID = thingHandler.getThing().getUID();
299         super.initialize();
300     }
301 }