Skip to content

Commit

Permalink
applications: Matter Bridge: added support for Generic Switch
Browse files Browse the repository at this point in the history
* implemented new Matter device type: Generic Switch
  that is based on the Switch cluster
* combined the Generic Switch with the LBS BT device
  implementation
* updated documentation
* updated changelog

Signed-off-by: Marcin Kajor <[email protected]>
  • Loading branch information
markaj-nordic authored and cvinayak committed Dec 5, 2023
1 parent cc1810d commit b6bb6a1
Show file tree
Hide file tree
Showing 16 changed files with 411 additions and 65 deletions.
13 changes: 8 additions & 5 deletions applications/matter_bridge/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,13 @@ if(CONFIG_BRIDGED_DEVICE_BT)
)
target_include_directories(app PRIVATE src/ble_providers)

if(CONFIG_BRIDGE_ONOFF_LIGHT_BRIDGED_DEVICE)
if(CONFIG_BRIDGE_ONOFF_LIGHT_BRIDGED_DEVICE AND CONFIG_BRIDGE_GENERIC_SWITCH_BRIDGED_DEVICE)
target_sources(app PRIVATE
src/bridged_device_types/onoff_light.cpp
src/ble_providers/ble_onoff_light_data_provider.cpp
src/bridged_device_types/generic_switch.cpp
src/ble_providers/ble_lbs_data_provider.cpp
)
endif() # CONFIG_BRIDGE_ONOFF_LIGHT_BRIDGED_DEVICE
endif() # CONFIG_BRIDGE_ONOFF_LIGHT_BRIDGED_DEVICE AND CONFIG_BRIDGE_GENERIC_SWITCH_BRIDGED_DEVICE

if(CONFIG_BRIDGE_HUMIDITY_SENSOR_BRIDGED_DEVICE)
target_sources(app PRIVATE
Expand All @@ -92,12 +93,14 @@ else()
)
target_include_directories(app PRIVATE src/simulated_providers)

if(CONFIG_BRIDGE_ONOFF_LIGHT_BRIDGED_DEVICE)
if(CONFIG_BRIDGE_ONOFF_LIGHT_BRIDGED_DEVICE AND CONFIG_BRIDGE_GENERIC_SWITCH_BRIDGED_DEVICE)
target_sources(app PRIVATE
src/bridged_device_types/onoff_light.cpp
src/bridged_device_types/generic_switch.cpp
src/simulated_providers/simulated_onoff_light_data_provider.cpp
src/simulated_providers/simulated_generic_switch_data_provider.cpp
)
endif() # CONFIG_BRIDGE_ONOFF_LIGHT_BRIDGED_DEVICE
endif() # CONFIG_BRIDGE_ONOFF_LIGHT_BRIDGED_DEVICE AND CONFIG_BRIDGE_GENERIC_SWITCH_BRIDGED_DEVICE

