From c33ea1f120d668cfb695e8ac057b752037128534 Mon Sep 17 00:00:00 2001 From: Markus Heberling Date: Mon, 4 Dec 2023 11:10:10 +0100 Subject: [PATCH] [grundfosalpha] Initial contribution (#15907) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [Bluez] Disable automatic filtering of duplicate data * Added Grundfos Alpha binding Signed-off-by: Markus Heberling Signed-off-by: Jørgen Austvik --- CODEOWNERS | 1 + bom/openhab-addons/pom.xml | 5 + .../bluez/internal/BlueZBridgeHandler.java | 16 ++++ .../NOTICE | 13 +++ .../README.md | 49 ++++++++++ .../pom.xml | 25 +++++ .../src/main/feature/feature.xml | 10 ++ .../GrundfosAlphaBindingConstants.java | 36 ++++++++ .../GrundfosAlphaDiscoveryParticipant.java | 88 ++++++++++++++++++ .../internal/GrundfosAlphaHandler.java | 70 ++++++++++++++ .../internal/GrundfosAlphaHandlerFactory.java | 55 +++++++++++ .../OH-INF/i18n/bluetooth.properties | 18 ++++ .../resources/OH-INF/thing/thing-types.xml | 62 +++++++++++++ .../internal/GrundfosAlphaHandlerTest.java | 91 +++++++++++++++++++ bundles/pom.xml | 1 + 15 files changed, 540 insertions(+) create mode 100644 bundles/org.openhab.binding.bluetooth.grundfosalpha/NOTICE create mode 100644 bundles/org.openhab.binding.bluetooth.grundfosalpha/README.md create mode 100644 bundles/org.openhab.binding.bluetooth.grundfosalpha/pom.xml create mode 100644 bundles/org.openhab.binding.bluetooth.grundfosalpha/src/main/feature/feature.xml create mode 100644 bundles/org.openhab.binding.bluetooth.grundfosalpha/src/main/java/org/openhab/binding/bluetooth/grundfosalpha/internal/GrundfosAlphaBindingConstants.java create mode 100644 bundles/org.openhab.binding.bluetooth.grundfosalpha/src/main/java/org/openhab/binding/bluetooth/grundfosalpha/internal/GrundfosAlphaDiscoveryParticipant.java create mode 100644 bundles/org.openhab.binding.bluetooth.grundfosalpha/src/main/java/org/openhab/binding/bluetooth/grundfosalpha/internal/GrundfosAlphaHandler.java create mode 100644 bundles/org.openhab.binding.bluetooth.grundfosalpha/src/main/java/org/openhab/binding/bluetooth/grundfosalpha/internal/GrundfosAlphaHandlerFactory.java create mode 100644 bundles/org.openhab.binding.bluetooth.grundfosalpha/src/main/resources/OH-INF/i18n/bluetooth.properties create mode 100644 bundles/org.openhab.binding.bluetooth.grundfosalpha/src/main/resources/OH-INF/thing/thing-types.xml create mode 100644 bundles/org.openhab.binding.bluetooth.grundfosalpha/src/test/java/org/openhab/binding/bluetooth/grundfosalpha/internal/GrundfosAlphaHandlerTest.java diff --git a/CODEOWNERS b/CODEOWNERS index 53edc8e5f7aa4..887b51cf72a8c 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -47,6 +47,7 @@ /bundles/org.openhab.binding.bluetooth.enoceanble/ @pfink /bundles/org.openhab.binding.bluetooth.generic/ @cpmeister /bundles/org.openhab.binding.bluetooth.govee/ @cpmeister +/bundles/org.openhab.binding.bluetooth.grundfosalpha/ @tisoft /bundles/org.openhab.binding.bluetooth.radoneye/ @petero-dk /bundles/org.openhab.binding.bluetooth.roaming/ @cpmeister /bundles/org.openhab.binding.bluetooth.ruuvitag/ @ssalonen diff --git a/bom/openhab-addons/pom.xml b/bom/openhab-addons/pom.xml index 5b20241b4142f..306356a673c3e 100644 --- a/bom/openhab-addons/pom.xml +++ b/bom/openhab-addons/pom.xml @@ -226,6 +226,11 @@ org.openhab.binding.bluetooth.govee ${project.version} + + org.openhab.addons.bundles + org.openhab.binding.bluetooth.grundfosalpha + ${project.version} + org.openhab.addons.bundles org.openhab.binding.bluetooth.radoneye diff --git a/bundles/org.openhab.binding.bluetooth.bluez/src/main/java/org/openhab/binding/bluetooth/bluez/internal/BlueZBridgeHandler.java b/bundles/org.openhab.binding.bluetooth.bluez/src/main/java/org/openhab/binding/bluetooth/bluez/internal/BlueZBridgeHandler.java index 6903f2d5a63c1..25adffdc92c00 100644 --- a/bundles/org.openhab.binding.bluetooth.bluez/src/main/java/org/openhab/binding/bluetooth/bluez/internal/BlueZBridgeHandler.java +++ b/bundles/org.openhab.binding.bluetooth.bluez/src/main/java/org/openhab/binding/bluetooth/bluez/internal/BlueZBridgeHandler.java @@ -12,13 +12,20 @@ */ package org.openhab.binding.bluetooth.bluez.internal; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.Future; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +import org.bluez.exceptions.BluezFailedException; +import org.bluez.exceptions.BluezInvalidArgumentsException; +import org.bluez.exceptions.BluezNotReadyException; +import org.bluez.exceptions.BluezNotSupportedException; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; +import org.freedesktop.dbus.types.Variant; import org.openhab.binding.bluetooth.AbstractBluetoothBridgeHandler; import org.openhab.binding.bluetooth.BluetoothAddress; import org.openhab.binding.bluetooth.bluez.internal.events.AdapterDiscoveringChangedEvent; @@ -139,6 +146,15 @@ public void dispose() { return null; } + Map> filter = new HashMap<>(); + filter.put("DuplicateData", new Variant<>(true)); + try { + adapter.setDiscoveryFilter(filter); + } catch (BluezInvalidArgumentsException | BluezFailedException | BluezNotSupportedException + | BluezNotReadyException e) { + throw new RuntimeException(e); + } + // now lets make sure that discovery is turned on if (!localAdapter.startDiscovery()) { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "Trying to start discovery"); diff --git a/bundles/org.openhab.binding.bluetooth.grundfosalpha/NOTICE b/bundles/org.openhab.binding.bluetooth.grundfosalpha/NOTICE new file mode 100644 index 0000000000000..38d625e349232 --- /dev/null +++ b/bundles/org.openhab.binding.bluetooth.grundfosalpha/NOTICE @@ -0,0 +1,13 @@ +This content is produced and maintained by the openHAB project. + +* Project home: https://www.openhab.org + +== Declared Project Licenses + +This program and the accompanying materials are made available under the terms +of the Eclipse Public License 2.0 which is available at +https://www.eclipse.org/legal/epl-2.0/. + +== Source Code + +https://github.com/openhab/openhab-addons diff --git a/bundles/org.openhab.binding.bluetooth.grundfosalpha/README.md b/bundles/org.openhab.binding.bluetooth.grundfosalpha/README.md new file mode 100644 index 0000000000000..840411971a55c --- /dev/null +++ b/bundles/org.openhab.binding.bluetooth.grundfosalpha/README.md @@ -0,0 +1,49 @@ +# GrundfosAlpha Binding + +This adds support for reading out the data of Grundfos Alpha Pumps with a [Grundfos Alpha Reader](https://product-selection.grundfos.com/products/alpha-reader) + +The reverse engineering of the protocol was taken from [https://github.com/JsBergbau/AlphaDecoder](https://github.com/JsBergbau/AlphaDecoder). + +## Supported Things + +- `mi401`: The Grundfos MI401 ALPHA Reader + +## Discovery + +All readers are auto-detected as soon as Bluetooth is configured in openHAB and the MI401 device is powered on. + +## Thing Configuration + +### `mi401` Thing Configuration + +| Name | Type | Description | Default | Required | Advanced | +|---------|------|-----------------------------------------------|---------|----------|----------| +| address | text | Bluetooth address in XX:XX:XX:XX:XX:XX format | N/A | yes | no | + +## Channels + +| Channel | Type | Read/Write | Description | +|------------------|---------------------------|------------|------------------------------------| +| rssi | Number | R | Received Signal Strength Indicator | +| flow-rate | Number:VolumetricFlowRate | R | The flow rate of the pump | +| pump-head | Number:Length | R | The water head above the pump | +| pump-temperature | Number:Temperature | R | The temperature of the pump | +| battery-level | Number:Dimensionless | R | The battery level of the reader | + +## Full Example + +grundfos_alpha.things (assuming you have a Bluetooth bridge with the ID `bluetooth:bluegiga:adapter1`: + +```java +bluetooth:mi401:hci0:sensor1 "Grundfos Alpha Reader 1" (bluetooth:bluegiga:adapter1) [ address="12:34:56:78:9A:BC" ] +``` + +grundfos_alpha.items: + +```java +Number RSSI "RSSI [%.1f dBm]" { channel="bluetooth:mi401:hci0:sensor1:rssi" } +Number:VolumetricFlowRate Flow_rate "Flowrate [%.1f %unit%]" { channel="bluetooth:mi401:hci0:sensor1:flow-rate" } +Number:Length Pump_Head "Pump head [%.1f %unit%]" { channel="bluetooth:mi401:hci0:sensor1:pump-head" } +Number:Temperature Pump_Temperature "Temperature [%.1f %unit%]" { channel="bluetooth:mi401:hci0:sensor1:pump-temperature" } +Number:Dimensionless Battery_Level "Battery Level [%d %%]" { channel="bluetooth:mi401:hci0:sensor1:battery-level" } +``` diff --git a/bundles/org.openhab.binding.bluetooth.grundfosalpha/pom.xml b/bundles/org.openhab.binding.bluetooth.grundfosalpha/pom.xml new file mode 100644 index 0000000000000..0d0b5cea5a556 --- /dev/null +++ b/bundles/org.openhab.binding.bluetooth.grundfosalpha/pom.xml @@ -0,0 +1,25 @@ + + + + 4.0.0 + + + org.openhab.addons.bundles + org.openhab.addons.reactor.bundles + 4.1.0-SNAPSHOT + + + org.openhab.binding.bluetooth.grundfosalpha + + openHAB Add-ons :: Bundles :: GrundfosAlpha Binding + + + + org.openhab.addons.bundles + org.openhab.binding.bluetooth + ${project.version} + provided + + + diff --git a/bundles/org.openhab.binding.bluetooth.grundfosalpha/src/main/feature/feature.xml b/bundles/org.openhab.binding.bluetooth.grundfosalpha/src/main/feature/feature.xml new file mode 100644 index 0000000000000..0a09c41c49dcd --- /dev/null +++ b/bundles/org.openhab.binding.bluetooth.grundfosalpha/src/main/feature/feature.xml @@ -0,0 +1,10 @@ + + + mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features + + + openhab-runtime-base + mvn:org.openhab.addons.bundles/org.openhab.binding.bluetooth/${project.version} + mvn:org.openhab.addons.bundles/org.openhab.binding.bluetooth.grundfosalpha/${project.version} + + diff --git a/bundles/org.openhab.binding.bluetooth.grundfosalpha/src/main/java/org/openhab/binding/bluetooth/grundfosalpha/internal/GrundfosAlphaBindingConstants.java b/bundles/org.openhab.binding.bluetooth.grundfosalpha/src/main/java/org/openhab/binding/bluetooth/grundfosalpha/internal/GrundfosAlphaBindingConstants.java new file mode 100644 index 0000000000000..f5eb64a5c5d31 --- /dev/null +++ b/bundles/org.openhab.binding.bluetooth.grundfosalpha/src/main/java/org/openhab/binding/bluetooth/grundfosalpha/internal/GrundfosAlphaBindingConstants.java @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2010-2023 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.bluetooth.grundfosalpha.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.bluetooth.BluetoothBindingConstants; +import org.openhab.core.thing.ThingTypeUID; + +/** + * The {@link GrundfosAlphaBindingConstants} class defines common constants, which are + * used across the whole binding. + * + * @author Markus Heberling - Initial contribution + */ +@NonNullByDefault +public class GrundfosAlphaBindingConstants { + + // List of all Thing Type UIDs + public static final ThingTypeUID THING_TYPE_MI401 = new ThingTypeUID(BluetoothBindingConstants.BINDING_ID, "mi401"); + + // List of all Channel ids + public static final String CHANNEL_TYPE_FLOW_RATE = "flow-rate"; + public static final String CHANNEL_TYPE_PUMP_HEAD = "pump-head"; + public static final String CHANNEL_TYPE_BATTERY_LEVEL = "battery-level"; + public static final String CHANNEL_TYPE_PUMP_TEMPERATUR = "pump-temperature"; +} diff --git a/bundles/org.openhab.binding.bluetooth.grundfosalpha/src/main/java/org/openhab/binding/bluetooth/grundfosalpha/internal/GrundfosAlphaDiscoveryParticipant.java b/bundles/org.openhab.binding.bluetooth.grundfosalpha/src/main/java/org/openhab/binding/bluetooth/grundfosalpha/internal/GrundfosAlphaDiscoveryParticipant.java new file mode 100644 index 0000000000000..cefdd8367bb0d --- /dev/null +++ b/bundles/org.openhab.binding.bluetooth.grundfosalpha/src/main/java/org/openhab/binding/bluetooth/grundfosalpha/internal/GrundfosAlphaDiscoveryParticipant.java @@ -0,0 +1,88 @@ +/** + * Copyright (c) 2010-2023 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.bluetooth.grundfosalpha.internal; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.bluetooth.BluetoothBindingConstants; +import org.openhab.binding.bluetooth.discovery.BluetoothDiscoveryDevice; +import org.openhab.binding.bluetooth.discovery.BluetoothDiscoveryParticipant; +import org.openhab.core.config.discovery.DiscoveryResult; +import org.openhab.core.config.discovery.DiscoveryResultBuilder; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingTypeUID; +import org.openhab.core.thing.ThingUID; +import org.osgi.service.component.annotations.Component; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This discovery participant is able to recognize Grundfos Alpha devices and create discovery results for them. + * + * @author Markus Heberling - Initial contribution + * + */ +@NonNullByDefault +@Component +public class GrundfosAlphaDiscoveryParticipant implements BluetoothDiscoveryParticipant { + private final Logger logger = LoggerFactory.getLogger(GrundfosAlphaDiscoveryParticipant.class); + + @Override + public Set getSupportedThingTypeUIDs() { + return Set.of(GrundfosAlphaBindingConstants.THING_TYPE_MI401); + } + + @Override + public boolean requiresConnection(BluetoothDiscoveryDevice device) { + return false; + } + + @Override + public @Nullable ThingUID getThingUID(BluetoothDiscoveryDevice device) { + Integer manufacturerId = device.getManufacturerId(); + @Nullable + String name = device.getName(); + logger.debug("Discovered device {} with manufacturerId {} and name {}", device.getAddress(), manufacturerId, + name); + if ("MI401".equals(name)) { + return new ThingUID(GrundfosAlphaBindingConstants.THING_TYPE_MI401, device.getAdapter().getUID(), + device.getAddress().toString().toLowerCase().replace(":", "")); + } + return null; + } + + @Override + public @Nullable DiscoveryResult createResult(BluetoothDiscoveryDevice device) { + ThingUID thingUID = getThingUID(device); + if (thingUID == null) { + return null; + } + String label = "Grundfos Alpha Reader MI401"; + Map properties = new HashMap<>(); + properties.put(BluetoothBindingConstants.CONFIGURATION_ADDRESS, device.getAddress().toString()); + properties.put(Thing.PROPERTY_VENDOR, "Grundfos"); + Integer txPower = device.getTxPower(); + if (txPower != null) { + properties.put(BluetoothBindingConstants.PROPERTY_TXPOWER, Integer.toString(txPower)); + } + + // Create the discovery result and add to the inbox + return DiscoveryResultBuilder.create(thingUID).withProperties(properties) + .withRepresentationProperty(BluetoothBindingConstants.CONFIGURATION_ADDRESS) + .withBridge(device.getAdapter().getUID()).withLabel(label).build(); + } +} diff --git a/bundles/org.openhab.binding.bluetooth.grundfosalpha/src/main/java/org/openhab/binding/bluetooth/grundfosalpha/internal/GrundfosAlphaHandler.java b/bundles/org.openhab.binding.bluetooth.grundfosalpha/src/main/java/org/openhab/binding/bluetooth/grundfosalpha/internal/GrundfosAlphaHandler.java new file mode 100644 index 0000000000000..ac77c4dcf851f --- /dev/null +++ b/bundles/org.openhab.binding.bluetooth.grundfosalpha/src/main/java/org/openhab/binding/bluetooth/grundfosalpha/internal/GrundfosAlphaHandler.java @@ -0,0 +1,70 @@ +/** + * Copyright (c) 2010-2023 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.bluetooth.grundfosalpha.internal; + +import static org.openhab.binding.bluetooth.grundfosalpha.internal.GrundfosAlphaBindingConstants.*; + +import javax.measure.quantity.Dimensionless; +import javax.measure.quantity.Length; +import javax.measure.quantity.Temperature; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.bluetooth.BeaconBluetoothHandler; +import org.openhab.binding.bluetooth.BluetoothDeviceListener; +import org.openhab.binding.bluetooth.notification.BluetoothScanNotification; +import org.openhab.core.library.dimension.VolumetricFlowRate; +import org.openhab.core.library.types.QuantityType; +import org.openhab.core.library.unit.SIUnits; +import org.openhab.core.library.unit.Units; +import org.openhab.core.thing.Thing; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The {@link GrundfosAlphaHandler} is responsible for handling commands, which are + * sent to one of the channels. + * + * @author Markus Heberling - Initial contribution + */ +@NonNullByDefault +public class GrundfosAlphaHandler extends BeaconBluetoothHandler implements BluetoothDeviceListener { + + private final Logger logger = LoggerFactory.getLogger(GrundfosAlphaHandler.class); + + public GrundfosAlphaHandler(Thing thing) { + super(thing); + } + + @Override + public void onScanRecordReceived(BluetoothScanNotification scanNotification) { + super.onScanRecordReceived(scanNotification); + byte[] data = scanNotification.getManufacturerData(); + if (data != null && data.length == 21) { + int batteryLevel = (data[5] & 0xFF) * 25; + QuantityType quantity = new QuantityType<>(batteryLevel, Units.PERCENT); + updateState(CHANNEL_TYPE_BATTERY_LEVEL, quantity); + + float flowRate = ((data[9] & 0xFF) << 8 | (data[8] & 0xFF)) / 6553.5f; + QuantityType quantity2 = new QuantityType<>(flowRate, Units.CUBICMETRE_PER_HOUR); + updateState(CHANNEL_TYPE_FLOW_RATE, quantity2); + + float pumpHead = ((data[11] & 0xFF) << 8 | (data[10] & 0xFF)) / 3276.7f; + QuantityType quantity3 = new QuantityType<>(pumpHead, SIUnits.METRE); + updateState(CHANNEL_TYPE_PUMP_HEAD, quantity3); + + float pumpTemperature = data[14] & 0xFF; + QuantityType quantity4 = new QuantityType<>(pumpTemperature, SIUnits.CELSIUS); + updateState(CHANNEL_TYPE_PUMP_TEMPERATUR, quantity4); + } + } +} diff --git a/bundles/org.openhab.binding.bluetooth.grundfosalpha/src/main/java/org/openhab/binding/bluetooth/grundfosalpha/internal/GrundfosAlphaHandlerFactory.java b/bundles/org.openhab.binding.bluetooth.grundfosalpha/src/main/java/org/openhab/binding/bluetooth/grundfosalpha/internal/GrundfosAlphaHandlerFactory.java new file mode 100644 index 0000000000000..ac0983bb9c3ed --- /dev/null +++ b/bundles/org.openhab.binding.bluetooth.grundfosalpha/src/main/java/org/openhab/binding/bluetooth/grundfosalpha/internal/GrundfosAlphaHandlerFactory.java @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2010-2023 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.bluetooth.grundfosalpha.internal; + +import static org.openhab.binding.bluetooth.grundfosalpha.internal.GrundfosAlphaBindingConstants.*; + +import java.util.Set; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingTypeUID; +import org.openhab.core.thing.binding.BaseThingHandlerFactory; +import org.openhab.core.thing.binding.ThingHandler; +import org.openhab.core.thing.binding.ThingHandlerFactory; +import org.osgi.service.component.annotations.Component; + +/** + * The {@link GrundfosAlphaHandlerFactory} is responsible for creating things and thing + * handlers. + * + * @author Markus Heberling - Initial contribution + */ +@NonNullByDefault +@Component(configurationPid = "binding.bluetooth.grundfosalpha", service = ThingHandlerFactory.class) +public class GrundfosAlphaHandlerFactory extends BaseThingHandlerFactory { + + private static final Set SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_MI401); + + @Override + public boolean supportsThingType(ThingTypeUID thingTypeUID) { + return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID); + } + + @Override + protected @Nullable ThingHandler createHandler(Thing thing) { + ThingTypeUID thingTypeUID = thing.getThingTypeUID(); + + if (THING_TYPE_MI401.equals(thingTypeUID)) { + return new GrundfosAlphaHandler(thing); + } + + return null; + } +} diff --git a/bundles/org.openhab.binding.bluetooth.grundfosalpha/src/main/resources/OH-INF/i18n/bluetooth.properties b/bundles/org.openhab.binding.bluetooth.grundfosalpha/src/main/resources/OH-INF/i18n/bluetooth.properties new file mode 100644 index 0000000000000..aac110918b671 --- /dev/null +++ b/bundles/org.openhab.binding.bluetooth.grundfosalpha/src/main/resources/OH-INF/i18n/bluetooth.properties @@ -0,0 +1,18 @@ +# thing types + +thing-type.bluetooth.mi401.label = Grundfos Alpha Reader MI401 +thing-type.bluetooth.mi401.description = A Grundfos Alpha Reader MI401 + +# thing types config + +thing-type.config.bluetooth.mi401.address.label = Address +thing-type.config.bluetooth.mi401.address.description = Bluetooth address in XX:XX:XX:XX:XX:XX format + +# channel types + +channel-type.bluetooth.grundfos-flow.label = Current Flow +channel-type.bluetooth.grundfos-flow.description = Current flow +channel-type.bluetooth.grundfos-head.label = Current Head +channel-type.bluetooth.grundfos-head.description = Current head +channel-type.bluetooth.grundfos-temperature.label = Current Pump Temperature +channel-type.bluetooth.grundfos-temperature.description = Current pump temperature diff --git a/bundles/org.openhab.binding.bluetooth.grundfosalpha/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.bluetooth.grundfosalpha/src/main/resources/OH-INF/thing/thing-types.xml new file mode 100644 index 0000000000000..61b2f20810d32 --- /dev/null +++ b/bundles/org.openhab.binding.bluetooth.grundfosalpha/src/main/resources/OH-INF/thing/thing-types.xml @@ -0,0 +1,62 @@ + + + + + Number:VolumetricFlowRate + + Current flow + Flow + + + + + Number:Length + + Current head + Water + + + + + Number:Temperature + + Current pump temperature + Temperature + + Measurement + Temperature + + + + + + + + + + + + + A Grundfos Alpha Reader MI401 + Pump + + + + + + + + + + + + + Bluetooth address in XX:XX:XX:XX:XX:XX format + + + + + diff --git a/bundles/org.openhab.binding.bluetooth.grundfosalpha/src/test/java/org/openhab/binding/bluetooth/grundfosalpha/internal/GrundfosAlphaHandlerTest.java b/bundles/org.openhab.binding.bluetooth.grundfosalpha/src/test/java/org/openhab/binding/bluetooth/grundfosalpha/internal/GrundfosAlphaHandlerTest.java new file mode 100644 index 0000000000000..840450a86d83e --- /dev/null +++ b/bundles/org.openhab.binding.bluetooth.grundfosalpha/src/test/java/org/openhab/binding/bluetooth/grundfosalpha/internal/GrundfosAlphaHandlerTest.java @@ -0,0 +1,91 @@ +/** + * Copyright (c) 2010-2023 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.bluetooth.grundfosalpha.internal; + +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.openhab.binding.bluetooth.notification.BluetoothScanNotification; +import org.openhab.core.library.types.QuantityType; +import org.openhab.core.library.unit.SIUnits; +import org.openhab.core.library.unit.Units; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingStatus; +import org.openhab.core.thing.ThingStatusDetail; +import org.openhab.core.thing.ThingStatusInfo; +import org.openhab.core.thing.ThingUID; +import org.openhab.core.thing.binding.ThingHandlerCallback; +import org.openhab.core.util.HexUtils; + +/** + * Test the {@link GrundfosAlphaHandler}. + * + * @author Markus Heberling - Initial contribution + */ +@ExtendWith(MockitoExtension.class) +class GrundfosAlphaHandlerTest { + + private @Mock Thing thingMock; + + private @Mock ThingHandlerCallback callback; + + @Test + public void testMessageType0xf1() { + byte[] data = HexUtils.hexToBytes("15f130017a5113030300994109589916613003004005"); + final BluetoothScanNotification scanNotification = new BluetoothScanNotification(); + scanNotification.setManufacturerData(data); + final GrundfosAlphaHandler handler = new GrundfosAlphaHandler(thingMock); + handler.setCallback(callback); + handler.onScanRecordReceived(scanNotification); + + verify(callback).statusUpdated(thingMock, + new ThingStatusInfo(ThingStatus.ONLINE, ThingStatusDetail.NONE, null)); + + verifyNoMoreInteractions(callback); + } + + @Test + public void testMessageType0xf2() { + when(thingMock.getUID()).thenReturn(new ThingUID(GrundfosAlphaBindingConstants.THING_TYPE_MI401, "dummy")); + + byte[] data = HexUtils.hexToBytes("14f23001650305065419b9180f011f007c1878170d"); + final BluetoothScanNotification scanNotification = new BluetoothScanNotification(); + scanNotification.setManufacturerData(data); + final GrundfosAlphaHandler handler = new GrundfosAlphaHandler(thingMock); + handler.setCallback(callback); + handler.onScanRecordReceived(scanNotification); + + verify(callback).statusUpdated(thingMock, + new ThingStatusInfo(ThingStatus.ONLINE, ThingStatusDetail.NONE, null)); + verify(callback).stateUpdated( + new ChannelUID(thingMock.getUID(), GrundfosAlphaBindingConstants.CHANNEL_TYPE_BATTERY_LEVEL), + new QuantityType<>(75, Units.PERCENT)); + verify(callback).stateUpdated( + new ChannelUID(thingMock.getUID(), GrundfosAlphaBindingConstants.CHANNEL_TYPE_FLOW_RATE), + new QuantityType<>(0.98939496, Units.CUBICMETRE_PER_HOUR)); + verify(callback).stateUpdated( + new ChannelUID(thingMock.getUID(), GrundfosAlphaBindingConstants.CHANNEL_TYPE_PUMP_HEAD), + new QuantityType<>(1.9315165, SIUnits.METRE)); + verify(callback).stateUpdated( + new ChannelUID(thingMock.getUID(), GrundfosAlphaBindingConstants.CHANNEL_TYPE_PUMP_TEMPERATUR), + new QuantityType<>(31, SIUnits.CELSIUS)); + + verifyNoMoreInteractions(callback); + } +} diff --git a/bundles/pom.xml b/bundles/pom.xml index 64ac470d63251..3e89512ab55c4 100644 --- a/bundles/pom.xml +++ b/bundles/pom.xml @@ -79,6 +79,7 @@ org.openhab.binding.bluetooth.enoceanble org.openhab.binding.bluetooth.generic org.openhab.binding.bluetooth.govee + org.openhab.binding.bluetooth.grundfosalpha org.openhab.binding.bluetooth.radoneye org.openhab.binding.bluetooth.roaming org.openhab.binding.bluetooth.ruuvitag