Skip to content

Commit

Permalink
applications: Matter Bridge: added BLE environmental sensor support
Browse files Browse the repository at this point in the history
* Added implementation of the BLE data provider which supports
  subscription to the humidity and temperature characteristics.
* implemented one provider to many Matter devices relation
* updated README

Signed-off-by: Marcin Kajor <marcin.kajor@nordicsemi.no>
  • Loading branch information
markaj-nordic committed Aug 25, 2023
1 parent 680a3d1 commit d583ba6
Show file tree
Hide file tree
Showing 24 changed files with 762 additions and 211 deletions.
21 changes: 20 additions & 1 deletion applications/matter_bridge/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ target_sources(app PRIVATE
src/main.cpp
src/bridge_shell.cpp
${COMMON_ROOT}/src/bridge/bridge_manager.cpp
${COMMON_ROOT}/src/bridge/bridged_device.cpp
${COMMON_ROOT}/src/bridge/matter_bridged_device.cpp
${COMMON_ROOT}/src/bridge/bridge_storage_manager.cpp
${COMMON_ROOT}/src/bridge/bridged_device_data_provider.cpp
src/zap-generated/IMClusterCommandHandler.cpp
Expand All @@ -63,6 +63,25 @@ if(CONFIG_BRIDGE_ONOFF_LIGHT_BRIDGED_DEVICE)
)
endif() # CONFIG_BRIDGE_ONOFF_LIGHT_BRIDGED_DEVICE

if(CONFIG_BRIDGE_HUMIDITY_SENSOR_BRIDGED_DEVICE)
target_sources(app PRIVATE
src/bridged_device_types/humidity_sensor.cpp
)
endif() # CONFIG_BRIDGE_HUMIDITY_SENSOR_BRIDGED_DEVICE

if(CONFIG_BRIDGE_TEMPERATURE_SENSOR_BRIDGED_DEVICE)
target_sources(app PRIVATE
src/bridged_device_types/temperature_sensor.cpp
)
endif() # CONFIG_BRIDGE_TEMPERATURE_SENSOR_BRIDGED_DEVICE

# Assume it makes no sense to support BLE environmental sensor without all Matter counterparts
if(CONFIG_BRIDGE_TEMPERATURE_SENSOR_BRIDGED_DEVICE AND CONFIG_BRIDGE_HUMIDITY_SENSOR_BRIDGED_DEVICE)
target_sources(app PRIVATE
src/bridged_device_types/ble_environmental_data_provider.cpp
)
endif() # CONFIG_BRIDGE_TEMPERATURE_SENSOR_BRIDGED_DEVICE AND CONFIG_BRIDGE_HUMIDITY_SENSOR_BRIDGED_DEVICE