if(CONFIG_BRIDGE_TEMPERATURE_SENSOR_BRIDGED_DEVICE)
target_sources(app PRIVATE
Expand Down
4 changes: 4 additions & 0 deletions applications/matter_bridge/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ config BRIDGE_HUMIDITY_SENSOR_BRIDGED_DEVICE
bool "Support for Humidity Sensor bridged device"
default y

config BRIDGE_GENERIC_SWITCH_BRIDGED_DEVICE
bool "Support for Generic Switch bridged device"
default y

choice BRIDGED_DEVICE_IMPLEMENTATION
prompt "Bridged Device implementation"
default BRIDGED_DEVICE_SIMULATED
Expand Down
37 changes: 29 additions & 8 deletions applications/matter_bridge/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ The Matter bridge has capability of representing non-Matter bridged devices as d
The application supports bridging the following Matter device types:

* On/Off Light
* Generic Switch
* Temperature Sensor
* Humidity Sensor

Expand Down Expand Up @@ -99,7 +100,7 @@ The application supports two bridged device configurations that are mutually exc
* Bluetooth LE bridged device - This configuration allows to connect a real peripheral Bluetooth LE device to the Matter bridge and represent its functionalities using :ref:`Matter Data Model <ug_matter_overview_data_model>`.
The application supports the following Bluetooth LE services:

* Nordic Semiconductor's :ref:`LED Button Service <lbs_readme>` - represented by the Matter On/Off Light device type.
* Nordic Semiconductor's :ref:`LED Button Service <lbs_readme>` - represented by the Matter On/Off Light and Generic Switch device types.
* Zephyr's :ref:`Environmental Sensing Service <peripheral_esp>` - represented by the Matter Temperature Sensor and Humidity Sensor device types.

Depending on the bridged device you want to support in your application, :ref:`enable it using the appropriate Kconfig option <matter_bridge_app_bridged_support_configs>`.
Expand Down Expand Up @@ -207,6 +208,7 @@ Adding a simulated bridged device to the Matter bridge
* *<device_type>* is the Matter device type to use for the bridged device.
The argument is mandatory and accepts the following values:

* ``15`` - Generic Switch.
* ``256`` - On/Off Light.
* ``770`` - Temperature Sensor.
* ``775`` - Humidity Sensor.
Expand All @@ -220,7 +222,7 @@ Adding a simulated bridged device to the Matter bridge
uart:~$ matter_bridge add 256 "Kitchen Light"
Controlling a simulated OnOff Light bridged device
Controlling a simulated On/Off Light bridged device
Use the following command:

.. parsed-literal::
Expand All @@ -230,8 +232,8 @@ Controlling a simulated OnOff Light bridged device
In this command:

* *<new_state>* is the new state (``0`` - off and ``1`` - on) that will be set on the simulated OnOff Light device.
* *<endpoint>* is the endpoint on which the bridged OnOff Light device is implemented
* *<new_state>* is the new state (``0`` - off and ``1`` - on) that will be set on the simulated On/Off Light device.
* *<endpoint>* is the endpoint on which the bridged On/Off Light device is implemented

Example command:

Expand Down Expand Up @@ -269,7 +271,10 @@ Adding a Bluetooth LE bridged device to the Matter bridge
.. code-block:: console
I: Added device to dynamic endpoint 3 (index=0)
I: Added device to dynamic endpoint 4 (index=1)
I: Created 0x100 device type on the endpoint 3
I: Created 0xf device type on the endpoint 4
Removing a bridged device from the Matter bridge
Use the following command:
Expand Down Expand Up @@ -302,12 +307,12 @@ You can enable the :ref:`matter_bridge_app_bridged_support` by using the followi
* :kconfig:option:`CONFIG_BRIDGED_DEVICE_SIMULATED` - For the simulated bridged device.
* :kconfig:option:`CONFIG_BRIDGED_DEVICE_BT` - For the Bluetooth LE bridged device.

The simulated OnOff Light bridged device can operate in the following modes:
The simulated On/Off Light bridged device can operate in the following modes:

* Autonomous - The simulated device periodically changes its state.
To build the simulated OnOff Light data provider in this mode, select the :kconfig:option:`CONFIG_BRIDGED_DEVICE_SIMULATED_ONOFF_AUTOMATIC` Kconfig option.
To build the simulated On/Off Light data provider in this mode, select the :kconfig:option:`CONFIG_BRIDGED_DEVICE_SIMULATED_ONOFF_AUTOMATIC` Kconfig option.
* Controllable - The user can explicitly control the On/Off state by using shell commands.
To build the simulated OnOff Light data provider in this mode, select the :kconfig:option:`CONFIG_BRIDGED_DEVICE_SIMULATED_ONOFF_SHELL` Kconfig option.
To build the simulated On/Off Light data provider in this mode, select the :kconfig:option:`CONFIG_BRIDGED_DEVICE_SIMULATED_ONOFF_SHELL` Kconfig option.
This is enabled by default.

Additionally, you can decide how many bridged devices the bridge application will support.
Expand Down Expand Up @@ -479,9 +484,14 @@ After building the sample and programming it to your development kit, complete t
:class: highlight
I: Added device to dynamic endpoint 3 (index=0)
I: Added device to dynamic endpoint 4 (index=1)
I: Created 0x100 device type on the endpoint 3
I: Created 0xf device type on the endpoint 4
For the LED Button Service and the Environmental Sensor, two endpoints are created:

For the Environmental Sensor, two endpoints are created: one implements the Temperature Sensor, and the other implements the Humidity Sensor.
* For the LED Button Service, one implements the On/Off Light Device and the other implements the Generic Switch Device.
* For the Environmental Sensor, 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>*).
Expand All @@ -493,6 +503,17 @@ 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>*
Read the value of the *current-position* attribute from the *switch* cluster using the following command:

