]> git.basschouten.com Git - openhab-addons.git/blob
8d9d09bad13b4b58e402ada9f9fba00ed2a620e2
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 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
14 package org.openhab.binding.mqtt.ruuvigateway.internal.discovery;
15
16 import static org.openhab.binding.mqtt.ruuvigateway.internal.RuuviGatewayBindingConstants.*;
17
18 import java.util.HashMap;
19 import java.util.Map;
20 import java.util.function.Predicate;
21 import java.util.regex.Pattern;
22
23 import org.eclipse.jdt.annotation.NonNullByDefault;
24 import org.openhab.binding.mqtt.discovery.AbstractMQTTDiscovery;
25 import org.openhab.binding.mqtt.discovery.MQTTTopicDiscoveryService;
26 import org.openhab.binding.mqtt.ruuvigateway.internal.RuuviGatewayBindingConstants;
27 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
28 import org.openhab.core.config.discovery.DiscoveryService;
29 import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
30 import org.openhab.core.thing.Thing;
31 import org.openhab.core.thing.ThingUID;
32 import org.osgi.service.component.annotations.Activate;
33 import org.osgi.service.component.annotations.Component;
34 import org.osgi.service.component.annotations.Reference;
35
36 /**
37  * The {@link RuuviGatewayDiscoveryService} is responsible for finding Ruuvi Tag Sensors
38  * and setting them up for the handlers.
39  *
40  * @author Matthew Skinner - Initial contribution
41  * @author Sami Salonen - Adaptation to Ruuvi Gateway
42  */
43 @Component(service = DiscoveryService.class, configurationPid = "discovery.mqttruuvigateway")
44 @NonNullByDefault
45 public class RuuviGatewayDiscoveryService extends AbstractMQTTDiscovery {
46     protected final MQTTTopicDiscoveryService discoveryService;
47
48     private static final Predicate<String> HEX_PATTERN_CHECKER = Pattern
49             .compile("^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$").asMatchPredicate();
50
51     @Activate
52     public RuuviGatewayDiscoveryService(@Reference MQTTTopicDiscoveryService discoveryService) {
53         super(SUPPORTED_THING_TYPES_UIDS, 3, true, BASE_TOPIC + "#");
54         this.discoveryService = discoveryService;
55     }
56
57     @Override
58     protected MQTTTopicDiscoveryService getDiscoveryService() {
59         return discoveryService;
60     }
61
62     @Override
63     public void receivedMessage(ThingUID connectionBridge, MqttBrokerConnection connection, String topic,
64             byte[] payload) {
65         resetTimeout();
66         if (topic.startsWith(BASE_TOPIC)) {
67             String cutTopic = topic.replace(BASE_TOPIC, "");
68             int index = cutTopic.lastIndexOf("/");
69             if (index != -1) // -1 means "not found"
70             {
71                 String tagMacAddress = cutTopic.substring(index + 1);
72                 if (looksLikeMac(tagMacAddress)) {
73                     publishDevice(connectionBridge, connection, topic, tagMacAddress);
74                 }
75             }
76         }
77     }
78
79     void publishDevice(ThingUID connectionBridge, MqttBrokerConnection connection, String topic, String tagMacAddress) {
80         Map<String, Object> properties = new HashMap<>();
81         String thingID = tagMacAddress.toLowerCase().replaceAll("[:-]", "");
82         String normalizedTagID = normalizedTagID(tagMacAddress);
83         properties.put(RuuviGatewayBindingConstants.CONFIGURATION_PROPERTY_TOPIC, topic);
84         properties.put(RuuviGatewayBindingConstants.PROPERTY_TAG_ID, normalizedTagID);
85         properties.put(Thing.PROPERTY_VENDOR, "Ruuvi Innovations Ltd (Oy)");
86
87         // Discovered things are identified with their topic name, in case of having pathological case
88         // where we find multiple tags with same mac address (e.g. ruuvi/gw1/mac1 and ruuvi/gw2/mac1)
89         thingDiscovered(DiscoveryResultBuilder.create(new ThingUID(THING_TYPE_BEACON, connectionBridge, thingID))
90                 .withProperties(properties)
91                 .withRepresentationProperty(RuuviGatewayBindingConstants.CONFIGURATION_PROPERTY_TOPIC)
92                 .withBridge(connectionBridge).withLabel("MQTT Ruuvi Tag " + normalizedTagID).build());
93     }
94
95     @Override
96     public void topicVanished(ThingUID connectionBridge, MqttBrokerConnection connection, String topic) {
97     }
98
99     private boolean looksLikeMac(String topic) {
100         return HEX_PATTERN_CHECKER.test(topic);
101     }
102
103     private static String normalizedTagID(String mac) {
104         String nondelimited = mac.toUpperCase().replaceAll("[:-]", "");
105         assert nondelimited.length() == 12; // Invariant: method to be used only with valid Ruuvi MACs
106         return nondelimited.subSequence(0, 2) + ":" + nondelimited.subSequence(2, 4) + ":"
107                 + nondelimited.subSequence(4, 6) + ":" + nondelimited.subSequence(6, 8) + ":"
108                 + nondelimited.subSequence(8, 10) + ":" + nondelimited.subSequence(10, 12);
109     }
110 }