else()
if(CONFIG_BRIDGE_ONOFF_LIGHT_BRIDGED_DEVICE)
target_sources(app PRIVATE
Expand Down
10 changes: 7 additions & 3 deletions applications/matter_bridge/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ config BRIDGE_ONOFF_LIGHT_BRIDGED_DEVICE

config BRIDGE_TEMPERATURE_SENSOR_BRIDGED_DEVICE
bool "Support for Temperature Sensor bridged device"
default y if BRIDGED_DEVICE_SIMULATED
default y

config BRIDGE_HUMIDITY_SENSOR_BRIDGED_DEVICE
bool "Support for Humidity Sensor bridged device"
default y if BRIDGED_DEVICE_SIMULATED
default y

choice BRIDGED_DEVICE_IMPLEMENTATION
prompt "Bridged Device implementation"
Expand Down Expand Up @@ -53,14 +53,18 @@ config BT_SCAN_FILTER_ENABLE

# Configure how many Bluetooth LE service UUIDs the Matter bridge can scan.
config BT_SCAN_UUID_CNT
default 1
default 2

config BT_GATT_CLIENT
default y

config BT_GATT_DM
default y

config BRIDGE_BLE_DEVICE_POLLING_INTERVAL
int "BLE humidity measurement readout polling interval in ms"
default 3000

endif

if BRIDGE_TEMPERATURE_SENSOR_BRIDGED_DEVICE
Expand Down
35 changes: 31 additions & 4 deletions applications/matter_bridge/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,12 @@ The application supports the following development kits:

To test the Matter bridge application with the :ref:`Bluetooth LE bridged device <matter_bridge_app_bridged_support>`, you also need the following:

* An additional development kit compatible with the :ref:`peripheral_lbs` sample.
* A micro USB cable to connect the development kit to the PC.
* An additional development kit compatible with one of the following Bluetooth LE samples:

* :ref:`peripheral_lbs`
* :ref:`peripheral_esp`

* A micro-USB cable to connect the development kit to the PC.

To commission the Matter bridge device and control it remotely through a Wi-Fi network, you also need a Matter controller device :ref:`configured on PC or smartphone <ug_matter_configuring>`.
This requires additional hardware depending on your setup.
Expand Down Expand Up @@ -182,6 +186,7 @@ Adding a Bluetooth LE bridged device to the Matter bridge
The argument is mandatory and accepts the following values:

* ``256`` - On/Off Light.
* ``291`` - Environmental Sensor (a combination of Temperature Sensor and Humidity Sensor).

* *<ble_device_index>* is the Bluetooth LE device index on the list returned by the ``scan`` command.
The argument is mandatory and accepts only the values returned by the ``scan`` command.
Expand Down Expand Up @@ -329,8 +334,12 @@ After building the sample and programming it to your development kit, complete t
.. group-tab:: Testing with Bluetooth LE bridged devices

a. Build and program the :ref:`peripheral_lbs` sample to an additional development kit compatible with the sample.
#. Connect the development kit that is running the :ref:`peripheral_lbs` sample to the PC.
a. Build and program the one of the following Bluetooth LE samples to an additional development kit compatible with the sample:

* :ref:`peripheral_lbs`
* :ref:`peripheral_esp`

#. Connect the development kit that is running the Bluetooth LE sample to the PC.
#. Using the terminal emulator connected to the bridge, run the following :ref:`Matter CLI command <matter_bridge_cli>` to scan for available Bluetooth LE devices:

.. code-block:: console
Expand Down Expand Up @@ -373,6 +382,8 @@ After building the sample and programming it to your development kit, complete t
I: Adding OnOff Light bridged device
I: Added device to dynamic endpoint 3 (index=0)
For the Environmental Sensor, two endpoints are created: one implements the Temperature Sensor, and the other implements the Humidity Sensor.

#. Write down the value for the bridged device dynamic endpoint ID.
This is going to be used in the next steps (*<bridged_device_endpoint_ID>*).
#. Use the :doc:`CHIP Tool <matter:chip_tool_guide>` to read the value of an attribute from the bridged device endpoint.
Expand All @@ -383,6 +394,22 @@ After building the sample and programming it to your development kit, complete t
./chip-tool onoff read on-off *<bridge_node_ID>* *<bridged_device_endpoint_ID>*
In case of the Environmental Sensor, the current temperature and humidity measurements forwarded by the Bluetooth LE Environmental Sensor can be read as follows:

* temperature:

.. parsed-literal::
:class: highlight
./chip-tool temperaturemeasurement read measured-value *<bridge_node_ID>* *<bridged_device_endpoint_ID>*
* humidity:

.. parsed-literal::
:class: highlight
./chip-tool relativehumiditymeasurement read measured-value *<bridge_node_ID>* *<bridged_device_endpoint_ID>*
Enabling remote control
=======================

Expand Down
3 changes: 2 additions & 1 deletion applications/matter_bridge/src/app_task.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ bool sHaveBLEConnections = false;

#ifdef CONFIG_BRIDGED_DEVICE_BT
static bt_uuid *sUuidLbs = BT_UUID_LBS;
static bt_uuid *sUuidServices[] = { sUuidLbs };
static bt_uuid *sUuidEs = BT_UUID_ESS;
static bt_uuid *sUuidServices[] = { sUuidLbs, sUuidEs };
static constexpr uint8_t kUuidServicesNumber = ARRAY_SIZE(sUuidServices);
#endif /* CONFIG_BRIDGED_DEVICE_BT */

Expand Down
62 changes: 43 additions & 19 deletions applications/matter_bridge/src/bridge_shell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,44 +21,66 @@ LOG_MODULE_DECLARE(app, CONFIG_CHIP_APP_LOG_LEVEL);
static BridgedDeviceDataProvider *CreateSimulatedProvider(int deviceType)
{
return BridgeFactory::GetSimulatedDataProviderFactory().Create(
static_cast<BridgedDevice::DeviceType>(deviceType), BridgeManager::HandleUpdate);
static_cast<MatterBridgedDevice::DeviceType>(deviceType), BridgeManager::HandleUpdate);
}
#endif /* CONFIG_BRIDGED_DEVICE_SIMULATED */

