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);
0 commit comments