]> git.basschouten.com Git - openhab-addons.git/blob
46aafa7db306d700b05006f262a073abe19db998
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2020 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.enocean.internal.discovery;
14
15 import static org.openhab.binding.enocean.internal.EnOceanBindingConstants.*;
16
17 import java.util.Set;
18
19 import org.eclipse.jdt.annotation.NonNull;
20 import org.openhab.binding.enocean.internal.eep.Base.UTEResponse;
21 import org.openhab.binding.enocean.internal.eep.Base._4BSMessage;
22 import org.openhab.binding.enocean.internal.eep.EEP;
23 import org.openhab.binding.enocean.internal.eep.EEPFactory;
24 import org.openhab.binding.enocean.internal.handler.EnOceanBridgeHandler;
25 import org.openhab.binding.enocean.internal.messages.BasePacket;
26 import org.openhab.binding.enocean.internal.messages.ERP1Message;
27 import org.openhab.binding.enocean.internal.messages.ERP1Message.RORG;
28 import org.openhab.binding.enocean.internal.transceiver.PacketListener;
29 import org.openhab.core.config.discovery.AbstractDiscoveryService;
30 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
31 import org.openhab.core.thing.ThingTypeUID;
32 import org.openhab.core.thing.ThingUID;
33 import org.openhab.core.util.HexUtils;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 /**
38  * The {@link EnOceanDeviceDiscoveryService} is used to discover Enocean devices and to accept teach in requests.
39  *
40  * @author Daniel Weber - Initial contribution
41  */
42
43 public class EnOceanDeviceDiscoveryService extends AbstractDiscoveryService implements PacketListener {
44     private final Logger logger = LoggerFactory.getLogger(EnOceanDeviceDiscoveryService.class);
45
46     private EnOceanBridgeHandler bridgeHandler;
47
48     public EnOceanDeviceDiscoveryService(EnOceanBridgeHandler bridgeHandler) {
49         super(null, 60, false);
50         this.bridgeHandler = bridgeHandler;
51     }
52
53     /**
54      * Called on component activation.
55      */
56     public void activate() {
57         super.activate(null);
58     }
59
60     @Override
61     public void deactivate() {
62         super.deactivate();
63     }
64
65     @Override
66     protected void startScan() {
67         if (bridgeHandler == null) {
68             return;
69         }
70
71         logger.info("Starting EnOcean discovery and accepting teach in requests");
72         bridgeHandler.startDiscovery(this);
73     }
74
75     @Override
76     public synchronized void stopScan() {
77         if (bridgeHandler == null) {
78             return;
79         }
80
81         logger.info("Stopping EnOcean discovery scan");
82         bridgeHandler.stopDiscovery();
83         super.stopScan();
84     }
85
86     @Override
87     public Set<@NonNull ThingTypeUID> getSupportedThingTypes() {
88         return SUPPORTED_DEVICE_THING_TYPES_UIDS;
89     }
90
91     @Override
92     public void packetReceived(BasePacket packet) {
93         ERP1Message msg = (ERP1Message) packet;
94
95         logger.info("EnOcean Package discovered, RORG {}, payload {}, additional {}", msg.getRORG().name(),
96                 HexUtils.bytesToHex(msg.getPayload()), HexUtils.bytesToHex(msg.getOptionalPayload()));
97
98         EEP eep = EEPFactory.buildEEPFromTeachInERP1(msg);
99         if (eep == null) {
100             logger.debug("Could not build EEP for received package");
101             return;
102         }
103
104         String enoceanId = HexUtils.bytesToHex(eep.getSenderId());
105         ThingTypeUID thingTypeUID = eep.getThingTypeUID();
106         ThingUID thingUID = new ThingUID(thingTypeUID, bridgeHandler.getThing().getUID(), enoceanId);
107
108         int senderIdOffset = 0;
109         boolean broadcastMessages = true;
110
111         // check for bidirectional communication => do not use broadcast in this case
112         if (msg.getRORG() == RORG.UTE && (msg.getPayload(1, 1)[0]
113                 & UTEResponse.CommunicationType_MASK) == UTEResponse.CommunicationType_MASK) {
114             broadcastMessages = false;
115         }
116
117         // if ute => send response if needed
118         if (msg.getRORG() == RORG.UTE && (msg.getPayload(1, 1)[0] & UTEResponse.ResponseNeeded_MASK) == 0) {
119             logger.info("Sending UTE response to {}", enoceanId);
120             senderIdOffset = sendTeachInResponse(msg, enoceanId);
121         }
122
123         // if 4BS teach in variation 3 => send response
124         if ((eep instanceof _4BSMessage) && ((_4BSMessage) eep).isTeachInVariation3Supported()) {
125             logger.info("Sending 4BS teach in variation 3 response to {}", enoceanId);
126             senderIdOffset = sendTeachInResponse(msg, enoceanId);
127         }
128
129         DiscoveryResultBuilder discoveryResultBuilder = DiscoveryResultBuilder.create(thingUID)
130                 .withRepresentationProperty(enoceanId).withBridge(bridgeHandler.getThing().getUID());
131
132         eep.addConfigPropertiesTo(discoveryResultBuilder);
133         discoveryResultBuilder.withProperty(PARAMETER_BROADCASTMESSAGES, broadcastMessages);
134         discoveryResultBuilder.withProperty(PARAMETER_ENOCEANID, enoceanId);
135
136         if (senderIdOffset > 0) {
137             // advance config with new device id
138             discoveryResultBuilder.withProperty(PARAMETER_SENDERIDOFFSET, senderIdOffset);
139         }
140
141         thingDiscovered(discoveryResultBuilder.build());
142
143         // As we only support sensors to be teached in, we do not need to send a teach in response => 4bs
144         // bidirectional teach in proc is not supported yet
145         // this is true except for UTE teach in => we always have to send a response here
146     }
147
148     private int sendTeachInResponse(ERP1Message msg, String enoceanId) {
149         int offset;
150         // get new sender Id
151         offset = bridgeHandler.getNextSenderId(enoceanId);
152         if (offset > 0) {
153             byte[] newSenderId = bridgeHandler.getBaseId();
154             newSenderId[3] += offset;
155
156             // send response
157             EEP response = EEPFactory.buildResponseEEPFromTeachInERP1(msg, newSenderId);
158             if (response != null) {
159                 bridgeHandler.sendMessage(response.getERP1Message(), null);
160                 logger.info("Teach in response for {} with new senderId {} (= offset {}) sent", enoceanId,
161                         HexUtils.bytesToHex(newSenderId), offset);
162             } else {
163                 logger.warn("Teach in response for enoceanId {} not supported!", enoceanId);
164             }
165         }
166         return offset;
167     }
168
169     @Override
170     public long getSenderIdToListenTo() {
171         // we just want teach in msg, so return zero here
172         return 0;
173     }
174 }