#ifdef CONFIG_BRIDGED_DEVICE_BT

static BridgedDeviceDataProvider *CreateBleProvider(int deviceType)
{
return BridgeFactory::GetBleDataProviderFactory().Create(static_cast<BridgedDevice::DeviceType>(deviceType),
BridgeManager::HandleUpdate);
return BridgeFactory::GetBleDataProviderFactory().Create(
static_cast<MatterBridgedDevice::DeviceType>(deviceType), BridgeManager::HandleUpdate);
}

struct BluetoothConnectionContext {
const struct shell *shell;
int deviceType;
char nodeLabel[BridgedDevice::kNodeLabelSize];
char nodeLabel[MatterBridgedDevice::kNodeLabelSize];
BLEBridgedDeviceProvider *provider;
};
#endif /* CONFIG_BRIDGED_DEVICE_BT */

static void AddDevice(const struct shell *shell, int deviceType, const char *nodeLabel,
BridgedDeviceDataProvider *provider)
{
VerifyOrReturn(provider != nullptr,
shell_fprintf(shell, SHELL_INFO, "Cannot allocate data provider of given type\n"));
VerifyOrReturn(provider != nullptr, shell_fprintf(shell, SHELL_INFO, "No valid data provider!\n"));

auto *newBridgedDevice = BridgeFactory::GetBridgedDeviceFactory().Create(
static_cast<BridgedDevice::DeviceType>(deviceType), nodeLabel);
CHIP_ERROR err;
if (deviceType == MatterBridgedDevice::DeviceType::EnvironmentalSensor) {
/* Handle special case for environmental sensor */
auto *temperatureBridgedDevice = BridgeFactory::GetBridgedDeviceFactory().Create(
MatterBridgedDevice::DeviceType::TemperatureSensor, nodeLabel);

VerifyOrReturn(newBridgedDevice != nullptr, delete provider,
shell_fprintf(shell, SHELL_INFO, "Cannot allocate Matter device of given type\n"));
VerifyOrReturn(temperatureBridgedDevice != nullptr, delete provider,
shell_fprintf(shell, SHELL_INFO, "Cannot allocate Matter device of given type\n"));

auto *humidityBridgedDevice = BridgeFactory::GetBridgedDeviceFactory().Create(
MatterBridgedDevice::DeviceType::HumiditySensor, nodeLabel);

VerifyOrReturn(humidityBridgedDevice != nullptr, delete provider, delete temperatureBridgedDevice,
shell_fprintf(shell, SHELL_INFO, "Cannot allocate Matter device of given type\n"));

MatterBridgedDevice *newBridgedDevices[] = { temperatureBridgedDevice, humidityBridgedDevice };
err = BridgeManager::Instance().AddBridgedDevices(newBridgedDevices, provider,
ARRAY_SIZE(newBridgedDevices));

} else {
auto *newBridgedDevice = BridgeFactory::GetBridgedDeviceFactory().Create(
static_cast<MatterBridgedDevice::DeviceType>(deviceType), nodeLabel);

MatterBridgedDevice *newBridgedDevices[] = { newBridgedDevice };
VerifyOrReturn(newBridgedDevice != nullptr, delete provider,
shell_fprintf(shell, SHELL_INFO, "Cannot allocate Matter device of given type\n"));
err = BridgeManager::Instance().AddBridgedDevices(newBridgedDevices, provider,
ARRAY_SIZE(newBridgedDevices));
}

CHIP_ERROR err = BridgeManager::Instance().AddBridgedDevices(newBridgedDevice, provider);
if (err == CHIP_NO_ERROR) {
shell_fprintf(shell, SHELL_INFO, "Done\n");
} else if (err == CHIP_ERROR_INVALID_STRING_LENGTH) {
shell_fprintf(shell, SHELL_ERROR, "Error: too long node label (max %d)\n",
BridgedDevice::kNodeLabelSize);
MatterBridgedDevice::kNodeLabelSize);
} else if (err == CHIP_ERROR_NO_MEMORY) {
shell_fprintf(shell, SHELL_ERROR, "Error: no memory\n");
} else if (err == CHIP_ERROR_INVALID_ARGUMENT) {
Expand Down Expand Up @@ -119,6 +141,7 @@ static int AddBridgedDeviceHandler(const struct shell *shell, size_t argc, char
BridgedDeviceDataProvider *provider = CreateBleProvider(contextPtr->deviceType);

if (!provider) {
shell_fprintf(shell, SHELL_INFO, "Cannot allocate data provider of given type\n");
return -ENOMEM;
}

Expand Down Expand Up @@ -193,13 +216,14 @@ static int ScanBridgedDeviceHandler(const struct shell *shell, size_t argc, char
SHELL_STATIC_SUBCMD_SET_CREATE(
sub_matter_bridge,
#ifdef CONFIG_BRIDGED_DEVICE_BT
SHELL_CMD_ARG(add, NULL,
"Adds bridged device. \n"
"Usage: add <bridged_device_type> <ble_device_index> [node_label]\n"
"* bridged_device_type - the bridged device's type, e.g. 256 - OnOff Light\n"
"* ble_device_index - the Bluetooth LE device's index on the list returned by the scan command\n"
"* node_label - the optional bridged device's node label\n",
AddBridgedDeviceHandler, 3, 1),
SHELL_CMD_ARG(
add, NULL,
"Adds bridged device. \n"
"Usage: add <bridged_device_type> <ble_device_index> [node_label]\n"
"* bridged_device_type - the bridged device's type, e.g. 256 - OnOff Light, 291 - EnvironmentalSensor\n"
"* ble_device_index - the Bluetooth LE device's index on the list returned by the scan command\n"
"* node_label - the optional bridged device's node label\n",
AddBridgedDeviceHandler, 3, 1),
#else
SHELL_CMD_ARG(
add, NULL,
Expand Down
30 changes: 21 additions & 9 deletions applications/matter_bridge/src/bridged_device_factory.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
#pragma once

#include "bridge_util.h"
#include "bridged_device.h"
#include "bridged_device_data_provider.h"
#include "matter_bridged_device.h"
#include <lib/support/CHIPMem.h>

#ifdef CONFIG_BRIDGE_HUMIDITY_SENSOR_BRIDGED_DEVICE
Expand All @@ -35,11 +35,17 @@
#endif
#endif

#ifdef CONFIG_BRIDGED_DEVICE_BT
#if defined(CONFIG_BRIDGE_HUMIDITY_SENSOR_BRIDGED_DEVICE) && defined(CONFIG_BRIDGE_TEMPERATURE_SENSOR_BRIDGED_DEVICE)
#include "ble_environmental_data_provider.h"
#endif
#endif

namespace BridgeFactory
{
using UpdateAttributeCallback = BridgedDeviceDataProvider::UpdateAttributeCallback;
using DeviceType = BridgedDevice::DeviceType;
using BridgedDeviceFactory = DeviceFactory<BridgedDevice, const char *>;
using DeviceType = MatterBridgedDevice::DeviceType;
using BridgedDeviceFactory = DeviceFactory<MatterBridgedDevice, const char *>;

#ifdef CONFIG_BRIDGED_DEVICE_SIMULATED
using SimulatedDataProviderFactory = DeviceFactory<BridgedDeviceDataProvider, UpdateAttributeCallback>;
Expand All @@ -51,7 +57,7 @@ using BleDataProviderFactory = DeviceFactory<BridgedDeviceDataProvider, UpdateAt

auto checkLabel = [](const char *nodeLabel) {
/* If node label is provided it must fit the maximum defined length */
if (!nodeLabel || (nodeLabel && (strlen(nodeLabel) < BridgedDevice::kNodeLabelSize))) {
if (!nodeLabel || (nodeLabel && (strlen(nodeLabel) < MatterBridgedDevice::kNodeLabelSize))) {
return true;
}
return false;
Expand All @@ -62,7 +68,7 @@ inline BridgedDeviceFactory &GetBridgedDeviceFactory()
static BridgedDeviceFactory sBridgedDeviceFactory{
#ifdef CONFIG_BRIDGE_HUMIDITY_SENSOR_BRIDGED_DEVICE
{ DeviceType::HumiditySensor,
[](const char *nodeLabel) -> BridgedDevice * {
[](const char *nodeLabel) -> MatterBridgedDevice * {
if (!checkLabel(nodeLabel)) {
return nullptr;
}
Expand All @@ -71,16 +77,16 @@ inline BridgedDeviceFactory &GetBridgedDeviceFactory()
#endif
#ifdef CONFIG_BRIDGE_ONOFF_LIGHT_BRIDGED_DEVICE
{ DeviceType::OnOffLight,
[](const char *nodeLabel) -> BridgedDevice * {
[](const char *nodeLabel) -> MatterBridgedDevice * {
if (!checkLabel(nodeLabel)) {
return nullptr;
}
return chip::Platform::New<OnOffLightDevice>(nodeLabel);
} },
#endif
#ifdef CONFIG_BRIDGE_TEMPERATURE_SENSOR_BRIDGED_DEVICE
{ BridgedDevice::DeviceType::TemperatureSensor,
[](const char *nodeLabel) -> BridgedDevice * {
{ MatterBridgedDevice::DeviceType::TemperatureSensor,
[](const char *nodeLabel) -> MatterBridgedDevice * {
if (!checkLabel(nodeLabel)) {
return nullptr;
}
Expand Down Expand Up @@ -121,10 +127,16 @@ inline SimulatedDataProviderFactory &GetSimulatedDataProviderFactory()
#ifdef CONFIG_BRIDGED_DEVICE_BT
inline BleDataProviderFactory &GetBleDataProviderFactory()
{
static BleDataProviderFactory sDeviceDataProvider{
static BleDataProviderFactory sDeviceDataProvider
{
#ifdef CONFIG_BRIDGE_ONOFF_LIGHT_BRIDGED_DEVICE
{ DeviceType::OnOffLight,
[](UpdateAttributeCallback clb) { return chip::Platform::New<BleOnOffLightDataProvider>(clb); } },
#endif
#if defined(CONFIG_BRIDGE_TEMPERATURE_SENSOR_BRIDGED_DEVICE) && defined(CONFIG_BRIDGE_HUMIDITY_SENSOR_BRIDGED_DEVICE)
{ DeviceType::EnvironmentalSensor, [](UpdateAttributeCallback clb) {
return chip::Platform::New<BleEnvironmentalDataProvider>(clb);
} },
#endif
};
return sDeviceDataProvider;
Expand Down
Loading

0 comments on commit d583ba6

Please sign in to comment.