.. parsed-literal::
:class: highlight
./chip-tool switch read current-position *<bridge_node_ID>* *<bridged_device_endpoint_ID>*
Note that the Generic Switch is implemented as a momentary switch.
This means that, in contrast to the latching switch, it remains switched on only as long as the physical button is pressed.

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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ CHIP_ERROR MatterDeviceTypeToBleService(MatterBridgedDevice::DeviceType deviceTy
{
switch (deviceType) {
case MatterBridgedDevice::DeviceType::OnOffLight:
case MatterBridgedDevice::DeviceType::GenericSwitch:
serviceUUid = BleBridgedDeviceFactory::ServiceUuid::LedButtonService;
break;
case MatterBridgedDevice::DeviceType::TemperatureSensor:
Expand All @@ -42,7 +43,8 @@ CHIP_ERROR BleServiceToMatterDeviceType(BleBridgedDeviceFactory::ServiceUuid ser
return CHIP_ERROR_BUFFER_TOO_SMALL;
}
deviceType[0] = MatterBridgedDevice::DeviceType::OnOffLight;
count = 1;
deviceType[1] = MatterBridgedDevice::DeviceType::GenericSwitch;
count = 2;
} break;
case BleBridgedDeviceFactory::ServiceUuid::EnvironmentalSensorService: {
if (maxCount < 2) {
Expand Down Expand Up @@ -244,6 +246,15 @@ BleBridgedDeviceFactory::BridgedDeviceFactory &BleBridgedDeviceFactory::GetBridg
}
return chip::Platform::New<TemperatureSensorDevice>(nodeLabel);
} },
#endif
#ifdef CONFIG_BRIDGE_GENERIC_SWITCH_BRIDGED_DEVICE
{ MatterBridgedDevice::DeviceType::GenericSwitch,
[checkLabel](const char *nodeLabel) -> MatterBridgedDevice * {
if (!checkLabel(nodeLabel)) {
return nullptr;
}
return chip::Platform::New<GenericSwitchDevice>(nodeLabel);
} },
#endif
};
return sBridgedDeviceFactory;
Expand All @@ -253,9 +264,9 @@ BleBridgedDeviceFactory::BleDataProviderFactory &BleBridgedDeviceFactory::GetDat
{
static BleDataProviderFactory sDeviceDataProvider
{
#ifdef CONFIG_BRIDGE_ONOFF_LIGHT_BRIDGED_DEVICE
#if defined(CONFIG_BRIDGE_ONOFF_LIGHT_BRIDGED_DEVICE) && defined(CONFIG_BRIDGE_GENERIC_SWITCH_BRIDGED_DEVICE)
{ ServiceUuid::LedButtonService,
[](UpdateAttributeCallback clb) { return chip::Platform::New<BleOnOffLightDataProvider>(clb); } },
[](UpdateAttributeCallback clb) { return chip::Platform::New<BleLBSDataProvider>(clb); } },
#endif
#if defined(CONFIG_BRIDGE_TEMPERATURE_SENSOR_BRIDGED_DEVICE) && defined(CONFIG_BRIDGE_HUMIDITY_SENSOR_BRIDGED_DEVICE)
{ ServiceUuid::EnvironmentalSensorService, [](UpdateAttributeCallback clb) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,19 @@
#include "matter_bridged_device.h"
#include <lib/support/CHIPMem.h>

#if defined(CONFIG_BRIDGE_ONOFF_LIGHT_BRIDGED_DEVICE) && defined(CONFIG_BRIDGE_GENERIC_SWITCH_BRIDGED_DEVICE)
#include "ble_lbs_data_provider.h"

#ifdef CONFIG_BRIDGE_ONOFF_LIGHT_BRIDGED_DEVICE
#include "ble_onoff_light_data_provider.h"
#include "onoff_light.h"
#endif

#ifdef CONFIG_BRIDGE_GENERIC_SWITCH_BRIDGED_DEVICE
#include "generic_switch.h"
#endif

#endif

#ifdef CONFIG_BRIDGE_HUMIDITY_SENSOR_BRIDGED_DEVICE
#include "humidity_sensor.h"
#endif
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/

#include "ble_onoff_light_data_provider.h"
#include "ble_lbs_data_provider.h"

#include <bluetooth/gatt_dm.h>
#include <zephyr/bluetooth/conn.h>
Expand All @@ -22,31 +22,32 @@ static bt_uuid *sUuidLED = BT_UUID_LBS_LED;
static bt_uuid *sUuidButton = BT_UUID_LBS_BUTTON;
static bt_uuid *sUuidCcc = BT_UUID_GATT_CCC;

uint8_t BleOnOffLightDataProvider::GattNotifyCallback(bt_conn *conn, bt_gatt_subscribe_params *params, const void *data,
uint16_t length)
uint8_t BleLBSDataProvider::GattNotifyCallback(bt_conn *conn, bt_gatt_subscribe_params *params, const void *data,
uint16_t length)
{
BleOnOffLightDataProvider *provider = static_cast<BleOnOffLightDataProvider *>(
BleLBSDataProvider *provider = static_cast<BleLBSDataProvider *>(
BLEConnectivityManager::Instance().FindBLEProvider(*bt_conn_get_dst(conn)));

VerifyOrExit(data, );
VerifyOrExit(length == sizeof(mOnOff), );
VerifyOrExit(length == sizeof(mCurrentSwitchPosition), );
VerifyOrExit(provider, );

/* TODO: Implement invoking command through the binding for OnOff light switch or update state of generic
* switch. */
/* Save data received in the notification. */
memcpy(&provider->mCurrentSwitchPosition, data, length);
DeviceLayer::PlatformMgr().ScheduleWork(NotifySwitchCurrentPositionAttributeChange,
reinterpret_cast<intptr_t>(provider));

exit:

return BT_GATT_ITER_CONTINUE;
}

void BleOnOffLightDataProvider::Init()
void BleLBSDataProvider::Init()
{
/* Do nothing in this case */
}

void BleOnOffLightDataProvider::NotifyUpdateState(chip::ClusterId clusterId, chip::AttributeId attributeId, void *data,
size_t dataSize)
void BleLBSDataProvider::NotifyUpdateState(chip::ClusterId clusterId, chip::AttributeId attributeId, void *data,
size_t dataSize)
{
if (mUpdateAttributeCallback) {
mUpdateAttributeCallback(*this, clusterId, attributeId, data, dataSize);
Expand All @@ -64,7 +65,7 @@ void BleOnOffLightDataProvider::NotifyUpdateState(chip::ClusterId clusterId, chi
}
}

void BleOnOffLightDataProvider::GattWriteCallback(bt_conn *conn, uint8_t err, bt_gatt_write_params *params)
void BleLBSDataProvider::GattWriteCallback(bt_conn *conn, uint8_t err, bt_gatt_write_params *params)
{
if (!params) {
return;
Expand All @@ -74,7 +75,7 @@ void BleOnOffLightDataProvider::GattWriteCallback(bt_conn *conn, uint8_t err, bt
return;
}

BleOnOffLightDataProvider *provider = static_cast<BleOnOffLightDataProvider *>(
BleLBSDataProvider *provider = static_cast<BleLBSDataProvider *>(
BLEConnectivityManager::Instance().FindBLEProvider(*bt_conn_get_dst(conn)));

if (!provider) {
Expand All @@ -84,11 +85,10 @@ void BleOnOffLightDataProvider::GattWriteCallback(bt_conn *conn, uint8_t err, bt
/* Save data received in GATT write response. */
memcpy(&provider->mOnOff, params->data, params->length);

DeviceLayer::PlatformMgr().ScheduleWork(NotifyAttributeChange, reinterpret_cast<intptr_t>(provider));
DeviceLayer::PlatformMgr().ScheduleWork(NotifyOnOffAttributeChange, reinterpret_cast<intptr_t>(provider));
}

CHIP_ERROR BleOnOffLightDataProvider::UpdateState(chip::ClusterId clusterId, chip::AttributeId attributeId,
uint8_t *buffer)
CHIP_ERROR BleLBSDataProvider::UpdateState(chip::ClusterId clusterId, chip::AttributeId attributeId, uint8_t *buffer)
{
if (clusterId != Clusters::OnOff::Id) {
return CHIP_ERROR_INVALID_ARGUMENT;
Expand All @@ -98,8 +98,7 @@ CHIP_ERROR BleOnOffLightDataProvider::UpdateState(chip::ClusterId clusterId, chi
return CHIP_ERROR_INCORRECT_STATE;
}

LOG_INF("Updating state of the BleOnOffLightDataProvider, cluster ID: %u, attribute ID: %u.", clusterId,
attributeId);
LOG_INF("Updating state of the BleLBSDataProvider, cluster ID: %u, attribute ID: %u.", clusterId, attributeId);

switch (attributeId) {
case Clusters::OnOff::Attributes::OnOff::Id: {
Expand All @@ -109,7 +108,7 @@ CHIP_ERROR BleOnOffLightDataProvider::UpdateState(chip::ClusterId clusterId, chi
mGattWriteParams.offset = 0;
mGattWriteParams.length = sizeof(mOnOff);
mGattWriteParams.handle = mLedCharacteristicHandle;
mGattWriteParams.func = BleOnOffLightDataProvider::GattWriteCallback;
mGattWriteParams.func = BleLBSDataProvider::GattWriteCallback;

int err = bt_gatt_write(mDevice.mConn, &mGattWriteParams);
if (err) {
Expand All @@ -126,20 +125,20 @@ CHIP_ERROR BleOnOffLightDataProvider::UpdateState(chip::ClusterId clusterId, chi
return CHIP_NO_ERROR;
}

bt_uuid *BleOnOffLightDataProvider::GetServiceUuid()
bt_uuid *BleLBSDataProvider::GetServiceUuid()
{
return sServiceUuid;
}

void BleOnOffLightDataProvider::Subscribe()
void BleLBSDataProvider::Subscribe()
{
VerifyOrReturn(mDevice.mConn, LOG_ERR("Invalid connection object"));

/* Configure subscription for the button characteristic */
mGattSubscribeParams.ccc_handle = mCccHandle;
mGattSubscribeParams.value_handle = mButtonCharacteristicHandle;
mGattSubscribeParams.value = BT_GATT_CCC_NOTIFY;
mGattSubscribeParams.notify = BleOnOffLightDataProvider::GattNotifyCallback;
mGattSubscribeParams.notify = BleLBSDataProvider::GattNotifyCallback;

if (CheckSubscriptionParameters(&mGattSubscribeParams)) {
int err = bt_gatt_subscribe(mDevice.mConn, &mGattSubscribeParams);
Expand All @@ -151,7 +150,7 @@ void BleOnOffLightDataProvider::Subscribe()
}
}

int BleOnOffLightDataProvider::ParseDiscoveredData(bt_gatt_dm *discoveredData)
int BleLBSDataProvider::ParseDiscoveredData(bt_gatt_dm *discoveredData)
{
const bt_gatt_dm_attr *gatt_chrc;
const bt_gatt_dm_attr *gatt_desc;
Expand Down Expand Up @@ -195,15 +194,23 @@ int BleOnOffLightDataProvider::ParseDiscoveredData(bt_gatt_dm *discoveredData)
return 0;
}

void BleOnOffLightDataProvider::NotifyAttributeChange(intptr_t context)
void BleLBSDataProvider::NotifyOnOffAttributeChange(intptr_t context)
{
BleOnOffLightDataProvider *provider = reinterpret_cast<BleOnOffLightDataProvider *>(context);
BleLBSDataProvider *provider = reinterpret_cast<BleLBSDataProvider *>(context);

provider->NotifyUpdateState(Clusters::OnOff::Id, Clusters::OnOff::Attributes::OnOff::Id, &provider->mOnOff,
sizeof(provider->mOnOff));
}

bool BleOnOffLightDataProvider::CheckSubscriptionParameters(bt_gatt_subscribe_params *params)
void BleLBSDataProvider::NotifySwitchCurrentPositionAttributeChange(intptr_t context)
{
BleLBSDataProvider *provider = reinterpret_cast<BleLBSDataProvider *>(context);

provider->NotifyUpdateState(Clusters::Switch::Id, Clusters::Switch::Attributes::CurrentPosition::Id,
&provider->mCurrentSwitchPosition, sizeof(provider->mCurrentSwitchPosition));
}

bool BleLBSDataProvider::CheckSubscriptionParameters(bt_gatt_subscribe_params *params)
{
/* If any of these is not met, the bt_gatt_subscribe() generates an assert at runtime */
VerifyOrReturnValue(params && params->notify, false);
Expand Down
Loading

0 comments on commit b6bb6a1

Please sign in to comment.