Skip to content

Commit d4c07f1

Browse files
silabs-borislrzr
authored andcommitted
UIC-3222: Add MQTT notification when slot has changed
Use a new callback mechanism that allows the server to listen to certain event
1 parent 58e310e commit d4c07f1

File tree

5 files changed

+154
-51
lines changed

5 files changed

+154
-51
lines changed

applications/zpc/components/zcl_cluster_servers/src/user_credential_cluster_server.cpp

Lines changed: 95 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "user_credential_cluster_server.h"
1414
#include "zcl_cluster_servers_helpers.hpp"
1515
// Interfaces
16+
#include "zwave_command_class_user_credential.h"
1617
#include "zwave_command_class_user_credential_api.h"
1718

1819
// ZPC includes
@@ -105,16 +106,16 @@ static const user_attributes_mqtt_map_t credential_attributes
105106
{ATTRIBUTE(ASSOCIATION_STATUS), {"AssociationStatus"}},
106107
{ATTRIBUTE(CREDENTIAL_LEARN_STATUS), {"CredentialLearnStatus"}}};
107108

108-
static const user_attributes_mqtt_map_t credential_rules_attributes
109-
= {{ATTRIBUTE(CREDENTIAL_LEARN_SUPPORT), {"LearnSupport", convert_to_bool}},
110-
{ATTRIBUTE(CREDENTIAL_SUPPORTED_SLOT_COUNT), {"SupportedSlotCount"}},
111-
{ATTRIBUTE(CREDENTIAL_MIN_LENGTH), {"CredentialMinLength"}},
112-
{ATTRIBUTE(CREDENTIAL_MAX_LENGTH), {"CredentialMaxLength"}},
113-
{ATTRIBUTE(CREDENTIAL_LEARN_RECOMMENDED_TIMEOUT),
114-
{"LearnRecommendedTimeout"}},
115-
{ATTRIBUTE(CREDENTIAL_LEARN_NUMBER_OF_STEPS), {"LearnNumberOfSteps"}},
116-
{ATTRIBUTE(CREDENTIAL_CHECKSUM), {"CredentialChecksum"}},
117-
{ATTRIBUTE(CREDENTIAL_CHECKSUM_MISMATCH_ERROR), {"CredentialChecksumError"}}};
109+
static const user_attributes_mqtt_map_t credential_rules_attributes = {
110+
{ATTRIBUTE(CREDENTIAL_LEARN_SUPPORT), {"LearnSupport", convert_to_bool}},
111+
{ATTRIBUTE(CREDENTIAL_SUPPORTED_SLOT_COUNT), {"SupportedSlotCount"}},
112+
{ATTRIBUTE(CREDENTIAL_MIN_LENGTH), {"CredentialMinLength"}},
113+
{ATTRIBUTE(CREDENTIAL_MAX_LENGTH), {"CredentialMaxLength"}},
114+
{ATTRIBUTE(CREDENTIAL_LEARN_RECOMMENDED_TIMEOUT),
115+
{"LearnRecommendedTimeout"}},
116+
{ATTRIBUTE(CREDENTIAL_LEARN_NUMBER_OF_STEPS), {"LearnNumberOfSteps"}},
117+
{ATTRIBUTE(CREDENTIAL_CHECKSUM), {"CredentialChecksum"}},
118+
{ATTRIBUTE(CREDENTIAL_CHECKSUM_MISMATCH_ERROR), {"CredentialChecksumError"}}};
118119

119120
///////////////////////////////////////////////////////////////////////////////
120121
// DotDot MQTT incoming commands handling functions
@@ -564,17 +565,17 @@ sl_status_t get_user_checksum(dotdot_unid_t unid,
564565

565566
return attribute_store_node_exists(user_count_node) ? SL_STATUS_OK
566567
: SL_STATUS_FAIL;
567-
568568
}
569569

570570
return zwave_command_class_user_credential_get_user_checksum(endpoint_node,
571571
user_uniqueid);
572572
}
573573

