Skip to content

Commit

Permalink
Pull request #196: Unify-Matter-Bridge updated to conform with latest…
Browse files Browse the repository at this point in the history
… Matter Spec 1.0

Merge in WMN_TOOLS/matter from feature/unify-matter-bridge-debugging2 to silabs

Squashed commit of the following:

commit c4ec6e7a68430ebafdb4b0aff431c132877bc402
Author: Jakob Olesen <[email protected]>
Date:   Thu Oct 20 10:47:15 2022 +0200

    Fixed ColorTemperature light support

commit 6ac8dd64fd56efc793056f18011fb758d72623f7
Author: Thomas Bowley <[email protected]>
Date:   Wed Oct 19 15:53:11 2022 +0200

    NoJira: Log JSON parse or type errors as warnings and not infos.

commit 320d13532ef6ad95a56a398d25b1715ced1bf1a5
Author: Dennis Jensen <[email protected]>
Date:   Wed Oct 19 14:04:50 2022 +0200

    NoJira: Don't map endpoints with only 'Groups' or 'NameAndLocation' clusters in them.

... and 2 more commits
  • Loading branch information
jsloth authored and jmartinez-silabs committed Oct 17, 2023
1 parent 3828a5b commit 53f9ccf
Show file tree
Hide file tree
Showing 35 changed files with 14,195 additions and 11,798 deletions.
11 changes: 6 additions & 5 deletions silabs_examples/unify-matter-bridge/linux/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ config("unify-config") {
static_library("unify-matter-bridge-lib") {

sources = [
"src/matter_data_storage.cpp",
"src/attribute_state_cache.cpp",
"src/cluster_translator/bridged_device_basic_info_attribute_translator.cpp",
"src/cluster_translator/group_command_translator.cpp",
Expand All @@ -50,15 +49,17 @@ static_library("unify-matter-bridge-lib") {
"src/device_type_mapper/matter_device_translator.cpp",
"src/device_type_mapper/matter_device_types_clusters_list_updated.inc",
"src/dummy.cpp",
"src/matter_bridge_config.c",
"src/matter_bridge_cli.cpp",
"src/matter_bridge_config.c",
"src/matter_data_storage.cpp",
"src/matter_node_state_monitor/matter_cluster_interactor.cpp",
"src/matter_node_state_monitor/matter_endpoint_builder.cpp",
"src/matter_node_state_monitor/matter_node_state_monitor.cpp",
"zap-handlers/gen/command_translator.cpp",
"src/uic_mqtt_wrapper.cpp",
"zap-handlers/gen/attribute_translator.cpp",
"zap-handlers/gen/unify_accessors.cpp",
"src/uic_mqtt_wrapper.cpp"
"zap-handlers/gen/attribute_type_size.cpp",
"zap-handlers/gen/command_translator.cpp",
"zap-handlers/gen/unify_accessors.cpp"
]

public_deps = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,11 @@ class attribute_translator_interface :
{
public:
attribute_translator_interface(matter_node_state_monitor &node_state_monitor,
chip::ClusterId id) :
chip::ClusterId id, const char *log_tag) :
chip::app::AttributeAccessInterface(
chip::Optional<chip::EndpointId>::Missing(), id),
m_node_state_monitor(node_state_monitor)
m_node_state_monitor(node_state_monitor),
LOG_TAG(log_tag)
{
registerAttributeAccessOverride(this);

Expand Down Expand Up @@ -82,7 +83,7 @@ class attribute_translator_interface :
matter_node_state_monitor &m_node_state_monitor;

private:
const char *LOG_TAG = "attribute_cluster_server";
const char *LOG_TAG;

void on_mqtt_message_cb(const char *topic,
const char *message,
Expand Down Expand Up @@ -122,16 +123,16 @@ class attribute_translator_interface :
nlohmann::json jsn = nlohmann::json::parse(msg);
reported_updated(unify_node, cluster, attribute, jsn["value"]);
} catch (const nlohmann::json::parse_error &e) {
sl_log_info(LOG_TAG,
sl_log_warning(LOG_TAG,
"It was not possible to parse incoming attribute state "
"update since the message payload is not json, %s\n",
e.what());
} catch (const nlohmann::json::type_error &e) {
sl_log_info(
sl_log_warning(
LOG_TAG,
"It was not possible to parse incoming attribute state update since "
"the value of different type or key is not present, %s\n",
e.what());
"the value of different type or key is not present, %s\n%s\n",
e.what(), msg.c_str());
}
} else {
sl_log_debug(LOG_TAG, "Unknown attributes [%s]", attribute.c_str());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ const static std::unordered_map<std::string, uint32_t> basic_information_map {
BridgedDeviceBasicInfoAttributeAccess::BridgedDeviceBasicInfoAttributeAccess(
matter_node_state_monitor &node_state_monitor) :
attribute_translator_interface(node_state_monitor,
chip::app::Clusters::BridgedDeviceBasic::Id)
chip::app::Clusters::BridgedDeviceBasic::Id, "attr_translator_BridgedDeviceBasic")

{
//Register the an event listener for reachable state update
Expand Down Expand Up @@ -154,6 +154,15 @@ CHIP_ERROR BridgedDeviceBasicInfoAttributeAccess::Read(
.get<Reachable::TypeInfo::Type>(attr_path);
return aEncoder.Encode(state);
}
case FeatureMap::Id: {
uint32_t map = 0;
return aEncoder.Encode(map);
}
case ClusterRevision::Id: {
// Update version if bridged-device-basic.xml version is changed
uint16_t revision = 1;
return aEncoder.Encode(revision);
}
}
} catch (const std::out_of_range &e) {
sl_log_info(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ static const std::map<chip::DeviceTypeId, std::pair<std::vector<const char *>, c
//{ 0x0403, {{"Basic", "Identify", "IASWD", "IASZone"}, "iasW"} },
{ 0x0100, {{"Basic", "Identify", "Groups", "Scenes", "OnOff"}, "onofflight"} },
{ 0x0101, {{"Basic", "Identify", "Groups", "Scenes", "OnOff", "Level"}, "dimmablelight"} },
{ 0x0102, {{"Basic", "Identify", "Groups", "Scenes", "OnOff", "Level", "ColorControl"}, "colordimmablelight"} },
//{ 0x0102, {{"Basic", "Identify", "Groups", "Scenes", "OnOff", "Level", "ColorControl"}, "colordimmablelight"} },
//{ 0x0103, {{"Basic", "Identify"}, "onofflightswitch"} },
//{ 0x0104, {{"Basic", "Identify"}, "dimmerswitch"} },
//{ 0x0105, {{"Basic", "Identify"}, "colordimmerswitch"} },
Expand All @@ -51,7 +51,7 @@ static const std::map<chip::DeviceTypeId, std::pair<std::vector<const char *>, c
//{ 0x010A, {{"Basic", "Identify", "Groups", "Scenes", "OnOff"}, "onoffpluginunit"} },
//{ 0x010B, {{"Basic", "Identify", "Groups", "Scenes", "OnOff", "Level"}, "dimmablepluginunit"} },
//{ 0x010C, {{"Basic", "Identify", "Groups", "Scenes", "OnOff", "Level", "ColorControl"}, "colortemperaturelight"} },
//{ 0x010D, {{"Basic", "Identify", "Groups", "Scenes", "OnOff", "Level", "ColorControl"}, "extendedcolorlight"} },
{ 0x010D, {{"Basic", "Identify", "Groups", "Scenes", "OnOff", "Level", "ColorControl"}, "extendedcolorlight"} },
{ 0x010E, {{"Basic", "Identify", "IlluminanceLevelSensing"}, "lightlevelsensor"} },
//{ 0x0800, {{"Basic", "Identify"}, "colorcontroller"} },
//{ 0x0810, {{"Basic", "Identify"}, "colorscenecontroller"} },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,24 @@
*****************************************************************************/

#include "matter_cluster_interactor.hpp"
#include "attribute_type_size.hpp"
#include "matter.h"
#include "matter_device_translator.hpp"
#include "matter_endpoint_builder.hpp"
#include "sl_log.h"

constexpr const char * LOG_TAG = "cluster_interactor";
constexpr int kNodeLabelSize = 32;
constexpr const char * LOG_TAG = "cluster_interactor";
constexpr int kNodeLabelSize = 32;
constexpr int kDescriptorAttributeArraySize = 254;
constexpr int kFixedLabelAttributeArraySize = 254;

namespace {
/**
* @brief these clusters are default clusters that are required by matter?
* these clusters will be appended for each registered endpoint
*/
static void append_bridged_clusters(unify::matter_bridge::matter_endpoint_builder & endpoint_builder)
{
constexpr int kDescriptorAttributeArraySize = 254;
constexpr int kFixedLabelAttributeArraySize = 254;

auto descriptor_cluster = endpoint_builder.register_cluster(ZCL_DESCRIPTOR_CLUSTER_ID);
descriptor_cluster.attributes.push_back(EmberAfAttributeMetadata{ ZCL_DEVICE_LIST_ATTRIBUTE_ID, ZCL_ARRAY_ATTRIBUTE_TYPE,
Expand All @@ -38,10 +40,14 @@ static void append_bridged_clusters(unify::matter_bridge::matter_endpoint_builde
kDescriptorAttributeArraySize, 0, ZAP_EMPTY_DEFAULT() });
descriptor_cluster.attributes.push_back(EmberAfAttributeMetadata{ ZCL_PARTS_LIST_ATTRIBUTE_ID, ZCL_ARRAY_ATTRIBUTE_TYPE,
kDescriptorAttributeArraySize, 0, ZAP_EMPTY_DEFAULT() });
descriptor_cluster.attributes.emplace_back(
EmberAfAttributeMetadata{ ZCL_CLUSTER_REVISION_SERVER_ATTRIBUTE_ID, ZCL_INT16U_ATTRIBUTE_TYPE, 2, 0, ZAP_EMPTY_DEFAULT() });

auto fixed_label_cluster = endpoint_builder.register_cluster(ZCL_FIXED_LABEL_CLUSTER_ID);
fixed_label_cluster.attributes.push_back(EmberAfAttributeMetadata{ ZCL_LABEL_LIST_ATTRIBUTE_ID, ZCL_ARRAY_ATTRIBUTE_TYPE,
kFixedLabelAttributeArraySize, 0, ZAP_EMPTY_DEFAULT() });
fixed_label_cluster.attributes.emplace_back(
EmberAfAttributeMetadata{ ZCL_CLUSTER_REVISION_SERVER_ATTRIBUTE_ID, ZCL_INT16U_ATTRIBUTE_TYPE, 2, 0, ZAP_EMPTY_DEFAULT() });
}

} // namespace
Expand All @@ -57,6 +63,10 @@ void cluster_interactor::build_matter_cluster(const std::unordered_map<std::stri
bool basic_cluster_is_supported = false;
for (const auto & [cluster_name, cluster] : clusters)
{
// Skip clusters that doesn't have attributes
if (cluster.attributes.empty()) {
continue;
}
if (cluster_name == "NameAndLocation")
{
sl_log_info(LOG_TAG, " NameAndLocation cluster is already mapped to BasicBridgedDevice Info.");
Expand All @@ -70,7 +80,7 @@ void cluster_interactor::build_matter_cluster(const std::unordered_map<std::stri
}
else
{
sl_log_info(LOG_TAG, "Mapping Custer %s", cluster_name.c_str());
sl_log_info(LOG_TAG, "Mapping cluster %s", cluster_name.c_str());
}

auto cluster_builder = endpoint_builder.register_cluster(cluster_id.value());
Expand All @@ -96,10 +106,9 @@ void cluster_interactor::build_matter_cluster(const std::unordered_map<std::stri
{
if (auto attribute_id = translator.get_attribute_id(cluster_name, attribute))
{
// TODO: required an API to get the attribute types from the cluster+ attribute name.
// with its corresponding size
cluster_builder.attributes.emplace_back(EmberAfAttributeMetadata{ attribute_id.value(), ZCL_BOOLEAN_ATTRIBUTE_TYPE,
1, CLUSTER_MASK_SERVER, ZAP_EMPTY_DEFAULT() });
attr_type_size type_size = get_attribute_type_size(cluster_id.value(), attribute_id.value());
cluster_builder.attributes.emplace_back(EmberAfAttributeMetadata{
attribute_id.value(), type_size.attrType, type_size.attrSize, CLUSTER_MASK_SERVER, ZAP_EMPTY_DEFAULT() });
}
}
if (cluster_name == "Basic")
Expand All @@ -110,6 +119,10 @@ void cluster_interactor::build_matter_cluster(const std::unordered_map<std::stri
cluster_builder.attributes.emplace_back(
EmberAfAttributeMetadata{ ZCL_REACHABLE_ATTRIBUTE_ID, ZCL_BOOLEAN_ATTRIBUTE_TYPE, 1, 0, ZAP_EMPTY_DEFAULT() });
}
cluster_builder.attributes.push_back(EmberAfAttributeMetadata{
ZCL_FEATURE_MAP_SERVER_ATTRIBUTE_ID, ZCL_BITMAP32_ATTRIBUTE_TYPE, 4, 0, ZAP_EMPTY_DEFAULT() });
cluster_builder.attributes.emplace_back(EmberAfAttributeMetadata{ ZCL_CLUSTER_REVISION_SERVER_ATTRIBUTE_ID,
ZCL_INT16U_ATTRIBUTE_TYPE, 2, 0, ZAP_EMPTY_DEFAULT() });

clusterlist.push_back(cluster_name.c_str());
}
Expand All @@ -120,6 +133,10 @@ void cluster_interactor::build_matter_cluster(const std::unordered_map<std::stri
kNodeLabelSize, 0, ZAP_EMPTY_DEFAULT() });
bridged_cluster.attributes.push_back(
EmberAfAttributeMetadata{ ZCL_REACHABLE_ATTRIBUTE_ID, ZCL_BOOLEAN_ATTRIBUTE_TYPE, 1, 0, ZAP_EMPTY_DEFAULT() });
bridged_cluster.attributes.push_back(EmberAfAttributeMetadata{ ZCL_FEATURE_MAP_SERVER_ATTRIBUTE_ID,
ZCL_BITMAP32_ATTRIBUTE_TYPE, 4, 0, ZAP_EMPTY_DEFAULT() });
bridged_cluster.attributes.emplace_back(EmberAfAttributeMetadata{ ZCL_CLUSTER_REVISION_SERVER_ATTRIBUTE_ID,
ZCL_INT16U_ATTRIBUTE_TYPE, 2, 0, ZAP_EMPTY_DEFAULT() });
}
append_bridged_clusters(endpoint_builder);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,18 @@ void matter_node_state_monitor::on_unify_node_added(
{
for (const auto &[ep_id, ep]: node.endpoints) {
uint8_t count_number_of_clusters_matched_to_matter = 0;

// TODO: This is a temporary solution to ignore endpoints with only the group cluster.
if (ep.clusters.size() <= 2 && (ep.clusters.begin()->first == "Groups" || ep.clusters.begin()->first == "NameAndLocation")) {
sl_log_warning(LOG_TAG, "Ignoring endpoint %d from UNID %s with only the 'Groups' or 'NameAndLocation' clusters", ep_id, node.unid.c_str());
continue;
}

for (const auto &[cluster_name, cluster]: ep.clusters) {
// Skip clusters that doesn't have attributes
if (cluster.attributes.empty()) {
continue;
}
if (matter_device_translator.get_cluster_id(cluster_name).has_value()) {
count_number_of_clusters_matched_to_matter++;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
class UnifyEmberInterface
{
protected:
chip::EndpointId last_returned_available_endpoint_id = FIXED_ENDPOINT_COUNT;
chip::EndpointId last_returned_available_endpoint_id = FIXED_ENDPOINT_COUNT - 1;
const char * LOG_TAG = "Unify Ember Interface";

public:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,40 @@ CHIP_ERROR
ConcreteAttributePath atrpath = ConcreteAttributePath(aPath.mEndpointId,
aPath.mClusterId,
aPath.mAttributeId);

try {
switch (aPath.mAttributeId) {
{{#zcl_attributes_server}}

{{#if_is_struct type}}
{{else if (canHaveSimpleAccessors this)}}
case MN::{{asUpperCamelCase label}}::Id: { // type is {{type}}
MN::{{asUpperCamelCase label}}::TypeInfo::Type value;
UN::{{asUpperCamelCase label}}::Get(atrpath, value );
{{#if (isStrEqual (asUpperCamelCase label) "FeatureMap") }}
{{#if (isStrEqual (asUpperCamelCase parent.label) "LevelControl")}}
// Set hardcoded FeatureMap values for LevelControl
value = 3;
{{else if (isStrEqual (asUpperCamelCase parent.label) "ColorControl")}}
{
ConcreteAttributePath cc_atrpath = ConcreteAttributePath(aPath.mEndpointId,
aPath.mClusterId,
MN::ColorCapabilities::Id);
MN::ColorCapabilities::TypeInfo::Type colorControlCapabilities;
if (EMBER_ZCL_STATUS_SUCCESS == UN::ColorCapabilities::Get(cc_atrpath, colorControlCapabilities)) {
value = static_cast<MN::{{asUpperCamelCase label}}::TypeInfo::Type>(colorControlCapabilities);
}
else {
sl_log_warning(LOG_TAG, "Failed to read ColorCapabilities, setting featuremap to HueSaturationSupported");
value = 1;
}
}
{{else if (isStrEqual (asUpperCamelCase parent.label) "OnOff")}}
// Set hardcoded FeatureMap values for OnOff
value = 1;
{{else}}
UN::{{asUpperCamelCase label}}::Get(atrpath, value);
{{/if}}
{{else}}
UN::{{asUpperCamelCase label}}::Get(atrpath, value);
{{/if}}
return aEncoder.Encode(value);
}
{{/if_is_struct}}
Expand Down Expand Up @@ -97,7 +121,7 @@ CHIP_ERROR {{asUpperCamelCase label}}AttributeAccess::Write(const ConcreteDataAt
switch (aPath.mAttributeId) {
{{#zcl_attributes_server}}
{{#if writable}}

case Attributes::{{asUpperCamelCase label}}::Id: {

Attributes::{{asUpperCamelCase label}}::TypeInfo::DecodableType value;
Expand All @@ -110,7 +134,6 @@ CHIP_ERROR {{asUpperCamelCase label}}AttributeAccess::Write(const ConcreteDataAt
{{/zcl_attributes_server}}
}


if (!attribute_name.empty()) {
std::string payload_str;
std::string topic = "ucl/by-unid/" + unify_node->unify_unid + "/ep"
Expand All @@ -127,8 +150,6 @@ CHIP_ERROR {{asUpperCamelCase label}}AttributeAccess::Write(const ConcreteDataAt
return CHIP_NO_ERROR;
}



void {{asUpperCamelCase label}}AttributeAccess::reported_updated(const bridged_endpoint *ep,
const std::string &cluster,
const std::string &attribute,
Expand All @@ -155,23 +176,35 @@ void {{asUpperCamelCase label}}AttributeAccess::reported_updated(const bridged_e
ConcreteAttributePath attrpath = ConcreteAttributePath(node_matter_endpoint,
Clusters::{{asUpperCamelCase label}}::Id,
attribute_id.value());

switch (attribute_id.value()) {
{{#zcl_attributes_server}}
{{#if_is_struct type}}
{{else if (canHaveSimpleAccessors this)}}
// type is {{type}}
case MN::{{asUpperCamelCase label}}::Id: {
{{#if_is_bitmap (asUpperCamelCase label)}}
{{#if (overrideBitmapType (asUpperCamelCase label))}}
std::optional<{{asUnderlyingType (asUpperCamelCase label)}}> value = from_json_{{asUpperCamelCase label}}(unify_value);
{{else}}
using T = MN::{{asUpperCamelCase label}}::TypeInfo::Type;
std::optional<T> value = from_json<T>(unify_value);
{{/if}}
{{else}}
{{#if (overrideEnumType (asUpperCamelCase label))}}
using T = ZclEnum{{asUpperCamelCase label}};
{{else}}
using T = MN::{{asUpperCamelCase label}}::TypeInfo::Type;
{{/if}}
std::optional<T> value = from_json<T>(unify_value);
{{/if_is_bitmap}}

if( value.has_value()) {
sl_log_debug(LOG_TAG,"{{asUpperCamelCase label}} attribute value is %s",unify_value.dump().c_str() );
UN::{{asUpperCamelCase label}}::Set( attrpath, value.value() );
sl_log_debug(LOG_TAG,"{{asUpperCamelCase label}} attribute value is %s",unify_value.dump().c_str());
UN::{{asUpperCamelCase label}}::Set(attrpath, value.value());
MatterReportingAttributeChangeCallback(
node_matter_endpoint,
Clusters::{{asUpperCamelCase parent.label}}::Id,
MN::{{asUpperCamelCase label}}::Id,
MN::{{asUpperCamelCase label}}::Id,
ZCL_{{typeAsDelimitedMacro type}}_ATTRIBUTE_TYPE,
reinterpret_cast<uint8_t *>(&value.value()));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ class {{asUpperCamelCase label}}AttributeAccess : public attribute_translator_in
public:
{{asUpperCamelCase label}}AttributeAccess(matter_node_state_monitor &node_state_monitor) :
attribute_translator_interface(node_state_monitor,
chip::app::Clusters::{{asUpperCamelCase label}}::Id)
chip::app::Clusters::{{asUpperCamelCase label}}::Id, "attr_translator_{{asUpperCamelCase label}}")

{}

CHIP_ERROR Read(const chip::app::ConcreteReadAttributePath &aPath,
Expand Down
Loading

0 comments on commit 53f9ccf

Please sign in to comment.