574-
sl_status_t get_credential_checksum(dotdot_unid_t unid,
575-
dotdot_endpoint_id_t endpoint,
576-
uic_mqtt_dotdot_callback_call_type_t call_type,
577-
CredType credential_type)
574+
sl_status_t
575+
get_credential_checksum(dotdot_unid_t unid,
576+
dotdot_endpoint_id_t endpoint,
577+
uic_mqtt_dotdot_callback_call_type_t call_type,
578+
CredType credential_type)
578579
{
579580
attribute_store_node_t endpoint_node
580581
= attribute_store_network_helper_get_endpoint_node(unid, endpoint);
@@ -588,7 +589,6 @@ sl_status_t get_credential_checksum(dotdot_unid_t unid,
588589

589590
return attribute_store_node_exists(user_count_node) ? SL_STATUS_OK
590591
: SL_STATUS_FAIL;
591-
592592
}
593593

594594
return zwave_command_class_user_credential_get_credential_checksum(
@@ -651,6 +651,18 @@ std::string get_base_mqtt_topic(attribute_store::attribute updated_node_cpp)
651651
return (mqtt_topic % unid % static_cast<unsigned int>(endpoint_id)).str();
652652
}
653653

654+
/**
655+
* @brief Get the base MQTT topic for a user.
656+
*
657+
* @see get_base_user_mqtt_topic(attribute_store::attribute)
658+
*/
659+
std::string
660+
get_base_user_mqtt_topic_str(const std::string &base_mqtt_topic,
661+
user_credential_user_unique_id_t user_id)
662+
{
663+
return (boost::format("%1%/User/%2%") % base_mqtt_topic % user_id).str();
664+
}
665+
654666
/**
655667
* @brief Get the base MQTT topic for a user.
656668
*
@@ -676,7 +688,7 @@ std::string
676688
= updated_node_cpp.first_parent_or_self(ATTRIBUTE(USER_UNIQUE_ID))
677689
.reported<user_credential_user_unique_id_t>();
678690

679-
return (mqtt_topic % base_mqtt_topic % user_id).str();
691+
return get_base_user_mqtt_topic_str(base_mqtt_topic, user_id);
680692
} catch (const std::exception &e) {
681693
sl_log_error(LOG_TAG,
682694
"Error while publishing User attribute (%s) : %s",
@@ -687,6 +699,23 @@ std::string
687699
return "";
688700
}
689701

702+
/**
703+
* @brief Get the base MQTT topic for a credential.
704+
*
705+
* @see get_base_credential_mqtt_topic(attribute_store::attribute updated_node_cpp)
706+
*/
707+
std::string
708+
get_base_credential_mqtt_topic_str(const std::string &base_user_mqtt_topic,
709+
user_credential_slot_t credential_slot,
710+
user_credential_type_t credential_type)
711+
{
712+
std::string credential_type_str
713+
= cred_type_get_enum_value_name(credential_type);
714+
return (boost::format("%1%/Credential/%2%/%3%") % base_user_mqtt_topic
715+
% credential_type_str % credential_slot)
716+
.str();
717+
}
718+
690719
/**
691720
* @brief Get the base MQTT topic for a credential.
692721
*
@@ -713,12 +742,10 @@ std::string
713742
user_credential_type_t credential_type
714743
= updated_node_cpp.first_parent(ATTRIBUTE(CREDENTIAL_TYPE))
715744
.reported<user_credential_type_t>();
716-
std::string credential_type_str
717-
= cred_type_get_enum_value_name(credential_type);
718745

719-
return (boost::format("%1%/Credential/%2%/%3%") % base_user_mqtt_topic
720-
% credential_type_str % credential_slot)
721-
.str();
746+
return get_base_credential_mqtt_topic_str(base_user_mqtt_topic,
747+
credential_slot,
748+
credential_type);
722749
} catch (const std::exception &e) {
723750
sl_log_error(LOG_TAG,
724751
"Error while publishing Credential attribute (%s) : %s",
@@ -973,6 +1000,48 @@ void on_credential_update(attribute_store_node_t updated_node,
9731000
credential_attributes);
9741001
}
9751002

1003+
/**
1004+
* @brief Callback for when a UUIC slot is updated.
1005+
*
1006+
* This is used to update the MQTT topics when a slot is updated.
1007+
* Since we only monitor properties of the slot, we need to update the slot
1008+
* itself when it changes.
1009+
*
1010+
* This callback is called whenever a slot is updated thanks to the UUIC command.
1011+
*
1012+
* @param old_credential_slot The old credential slot id.
1013+
* @param node The node that contains the updated slot.
1014+
*/
1015+
void on_uuic_slot_update(
1016+
const user_credential_credential_identifier_t old_credential_slot,
1017+
attribute_store_node_t node)
1018+
{
1019+
auto credential_slot_node = attribute_store::attribute(node);
1020+
1021+
// Update old slot
1022+
auto old_user_topic
1023+
= get_base_user_mqtt_topic_str(get_base_mqtt_topic(credential_slot_node),
1024+
old_credential_slot.user_unique_id);
1025+
auto old_credential_topic
1026+
= get_base_credential_mqtt_topic_str(old_user_topic,
1027+
old_credential_slot.credential_slot,
1028+
old_credential_slot.credential_type);
1029+
// Simulate deletion of the old slot
1030+
// First simulate deletion of all attributes
1031+
for (auto [attribute_store_type, mqtt_data]: credential_attributes) {
1032+
std::string mqtt_topic
1033+
= mqtt_topic_add_attribute(old_credential_topic, mqtt_data.topic);
1034+
uic_mqtt_publish(mqtt_topic.c_str(), "", 0, true);
1035+
}
1036+
// Then delete the slot itself
1037+
uic_mqtt_publish(old_credential_topic.c_str(), "", 0, true);
1038+
1039+
// Trigger update for the new slot
1040+
for (auto child: credential_slot_node.children()) {
1041+
on_credential_update(child, ATTRIBUTE_UPDATED);
1042+
}
1043+
}
1044+
9761045
///////////////////////////////////////////////////////////////////////////////
9771046
// Init and teardown functions.
9781047
//////////////////////////////////////////////////////////////////////////////
@@ -986,6 +1055,10 @@ sl_status_t user_credential_cluster_server_init()
9861055
register_attributes_to_mqtt_map(credential_rules_attributes,
9871056
&on_credential_rules_update);
9881057

1058+
// Custom callbacks
1059+
zwave_command_class_user_credential_set_uuic_slot_changed_callback(
1060+
&on_uuic_slot_update);
1061+
9891062
// Command callbacks
9901063
// User
9911064
uic_mqtt_dotdot_user_credential_add_user_callback_set(&add_user_command);

applications/zpc/components/zpc_attribute_store/include/command_class_types/zwave_command_class_user_credential_types.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,13 @@ typedef uint8_t user_credential_learn_timeout_t;
8181
///> Credential Learn Status. uint8_t
8282
typedef uint8_t user_credential_learn_status_t;
8383

84+
///> Full identifier for a user credential.
85+
typedef struct user_credential_credential_identifier {
86+
user_credential_user_unique_id_t user_unique_id;
87+
user_credential_type_t credential_type;
88+
user_credential_slot_t credential_slot;
89+
} user_credential_credential_identifier_t;
90+
8491
#ifdef __cplusplus
8592
extern "C" {
8693
#endif

applications/zpc/components/zwave_command_classes/src/zwave_command_class_user_credential.cpp

Lines changed: 40 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include <string>
4242
#include <map>
4343
#include <boost/format.hpp>
44+
#include <set>
4445

4546
// Cpp Attribute store
4647
#include "attribute.hpp"
@@ -71,8 +72,23 @@ using namespace user_credential_helpers;
7172
namespace
7273
{
7374
zwave_frame_generator frame_generator(COMMAND_CLASS_USER_CREDENTIAL);
75+
76+
// Callbacks
77+
std::set<user_credential_slot_changed_callback_t> user_credential_slot_changed_callback;
7478
}
7579

80+
/////////////////////////////////////////////////////////////////////////////
81+
// Callbacks
82+
/////////////////////////////////////////////////////////////////////////////
83+
void zwave_command_class_user_credential_set_uuic_slot_changed_callback(
84+
user_credential_slot_changed_callback_t callback)
85+
{
86+
if (callback != nullptr) {
87+
user_credential_slot_changed_callback.insert(callback);
88+
}
89+
}
90+
91+
7692
/////////////////////////////////////////////////////////////////////////////
7793
// Version & Attribute Creation
7894
/////////////////////////////////////////////////////////////////////////////
@@ -1160,17 +1176,12 @@ sl_status_t zwave_command_class_user_credential_uuic_association_report(
11601176
const uint8_t association_status = parser.read_byte();
11611177

11621178
sl_log_debug(LOG_TAG,
1163-
"User Unique Identifier Credential Association Report. Source "
1164-
"User ID: %d / "
1165-
"Source Credential Type: %d / Source Credential Slot: %d / "
1166-
"Destination User ID: %d / Destination Credential Slot: %d",
1167-
"Association status : %d",
1168-
source_user_id,
1169-
source_credential_type,
1170-
source_credential_slot,
1171-
destination_user_id,
1172-
destination_credential_slot,
1173-
association_status);
1179+
"User Unique Identifier Credential Association Report.");
1180+
sl_log_debug(LOG_TAG,"\tSource User ID: %d", source_user_id);
1181+
sl_log_debug(LOG_TAG,"\tSource Credential Type: %d", source_credential_type);
1182+
sl_log_debug(LOG_TAG,"\tSource Credential Slot: %d", source_credential_slot);
1183+
sl_log_debug(LOG_TAG,"\tDestination User ID: %d", destination_user_id);
1184+
sl_log_debug(LOG_TAG,"\tDestination Credential Slot: %d", destination_credential_slot);
11741185

11751186
// Get nodes
11761187
auto source_credential_nodes = get_credential_identifier_nodes(
@@ -1202,22 +1213,17 @@ sl_status_t zwave_command_class_user_credential_uuic_association_report(
12021213
return SL_STATUS_OK;
12031214
}
12041215

1205-
// Simple case : we only have to change the slot number
1206-
if (destination_user_id == source_user_id) {
1207-
sl_log_info(LOG_TAG,
1208-
"Moving slot %d to slot %d (user %d)",
1209-
source_credential_slot,
1210-
destination_credential_slot,
1211-
destination_user_id);
1212-
source_credential_slot_node.set_reported(destination_credential_slot);
1213-
} else {
1214-
// Complex case : we have to move the slot to another user
1215-
sl_log_info(LOG_TAG,
1216-
"Moving slot %d (user %d) to slot %d (user %d)",
1217-
source_credential_slot,
1218-
source_user_id,
1219-
destination_credential_slot,
1220-
destination_user_id);
1216+
sl_log_info(LOG_TAG,
1217+
"Moving slot %d (user %d) to slot %d (user %d)",
1218+
source_credential_slot,
1219+
source_user_id,
1220+
destination_credential_slot,
1221+
destination_user_id);
1222+
source_credential_slot_node.set_reported(destination_credential_slot);
1223+
1224+
// Need to move to new user
1225+
if (destination_user_id != source_user_id) {
1226+
sl_log_debug(LOG_TAG, "Moving slot to new user");
12211227

12221228
// Get destination user node
12231229
auto destination_user_id_node
@@ -1242,8 +1248,14 @@ sl_status_t zwave_command_class_user_credential_uuic_association_report(
12421248
destination_user_id);
12431249
return result;
12441250
}
1251+
}
12451252

1246-
source_credential_slot_node.set_reported(destination_credential_slot);
1253+
// Call MQTT callback if needed to notify that the slot has changed
1254+
for (auto &uicc_slot_changed_callback:
1255+
user_credential_slot_changed_callback) {
1256+
uicc_slot_changed_callback(
1257+
{source_user_id, source_credential_type, source_credential_slot},
1258+
source_credential_slot_node);
12471259
}
12481260
} catch (const std::exception &e) {
12491261
sl_log_error(LOG_TAG,

applications/zpc/components/zwave_command_classes/src/zwave_command_class_user_credential.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,23 @@
3232
extern "C" {
3333
#endif
3434

35+
36+
typedef void (*user_credential_slot_changed_callback_t)(
37+
const user_credential_credential_identifier_t old_credential_slot_id,
38+
const attribute_store_node_t new_credential_node);
39+
40+
void zwave_command_class_user_credential_set_uuic_slot_changed_callback(
41+
user_credential_slot_changed_callback_t callback);
42+
43+
3544
sl_status_t zwave_command_class_user_credential_init();
3645

3746
#ifdef __cplusplus
3847
}
3948
#endif
4049

50+
51+
52+
4153
#endif //ZWAVE_COMMAND_CLASS_USER_CREDENTIAL_H
4254
/** @} end zwave_command_class_user_credential */

applications/zpc/components/zwave_command_classes/src/zwave_command_class_user_credential_api.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,6 @@ sl_status_t zwave_command_class_user_credential_get_credential_checksum(
344344
attribute_store_node_t endpoint_node,
345345
user_credential_type_t credential_type);
346346

347-
348347
#ifdef __cplusplus
349348
}
350349
#endif

0 commit comments

Comments
 (0)