From 92eed1390eb3336fc81af71a088eeebb0eca4c96 Mon Sep 17 00:00:00 2001 From: Markus Becker Date: Mon, 29 Mar 2021 11:01:47 +0200 Subject: [PATCH 01/13] Add Occupancy sensor from SimplicityStudio v5 --- .../occupancy-sensor-server.c | 182 ++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.c diff --git a/src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.c b/src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.c new file mode 100644 index 00000000000000..db62d5de6ad0a4 --- /dev/null +++ b/src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.c @@ -0,0 +1,182 @@ +/***************************************************************************//** + * @file + * @brief Generic occupancy sensor server implementation. + * Requires a HAL plugin that implements the occupancy API to be included + * in the project to provide APIs and callbacks for initialization and device + * management. + * Populates the Occupancy and Occupancy Sensor Type attributes of the + * occupancy sensor cluster. + ******************************************************************************* + * # License + * Copyright 2018 Silicon Laboratories Inc. www.silabs.com + ******************************************************************************* + * + * The licensor of this software is Silicon Laboratories Inc. Your use of this + * software is governed by the terms of Silicon Labs Master Software License + * Agreement (MSLA) available at + * www.silabs.com/about-us/legal/master-software-license-agreement. This + * software is distributed to you in Source Code format and is governed by the + * sections of the MSLA applicable to Source Code. + * + ******************************************************************************/ + +#include "app/framework/include/af.h" +#include EMBER_AF_API_OCCUPANCY + +#ifdef EMBER_AF_PLUGIN_REPORTING +#include "app/framework/plugin/reporting/reporting.h" +#endif + +//------------------------------------------------------------------------------ +// Plugin private function prototypes +static void writeServerAttributeForAllEndpoints(EmberAfAttributeId attributeID, + uint8_t* dataPtr, + uint8_t attributeType); +static void checkForReportingConfig(void); + +//------------------------------------------------------------------------------ +// Global variables + +// The default configuration to be used if no reporting has been set up +static EmberAfPluginReportingEntry defaultConfiguration = { + EMBER_ZCL_REPORTING_DIRECTION_REPORTED, //direction + 0, //endpoint, which will be set on a per-use basis + ZCL_OCCUPANCY_SENSING_CLUSTER_ID, //clusterId + ZCL_OCCUPANCY_ATTRIBUTE_ID, //attributeId + CLUSTER_MASK_SERVER, //mask + EMBER_AF_NULL_MANUFACTURER_CODE, //manufacturerCode + .data.reported = { + 1, //minInterval + EMBER_AF_PLUGIN_OCCUPANCY_SENSOR_SERVER_DEFAULT_OCCUPANCY_MAX_REPORT_PERIOD_S, //maxInterval + 1 //reportableChange + } +}; + +//------------------------------------------------------------------------------ +// Plugin consumed callback implementations + +//****************************************************************************** +// Plugin init function +//****************************************************************************** +void emberAfPluginOccupancySensorServerInitCallback(void) +{ + HalOccupancySensorType deviceType; + + checkForReportingConfig(); + deviceType = halOccupancyGetSensorType(); + writeServerAttributeForAllEndpoints(ZCL_OCCUPANCY_SENSOR_TYPE_ATTRIBUTE_ID, + (uint8_t *) &deviceType, + ZCL_ENUM8_ATTRIBUTE_TYPE); + + uint8_t deviceTypeBitmap = 0; + switch (deviceType) { + case HAL_OCCUPANCY_SENSOR_TYPE_PIR: + deviceTypeBitmap = EMBER_AF_OCCUPANCY_SENSOR_TYPE_BITMAP_PIR; + break; + + case HAL_OCCUPANCY_SENSOR_TYPE_ULTRASONIC: + deviceTypeBitmap = EMBER_AF_OCCUPANCY_SENSOR_TYPE_BITMAP_ULTRASONIC; + break; + + case HAL_OCCUPANCY_SENSOR_TYPE_PIR_AND_ULTRASONIC: + deviceTypeBitmap = (EMBER_AF_OCCUPANCY_SENSOR_TYPE_BITMAP_PIR + | EMBER_AF_OCCUPANCY_SENSOR_TYPE_BITMAP_ULTRASONIC); + break; + + default: + break; + } + writeServerAttributeForAllEndpoints(ZCL_OCCUPANCY_SENSOR_TYPE_BITMAP_ATTRIBUTE_ID, + (uint8_t *) &deviceTypeBitmap, + ZCL_BITMAP8_ATTRIBUTE_TYPE); +} + +//****************************************************************************** +// Notification callback from the HAL plugin +//****************************************************************************** +void halOccupancyStateChangedCallback(HalOccupancyState occupancyState) +{ + if (occupancyState == HAL_OCCUPANCY_STATE_OCCUPIED) { + emberAfOccupancySensingClusterPrintln("Occupancy detected"); + } else { + emberAfOccupancySensingClusterPrintln("Occupancy no longer detected"); + } + + writeServerAttributeForAllEndpoints(ZCL_OCCUPANCY_ATTRIBUTE_ID, + (uint8_t *) &occupancyState, + ZCL_BITMAP8_ATTRIBUTE_TYPE); + emberAfPluginOccupancySensorServerOccupancyStateChangedCallback( + occupancyState); +} + +void emberAfPluginOccupancySensorServerStackStatusCallback( + EmberStatus status) +{ + // On network connect, verify that a reporting entry is set up for the + // occupancy sensor + if (status == EMBER_NETWORK_UP) { + checkForReportingConfig(); + } +} + +//------------------------------------------------------------------------------ +// Plugin private functions + +static void checkForReportingConfig(void) +{ +#ifdef EMBER_AF_PLUGIN_REPORTING + uint16_t i; + EmberAfPluginReportingEntry entry; + uint8_t endpoint; + bool existingEntry = false; + + // On initialization, cycle through the reporting table to determine if a + // reporting table entry has been created for the occupancy state attribute + for (i = 0; i < emAfPluginReportingNumEntries(); i++) { + emAfPluginReportingGetEntry(i, &entry); + if ((entry.clusterId == ZCL_OCCUPANCY_SENSING_CLUSTER_ID) + && (entry.attributeId == ZCL_OCCUPANCY_ATTRIBUTE_ID) + && (entry.direction == EMBER_ZCL_REPORTING_DIRECTION_REPORTED) + && (entry.manufacturerCode == EMBER_AF_NULL_MANUFACTURER_CODE)) { + existingEntry = true; + } + } + + // If no entry is found for the occupancy sensor, a default reporting + // configuration should be created using the plugin defined options. This + // needs to be done for all endpoints that support an occupancy sensor server. + if (!existingEntry) { + for (i = 0; i < emberAfEndpointCount(); i++) { + endpoint = emberAfEndpointFromIndex(i); + defaultConfiguration.endpoint = endpoint; + if (emberAfContainsServer(endpoint, ZCL_OCCUPANCY_SENSING_CLUSTER_ID)) { + emAfPluginReportingAppendEntry(&defaultConfiguration); + } + } + } +#endif +} + +//****************************************************************************** +// Cycle through the list of all endpoints in the system and write the given +// attribute of the occupancy sensing cluster for all endpoints in the system +// are servers of that cluster. +//****************************************************************************** +static void writeServerAttributeForAllEndpoints(EmberAfAttributeId attributeID, + uint8_t* dataPtr, + uint8_t attributeType) +{ + uint8_t i; + uint8_t endpoint; + + for (i = 0; i < emberAfEndpointCount(); i++) { + endpoint = emberAfEndpointFromIndex(i); + if (emberAfContainsServer(endpoint, ZCL_OCCUPANCY_SENSING_CLUSTER_ID)) { + emberAfWriteServerAttribute(endpoint, + ZCL_OCCUPANCY_SENSING_CLUSTER_ID, + attributeID, + dataPtr, + attributeType); + } + } +} From f6356d5f6c8ec519a0085b2498023ce8bb22a0a4 Mon Sep 17 00:00:00 2001 From: Markus Becker Date: Mon, 29 Mar 2021 11:03:15 +0200 Subject: [PATCH 02/13] Move to cpp --- .../{occupancy-sensor-server.c => occupancy-sensor-server.cpp} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/app/clusters/occupancy-sensor-server/{occupancy-sensor-server.c => occupancy-sensor-server.cpp} (100%) diff --git a/src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.c b/src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.cpp similarity index 100% rename from src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.c rename to src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.cpp From 1709ca98691b3d32da2129b809ffcf34d6ca4369 Mon Sep 17 00:00:00 2001 From: Markus Becker Date: Tue, 30 Mar 2021 13:24:16 +0200 Subject: [PATCH 03/13] Adapt Occupancy Sensor Server Cluster to CHIP --- .../occupancy-sensor-server/occupancy-hal.h | 63 ++++++ .../occupancy-sensor-server.cpp | 199 ++++++++++-------- .../occupancy-sensor-server.h | 32 +++ 3 files changed, 201 insertions(+), 93 deletions(-) create mode 100644 src/app/clusters/occupancy-sensor-server/occupancy-hal.h create mode 100644 src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.h diff --git a/src/app/clusters/occupancy-sensor-server/occupancy-hal.h b/src/app/clusters/occupancy-sensor-server/occupancy-hal.h new file mode 100644 index 00000000000000..2e6ec7b47a8b37 --- /dev/null +++ b/src/app/clusters/occupancy-sensor-server/occupancy-hal.h @@ -0,0 +1,63 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +//#include +#include + +// enum used to track the type of occupancy sensor being implemented +typedef enum { + HAL_OCCUPANCY_SENSOR_TYPE_PIR = 0x00, + HAL_OCCUPANCY_SENSOR_TYPE_ULTRASONIC = 0x01, + HAL_OCCUPANCY_SENSOR_TYPE_PIR_AND_ULTRASONIC = 0x02, + HAL_OCCUPANCY_SENSOR_TYPE_PHYSICAL = 0x03, +} HalOccupancySensorType; + +typedef enum { + HAL_OCCUPANCY_STATE_UNOCCUPIED = 0x00, + HAL_OCCUPANCY_STATE_OCCUPIED = 0x01, + +} HalOccupancyState; + +/** @brief Initializes the occupancy sensor, along with any hardware + * peripherals necessary to interface with the hardware. The application + * framework will generally initialize this plugin automatically. Customers who + * do not use the framework must ensure the plugin is initialized by calling + * this function. + */ +void halOccupancyInit(chip::EndpointId endpoint); + +/** @brief Get the hardware mechanism used to detect occupancy + * + * This function should be used to determine what kind of hardware mechanism + * is driving the occupancy functionality. + * + * @return HAL_OCCUPANCY_SENSOR_TYPE_PIR, HAL_OCCUPANCY_SENSOR_TYPE_ULTRASONIC, + * or HAL_OCCUPANCY_SENSOR_TYPE_PIR_AND_ULTRASONIC, which are defined to match + * the values used by the ZCL defined SensorType attribute + */ +HalOccupancySensorType halOccupancyGetSensorType(chip::EndpointId endpoint); + +/** @brief Notify the system of a change in occupancy state + * + * This function will be called whenever the occupancy state of the system + * changes. + * + * @param occupancyState The new occupancy state + */ +void halOccupancyStateChangedCallback(chip::EndpointId endpoint, HalOccupancyState occupancyState); diff --git a/src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.cpp b/src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.cpp index db62d5de6ad0a4..9090f85951c86e 100644 --- a/src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.cpp +++ b/src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.cpp @@ -1,42 +1,73 @@ -/***************************************************************************//** - * @file - * @brief Generic occupancy sensor server implementation. - * Requires a HAL plugin that implements the occupancy API to be included - * in the project to provide APIs and callbacks for initialization and device - * management. - * Populates the Occupancy and Occupancy Sensor Type attributes of the - * occupancy sensor cluster. - ******************************************************************************* - * # License - * Copyright 2018 Silicon Laboratories Inc. www.silabs.com - ******************************************************************************* +/** + * + * Copyright (c) 2020 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * + * Copyright (c) 2020 Silicon Labs * - * The licensor of this software is Silicon Laboratories Inc. Your use of this - * software is governed by the terms of Silicon Labs Master Software License - * Agreement (MSLA) available at - * www.silabs.com/about-us/legal/master-software-license-agreement. This - * software is distributed to you in Source Code format and is governed by the - * sections of the MSLA applicable to Source Code. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/***************************************************************************/ +/** + * @file + * @brief Routines for the Occupancy plugin, which + *implements the Occupancy server cluster. + ******************************************************************************* ******************************************************************************/ +#include "occupancy-sensor-server.h" + +#include -#include "app/framework/include/af.h" -#include EMBER_AF_API_OCCUPANCY +#include +#include + +#include "gen/att-storage.h" +#include "gen/attribute-id.h" +#include "gen/attribute-type.h" +#include "gen/cluster-id.h" +#include "gen/command-id.h" +#include "gen/enums.h" + +#include "occupancy-hal.h" #ifdef EMBER_AF_PLUGIN_REPORTING -#include "app/framework/plugin/reporting/reporting.h" +#include #endif + +using namespace chip; + //------------------------------------------------------------------------------ // Plugin private function prototypes -static void writeServerAttributeForAllEndpoints(EmberAfAttributeId attributeID, - uint8_t* dataPtr, - uint8_t attributeType); static void checkForReportingConfig(void); //------------------------------------------------------------------------------ // Global variables - +/* // The default configuration to be used if no reporting has been set up static EmberAfPluginReportingEntry defaultConfiguration = { EMBER_ZCL_REPORTING_DIRECTION_REPORTED, //direction @@ -51,22 +82,22 @@ static EmberAfPluginReportingEntry defaultConfiguration = { 1 //reportableChange } }; - +*/ //------------------------------------------------------------------------------ // Plugin consumed callback implementations //****************************************************************************** // Plugin init function //****************************************************************************** -void emberAfPluginOccupancySensorServerInitCallback(void) +void emberAfOccupancySensingClusterServerInitCallback(chip::EndpointId endpoint) { HalOccupancySensorType deviceType; checkForReportingConfig(); - deviceType = halOccupancyGetSensorType(); - writeServerAttributeForAllEndpoints(ZCL_OCCUPANCY_SENSOR_TYPE_ATTRIBUTE_ID, - (uint8_t *) &deviceType, - ZCL_ENUM8_ATTRIBUTE_TYPE); + deviceType = halOccupancyGetSensorType(endpoint); + + emberAfWriteAttribute(endpoint, ZCL_OCCUPANCY_SENSING_CLUSTER_ID, ZCL_OCCUPANCY_SENSOR_TYPE_ATTRIBUTE_ID, CLUSTER_MASK_SERVER, + (uint8_t *) &deviceType, ZCL_ENUM8_ATTRIBUTE_TYPE); uint8_t deviceTypeBitmap = 0; switch (deviceType) { @@ -83,18 +114,23 @@ void emberAfPluginOccupancySensorServerInitCallback(void) | EMBER_AF_OCCUPANCY_SENSOR_TYPE_BITMAP_ULTRASONIC); break; + case HAL_OCCUPANCY_SENSOR_TYPE_PHYSICAL: + deviceTypeBitmap = EMBER_AF_OCCUPANCY_SENSOR_TYPE_BITMAP_PHYSICAL_CONTACT; + break; + default: break; } - writeServerAttributeForAllEndpoints(ZCL_OCCUPANCY_SENSOR_TYPE_BITMAP_ATTRIBUTE_ID, - (uint8_t *) &deviceTypeBitmap, - ZCL_BITMAP8_ATTRIBUTE_TYPE); + emberAfWriteAttribute(endpoint, ZCL_OCCUPANCY_SENSING_CLUSTER_ID, ZCL_OCCUPANCY_SENSOR_TYPE_BITMAP_ATTRIBUTE_ID, CLUSTER_MASK_SERVER, + (uint8_t *) &deviceTypeBitmap, ZCL_BITMAP8_ATTRIBUTE_TYPE); + + emberAfPluginOccupancyClusterServerPostInitCallback(endpoint); } //****************************************************************************** // Notification callback from the HAL plugin //****************************************************************************** -void halOccupancyStateChangedCallback(HalOccupancyState occupancyState) +void halOccupancyStateChangedCallback(EndpointId endpoint, HalOccupancyState occupancyState) { if (occupancyState == HAL_OCCUPANCY_STATE_OCCUPIED) { emberAfOccupancySensingClusterPrintln("Occupancy detected"); @@ -102,15 +138,14 @@ void halOccupancyStateChangedCallback(HalOccupancyState occupancyState) emberAfOccupancySensingClusterPrintln("Occupancy no longer detected"); } - writeServerAttributeForAllEndpoints(ZCL_OCCUPANCY_ATTRIBUTE_ID, - (uint8_t *) &occupancyState, - ZCL_BITMAP8_ATTRIBUTE_TYPE); - emberAfPluginOccupancySensorServerOccupancyStateChangedCallback( - occupancyState); + emberAfWriteAttribute(endpoint, ZCL_OCCUPANCY_SENSING_CLUSTER_ID, ZCL_OCCUPANCY_ATTRIBUTE_ID, CLUSTER_MASK_SERVER, + (uint8_t *) &occupancyState, ZCL_BITMAP8_ATTRIBUTE_TYPE); + // emberAfPluginOccupancySensorServerOccupancyStateChangedCallback( + // endpoint, occupancyState); } void emberAfPluginOccupancySensorServerStackStatusCallback( - EmberStatus status) + EndpointId endpoint, EmberStatus status) { // On network connect, verify that a reporting entry is set up for the // occupancy sensor @@ -125,58 +160,36 @@ void emberAfPluginOccupancySensorServerStackStatusCallback( static void checkForReportingConfig(void) { #ifdef EMBER_AF_PLUGIN_REPORTING - uint16_t i; - EmberAfPluginReportingEntry entry; - uint8_t endpoint; - bool existingEntry = false; - - // On initialization, cycle through the reporting table to determine if a - // reporting table entry has been created for the occupancy state attribute - for (i = 0; i < emAfPluginReportingNumEntries(); i++) { - emAfPluginReportingGetEntry(i, &entry); - if ((entry.clusterId == ZCL_OCCUPANCY_SENSING_CLUSTER_ID) - && (entry.attributeId == ZCL_OCCUPANCY_ATTRIBUTE_ID) - && (entry.direction == EMBER_ZCL_REPORTING_DIRECTION_REPORTED) - && (entry.manufacturerCode == EMBER_AF_NULL_MANUFACTURER_CODE)) { - existingEntry = true; - } - } - - // If no entry is found for the occupancy sensor, a default reporting - // configuration should be created using the plugin defined options. This - // needs to be done for all endpoints that support an occupancy sensor server. - if (!existingEntry) { - for (i = 0; i < emberAfEndpointCount(); i++) { - endpoint = emberAfEndpointFromIndex(i); - defaultConfiguration.endpoint = endpoint; - if (emberAfContainsServer(endpoint, ZCL_OCCUPANCY_SENSING_CLUSTER_ID)) { - emAfPluginReportingAppendEntry(&defaultConfiguration); - } - } - } + // uint16_t i; + // EmberAfPluginReportingEntry entry; + // uint8_t endpoint; + // bool existingEntry = false; + + // // On initialization, cycle through the reporting table to determine if a + // // reporting table entry has been created for the occupancy state attribute + // for (i = 0; i < emAfPluginReportingNumEntries(); i++) { + // emAfPluginReportingGetEntry(i, &entry); + // if ((entry.clusterId == ZCL_OCCUPANCY_SENSING_CLUSTER_ID) + // && (entry.attributeId == ZCL_OCCUPANCY_ATTRIBUTE_ID) + // && (entry.direction == EMBER_ZCL_REPORTING_DIRECTION_REPORTED) + // && (entry.manufacturerCode == EMBER_AF_NULL_MANUFACTURER_CODE)) { + // existingEntry = true; + // } + // } + + // // If no entry is found for the occupancy sensor, a default reporting + // // configuration should be created using the plugin defined options. This + // // needs to be done for all endpoints that support an occupancy sensor server. + // if (!existingEntry) { + // for (i = 0; i < emberAfEndpointCount(); i++) { + // endpoint = emberAfEndpointFromIndex(i); + // defaultConfiguration.endpoint = endpoint; + // if (emberAfContainsServer(endpoint, ZCL_OCCUPANCY_SENSING_CLUSTER_ID)) { + // emAfPluginReportingAppendEntry(&defaultConfiguration); + // } + // } + // } #endif } -//****************************************************************************** -// Cycle through the list of all endpoints in the system and write the given -// attribute of the occupancy sensing cluster for all endpoints in the system -// are servers of that cluster. -//****************************************************************************** -static void writeServerAttributeForAllEndpoints(EmberAfAttributeId attributeID, - uint8_t* dataPtr, - uint8_t attributeType) -{ - uint8_t i; - uint8_t endpoint; - - for (i = 0; i < emberAfEndpointCount(); i++) { - endpoint = emberAfEndpointFromIndex(i); - if (emberAfContainsServer(endpoint, ZCL_OCCUPANCY_SENSING_CLUSTER_ID)) { - emberAfWriteServerAttribute(endpoint, - ZCL_OCCUPANCY_SENSING_CLUSTER_ID, - attributeID, - dataPtr, - attributeType); - } - } -} +void emberAfPluginOccupancyClusterServerPostInitCallback(EndpointId endpoint) {} diff --git a/src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.h b/src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.h new file mode 100644 index 00000000000000..ea81bb3c0736e2 --- /dev/null +++ b/src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.h @@ -0,0 +1,32 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +/** @brief Occupancy Cluster Server Post Init + * + * Following resolution of the Occupancy state at startup for this endpoint, + * perform any additional initialization needed; e.g., synchronize hardware + * state. + * + * @param endpoint Endpoint that is being initialized Ver.: always + */ +void emberAfPluginOccupancyClusterServerPostInitCallback(chip::EndpointId endpoint); + From ff4e294b92bcd892215af568339c7205bfd93d5b Mon Sep 17 00:00:00 2001 From: Markus Becker Date: Thu, 8 Apr 2021 12:15:02 +0200 Subject: [PATCH 04/13] Add Occupancy Sensor Server Cluster to all-clusters-app --- .../all-clusters-common/all-clusters-app.zap | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap b/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap index 23a72f9b0d60ef..4566461a4677dd 100644 --- a/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap +++ b/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap @@ -13020,6 +13020,103 @@ } ] }, + { + "name": "Occupancy Sensing", + "code": 1030, + "mfgCode": null, + "define": "OCCUPANCY_SENSING_CLUSTER", + "side": "client", + "enabled": 0, + "commands": [], + "attributes": [ + { + "name": "cluster revision", + "code": 65533, + "mfgCode": null, + "side": "client", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "2", + "reportable": 0, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Occupancy Sensing", + "code": 1030, + "mfgCode": null, + "define": "OCCUPANCY_SENSING_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [], + "attributes": [ + { + "name": "cluster revision", + "code": 65533, + "mfgCode": null, + "side": "server", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "2", + "reportable": 0, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "occupancy", + "code": 0, + "mfgCode": null, + "side": "server", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "occupancy sensor type", + "code": 1, + "mfgCode": null, + "side": "server", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 0, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "occupancy sensor type bitmap", + "code": 2, + "mfgCode": null, + "side": "server", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 0, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, { "name": "Temperature Measurement", "code": 1026, From 567211d1c225f94f77b5ffec6afea46c1408ff13 Mon Sep 17 00:00:00 2001 From: Markus Becker Date: Wed, 31 Mar 2021 14:27:34 +0200 Subject: [PATCH 05/13] Add Occupancy Sensing to the list of objects with init function --- src/app/zap-templates/templates/app/helper.js | 236 ++++++++---------- 1 file changed, 108 insertions(+), 128 deletions(-) diff --git a/src/app/zap-templates/templates/app/helper.js b/src/app/zap-templates/templates/app/helper.js index 7a9a6e4bf67066..c253620c82c854 100644 --- a/src/app/zap-templates/templates/app/helper.js +++ b/src/app/zap-templates/templates/app/helper.js @@ -16,14 +16,14 @@ */ // Import helpers from zap core -const zapPath = '../../../../../third_party/zap/repo/src-electron/'; -const queryImpexp = require(zapPath + 'db/query-impexp.js') +const zapPath = '../../../../../third_party/zap/repo/src-electron/'; +const queryImpexp = require(zapPath + 'db/query-impexp.js') const templateUtil = require(zapPath + 'generator/template-util.js') -const zclHelper = require(zapPath + 'generator/helper-zcl.js') -const zclQuery = require(zapPath + 'db/query-zcl.js') -const cHelper = require(zapPath + 'generator/helper-c.js') +const zclHelper = require(zapPath + 'generator/helper-zcl.js') +const zclQuery = require(zapPath + 'db/query-zcl.js') +const cHelper = require(zapPath + 'generator/helper-c.js') -const StringHelper = require('../../common/StringHelper.js'); +const StringHelper = require('../../common/StringHelper.js'); const ChipTypesHelper = require('../../common/ChipTypesHelper.js'); /** @@ -35,38 +35,35 @@ const ChipTypesHelper = require('../../common/ChipTypesHelper.js'); * @param {*} options * @returns True if cluster has enabled commands otherwise false */ -function user_cluster_has_enabled_manufacturer_command(name, side, options) -{ +function user_cluster_has_enabled_manufacturer_command(name, side, options) { return queryImpexp.exportEndPointTypeIds(this.global.db, this.global.sessionId) - .then((endpointTypes) => zclQuery.exportClustersAndEndpointDetailsFromEndpointTypes(this.global.db, endpointTypes)) - .then((endpointsAndClusters) => zclQuery.exportCommandDetailsFromAllEndpointTypesAndClusters( - this.global.db, endpointsAndClusters)) - .then((endpointCommands) => { - return !!endpointCommands.find(cmd => cmd.mfgCode && zclHelper.isStrEqual(name, cmd.clusterName) - && zclHelper.isCommandAvailable(side, cmd.incoming, cmd.outgoing, cmd.commandSource, cmd.name)); - }) + .then((endpointTypes) => zclQuery.exportClustersAndEndpointDetailsFromEndpointTypes(this.global.db, endpointTypes)) + .then((endpointsAndClusters) => zclQuery.exportCommandDetailsFromAllEndpointTypesAndClusters( + this.global.db, endpointsAndClusters)) + .then((endpointCommands) => { + return !!endpointCommands.find(cmd => cmd.mfgCode && zclHelper.isStrEqual(name, cmd.clusterName) + && zclHelper.isCommandAvailable(side, cmd.incoming, cmd.outgoing, cmd.commandSource, cmd.name)); + }) } -function asValueIfNotPresent(type, isArray) -{ +function asValueIfNotPresent(type, isArray) { if (StringHelper.isString(type) || isArray) { return 'NULL'; } - function fn(pkgId) - { - const options = { 'hash' : {} }; + function fn(pkgId) { + const options = { 'hash': {} }; return zclHelper.asUnderlyingZclType.call(this, type, options).then(zclType => { switch (zclType) { - case 'uint8_t': - return 'UINT8_MAX'; - case 'uint16_t': - return 'UINT16_MAX'; - case 'uint32_t': - return 'UINT32_MAX'; - default: - error = 'Unhandled underlying type ' + zclType + ' for original type ' + type; - throw error; + case 'uint8_t': + return 'UINT8_MAX'; + case 'uint16_t': + return 'UINT16_MAX'; + case 'uint32_t': + return 'UINT32_MAX'; + default: + error = 'Unhandled underlying type ' + zclType + ' for original type ' + type; + throw error; } }) } @@ -77,8 +74,7 @@ function asValueIfNotPresent(type, isArray) // TODO Expose the readTypeLength as an additional member field of {{asUnderlyingZclType}} instead // of having to call this method separately. -function asReadTypeLength(type) -{ +function asReadTypeLength(type) { const db = this.global.db; if (StringHelper.isShortString(type)) { @@ -89,8 +85,7 @@ function asReadTypeLength(type) return '2u'; } - function fn(pkgId) - { + function fn(pkgId) { const defaultResolver = zclQuery.selectAtomicType(db, pkgId, type); const enumResolver = zclHelper.isEnum(db, type, pkgId).then(result => { @@ -105,7 +100,7 @@ function asReadTypeLength(type) }); }); - const typeResolver = Promise.all([ defaultResolver, enumResolver, bitmapResolver ]); + const typeResolver = Promise.all([defaultResolver, enumResolver, bitmapResolver]); return typeResolver.then(types => (types.find(type => type)).size); } @@ -115,8 +110,7 @@ function asReadTypeLength(type) // TODO Expose the readType as an additional member field of {{asUnderlyingZclType}} instead // of having to call this method separately. -function asReadType(type) -{ +function asReadType(type) { if (StringHelper.isShortString(type)) { return 'String'; } @@ -125,30 +119,29 @@ function asReadType(type) return 'LongString'; } - function fn(pkgId) - { - const options = { 'hash' : {} }; + function fn(pkgId) { + const options = { 'hash': {} }; return zclHelper.asUnderlyingZclType.call(this, type, options).then(zclType => { const basicType = ChipTypesHelper.asBasicType(zclType); switch (basicType) { - case 'int8_t': - case 'uint8_t': - return 'Int8u'; - case 'int16_t': - case 'uint16_t': - return 'Int16u'; - case 'int24_t': - case 'uint24_t': - return 'Int24u'; - case 'int32_t': - case 'uint32_t': - return 'Int32u'; - case 'int64_t': - case 'uint64_t': - return 'Int64u'; - default: - error = 'Unhandled underlying type ' + zclType + ' for original type ' + type; - throw error; + case 'int8_t': + case 'uint8_t': + return 'Int8u'; + case 'int16_t': + case 'uint16_t': + return 'Int16u'; + case 'int24_t': + case 'uint24_t': + return 'Int24u'; + case 'int32_t': + case 'uint32_t': + return 'Int32u'; + case 'int64_t': + case 'uint64_t': + return 'Int64u'; + default: + error = 'Unhandled underlying type ' + zclType + ' for original type ' + type; + throw error; } }) } @@ -166,8 +159,7 @@ function asReadType(type) * @param {*} label : The xml label of the type. * @param {*} type : The xml type to be converted */ -function asChipUnderlyingType(label, type) -{ +function asChipUnderlyingType(label, type) { if (zclHelper.isStrEqual(label, "endpoint")) { return 'chip::EndpointId'; @@ -184,7 +176,7 @@ function asChipUnderlyingType(label, type) } else if (type == 'OCTET_STRING') { return 'chip::ByteSpan'; } else { - const options = { 'hash' : {} }; + const options = { 'hash': {} }; return zclHelper.asUnderlyingZclType.call(this, type, options); } } @@ -195,17 +187,16 @@ function asChipUnderlyingType(label, type) // These helpers only works within the endpoint_config iterator // List of all cluster with generated functions -var endpointClusterWithInit = [ 'Basic', 'Identify', 'Groups', 'Scenes', 'On/off', 'Level Control', 'Color Control', 'IAS Zone' ]; -var endpointClusterWithAttributeChanged = [ 'Identify', 'Door Lock' ]; -var endpointClusterWithPreAttribute = [ 'IAS Zone' ]; -var endpointClusterWithMessageSent = [ 'IAS Zone' ]; +var endpointClusterWithInit = ['Basic', 'Identify', 'Groups', 'Scenes', 'Occupancy Sensing', 'On/off', 'Level Control', 'Color Control', 'IAS Zone']; +var endpointClusterWithAttributeChanged = ['Identify', 'Door Lock']; +var endpointClusterWithPreAttribute = ['IAS Zone']; +var endpointClusterWithMessageSent = ['IAS Zone']; /** * extract the cluster name from the enpoint cluster comment * @param {*} comments */ -function extract_cluster_name(comments) -{ +function extract_cluster_name(comments) { let secondPart = comments.split(": ").pop(); return secondPart.split(" (")[0]; } @@ -213,12 +204,11 @@ function extract_cluster_name(comments) /** * Populate the GENERATED_FUNCTIONS field */ -function chip_endpoint_generated_functions() -{ +function chip_endpoint_generated_functions() { let alreadySetCluster = []; - let ret = '\\\n'; + let ret = '\\\n'; this.clusterList.forEach((c) => { - let clusterName = extract_cluster_name(c.comment); + let clusterName = extract_cluster_name(c.comment); let functionList = ''; if (alreadySetCluster.includes(clusterName)) { // Only one array of Generated functions per cluster across all endpoints @@ -226,34 +216,30 @@ function chip_endpoint_generated_functions() } if (c.comment.includes('server')) { let hasFunctionArray = false - if (endpointClusterWithInit.includes(clusterName)) - { + if (endpointClusterWithInit.includes(clusterName)) { hasFunctionArray = true - functionList = functionList.concat( - ` (EmberAfGenericClusterFunction) emberAf${cHelper.asCamelCased(clusterName, false)}ClusterServerInitCallback,\\\n`) + functionList = functionList.concat( + ` (EmberAfGenericClusterFunction) emberAf${cHelper.asCamelCased(clusterName, false)}ClusterServerInitCallback,\\\n`) } if (endpointClusterWithAttributeChanged.includes(clusterName)) { - functionList = functionList.concat(` (EmberAfGenericClusterFunction) emberAf${ - cHelper.asCamelCased(clusterName, false)}ClusterServerAttributeChangedCallback,\\\n`) + functionList = functionList.concat(` (EmberAfGenericClusterFunction) emberAf${cHelper.asCamelCased(clusterName, false)}ClusterServerAttributeChangedCallback,\\\n`) hasFunctionArray = true } if (endpointClusterWithMessageSent.includes(clusterName)) { - functionList = functionList.concat(` (EmberAfGenericClusterFunction) emberAf${ - cHelper.asCamelCased(clusterName, false)}ClusterServerMessageSentCallback,\\\n`) + functionList = functionList.concat(` (EmberAfGenericClusterFunction) emberAf${cHelper.asCamelCased(clusterName, false)}ClusterServerMessageSentCallback,\\\n`) hasFunctionArray = true } if (endpointClusterWithPreAttribute.includes(clusterName)) { - functionList = functionList.concat(` (EmberAfGenericClusterFunction) emberAf${ - cHelper.asCamelCased(clusterName, false)}ClusterServerPreAttributeChangedCallback,\\\n`) + functionList = functionList.concat(` (EmberAfGenericClusterFunction) emberAf${cHelper.asCamelCased(clusterName, false)}ClusterServerPreAttributeChangedCallback,\\\n`) hasFunctionArray = true } if (hasFunctionArray) { ret = ret.concat( - `const EmberAfGenericClusterFunction chipFuncArray${cHelper.asCamelCased(clusterName, false)}Server[] = {\\\n`) + `const EmberAfGenericClusterFunction chipFuncArray${cHelper.asCamelCased(clusterName, false)}Server[] = {\\\n`) ret = ret.concat(functionList) ret = ret.concat(`};\\\n`) alreadySetCluster.push(clusterName) @@ -268,13 +254,12 @@ function chip_endpoint_generated_functions() * To be used as a replacement of endpoint_cluster_list since this one * includes the GENERATED_FUNCTIONS array */ -function chip_endpoint_cluster_list() -{ +function chip_endpoint_cluster_list() { let ret = '{ \\\n'; this.clusterList.forEach((c) => { - let mask = ''; + let mask = ''; let functionArray = c.functions; - let clusterName = extract_cluster_name(c.comment); + let clusterName = extract_cluster_name(c.comment); if (c.comment.includes('server')) { let hasFunctionArray = false; @@ -308,48 +293,45 @@ function chip_endpoint_cluster_list() } else { mask = c.mask.map((m) => `ZAP_CLUSTER_MASK(${m.toUpperCase()})`).join(' | ') } - ret = ret.concat(` { ${c.clusterId}, ZAP_ATTRIBUTE_INDEX(${c.attributeIndex}), ${c.attributeCount}, ${c.attributeSize}, ${ - mask}, ${functionArray} }, /* ${c.comment} */ \\\n`) + ret = ret.concat(` { ${c.clusterId}, ZAP_ATTRIBUTE_INDEX(${c.attributeIndex}), ${c.attributeCount}, ${c.attributeSize}, ${mask}, ${functionArray} }, /* ${c.comment} */ \\\n`) }) return ret.concat('}\n'); } // End of Endpoint-config specific helpers -function asPrintFormat(type) -{ +function asPrintFormat(type) { if (StringHelper.isString(type)) { return '%s'; } - function fn(pkgId) - { - const options = { 'hash' : {} }; + function fn(pkgId) { + const options = { 'hash': {} }; return zclHelper.asUnderlyingZclType.call(this, type, options).then(zclType => { const basicType = ChipTypesHelper.asBasicType(zclType); switch (basicType) { - case 'int8_t': - return '%" PRId8 "'; - case 'uint8_t': - return '%" PRIu8 "'; - case 'int16_t': - return '%" PRId16 "'; - case 'uint16_t': - return '%" PRIu16 "'; - case 'int24_t': - return '%" PRId32 "'; - case 'uint24_t': - return '%" PRIu32 "'; - case 'int32_t': - return '%" PRId32 "'; - case 'uint32_t': - return '%" PRIu32 "'; - case 'int64_t': - return '%" PRId64 "'; - case 'uint64_t': - return '%" PRIu64 "'; - default: - return '%p'; + case 'int8_t': + return '%" PRId8 "'; + case 'uint8_t': + return '%" PRIu8 "'; + case 'int16_t': + return '%" PRId16 "'; + case 'uint16_t': + return '%" PRIu16 "'; + case 'int24_t': + return '%" PRId32 "'; + case 'uint24_t': + return '%" PRIu32 "'; + case 'int32_t': + return '%" PRId32 "'; + case 'uint32_t': + return '%" PRIu32 "'; + case 'int64_t': + return '%" PRId64 "'; + case 'uint64_t': + return '%" PRIu64 "'; + default: + return '%p'; } }) } @@ -358,27 +340,25 @@ function asPrintFormat(type) return templateUtil.templatePromise(this.global, promise) } -function isFirstElement(index) -{ +function isFirstElement(index) { return index == 0; } -function isStrEndsWith(str, substr) -{ +function isStrEndsWith(str, substr) { return str.endsWith(substr); } // // Module exports // -exports.asPrintFormat = asPrintFormat; -exports.asReadType = asReadType; -exports.asReadTypeLength = asReadTypeLength; -exports.asValueIfNotPresent = asValueIfNotPresent; -exports.asChipUnderlyingType = asChipUnderlyingType; -exports.isFirstElement = isFirstElement; +exports.asPrintFormat = asPrintFormat; +exports.asReadType = asReadType; +exports.asReadTypeLength = asReadTypeLength; +exports.asValueIfNotPresent = asValueIfNotPresent; +exports.asChipUnderlyingType = asChipUnderlyingType; +exports.isFirstElement = isFirstElement; exports.user_cluster_has_enabled_manufacturer_command = user_cluster_has_enabled_manufacturer_command; -exports.chip_endpoint_generated_functions = chip_endpoint_generated_functions -exports.chip_endpoint_cluster_list = chip_endpoint_cluster_list -exports.isSigned = ChipTypesHelper.isSigned; -exports.isStrEndsWith = isStrEndsWith; +exports.chip_endpoint_generated_functions = chip_endpoint_generated_functions +exports.chip_endpoint_cluster_list = chip_endpoint_cluster_list +exports.isSigned = ChipTypesHelper.isSigned; +exports.isStrEndsWith = isStrEndsWith; From 06d8f5418431baeb971ab2d36ce102c05ee85dbb Mon Sep 17 00:00:00 2001 From: Markus Becker Date: Thu, 8 Apr 2021 13:57:35 +0200 Subject: [PATCH 06/13] Add weak implementation of Occupancy Sensor Type --- .../occupancy-sensor-server/occupancy-sensor-server.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.cpp b/src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.cpp index 9090f85951c86e..73d2e73fdabcc9 100644 --- a/src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.cpp +++ b/src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.cpp @@ -193,3 +193,7 @@ static void checkForReportingConfig(void) } void emberAfPluginOccupancyClusterServerPostInitCallback(EndpointId endpoint) {} + +HalOccupancySensorType __attribute__((weak)) halOccupancyGetSensorType(chip::EndpointId endpoint) { + return HAL_OCCUPANCY_SENSOR_TYPE_PIR; +} From 931686fa3e7c57e1331999ca29a35cfc75ab9814 Mon Sep 17 00:00:00 2001 From: Markus Becker Date: Thu, 8 Apr 2021 14:45:53 +0200 Subject: [PATCH 07/13] Add occupancy-sensor-server to ESP32 build --- examples/all-clusters-app/esp32/main/component.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/all-clusters-app/esp32/main/component.mk b/examples/all-clusters-app/esp32/main/component.mk index e8c22cb7db5fba..bacfb33784819b 100644 --- a/examples/all-clusters-app/esp32/main/component.mk +++ b/examples/all-clusters-app/esp32/main/component.mk @@ -56,6 +56,7 @@ COMPONENT_SRCDIRS := ../third_party/connectedhomeip/src/app/clusters/bindings \ ../third_party/connectedhomeip/src/app/reporting \ ../third_party/connectedhomeip/src/app/clusters/door-lock-server \ + ../third_party/connectedhomeip/src/app/clusters/occupancy-sensor-server \ ../third_party/connectedhomeip/src/app/clusters/ias-zone-server \ # ../third_party/connectedhomeip/src/app/clusters/ias-zone-client \ From a8b7f4dbc5ab38d76ac54c4171c3985f0f9bace7 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Sun, 25 Apr 2021 19:52:19 +0000 Subject: [PATCH 08/13] Restyled by whitespace --- src/app/clusters/occupancy-sensor-server/occupancy-hal.h | 2 +- .../clusters/occupancy-sensor-server/occupancy-sensor-server.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/app/clusters/occupancy-sensor-server/occupancy-hal.h b/src/app/clusters/occupancy-sensor-server/occupancy-hal.h index 2e6ec7b47a8b37..47087bc8f9e240 100644 --- a/src/app/clusters/occupancy-sensor-server/occupancy-hal.h +++ b/src/app/clusters/occupancy-sensor-server/occupancy-hal.h @@ -31,7 +31,7 @@ typedef enum { typedef enum { HAL_OCCUPANCY_STATE_UNOCCUPIED = 0x00, HAL_OCCUPANCY_STATE_OCCUPIED = 0x01, - + } HalOccupancyState; /** @brief Initializes the occupancy sensor, along with any hardware diff --git a/src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.h b/src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.h index ea81bb3c0736e2..3ed762cbfb4013 100644 --- a/src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.h +++ b/src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.h @@ -29,4 +29,3 @@ * @param endpoint Endpoint that is being initialized Ver.: always */ void emberAfPluginOccupancyClusterServerPostInitCallback(chip::EndpointId endpoint); - From c778a516cc9cd8e590ed434765ed98cd44bb8a70 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Sun, 25 Apr 2021 19:52:20 +0000 Subject: [PATCH 09/13] Restyled by clang-format --- .../occupancy-sensor-server/occupancy-hal.h | 18 +- .../occupancy-sensor-server.cpp | 141 ++++++----- src/app/zap-templates/templates/app/helper.js | 237 ++++++++++-------- 3 files changed, 211 insertions(+), 185 deletions(-) diff --git a/src/app/clusters/occupancy-sensor-server/occupancy-hal.h b/src/app/clusters/occupancy-sensor-server/occupancy-hal.h index 47087bc8f9e240..60df0ebcba4bed 100644 --- a/src/app/clusters/occupancy-sensor-server/occupancy-hal.h +++ b/src/app/clusters/occupancy-sensor-server/occupancy-hal.h @@ -21,16 +21,18 @@ #include // enum used to track the type of occupancy sensor being implemented -typedef enum { - HAL_OCCUPANCY_SENSOR_TYPE_PIR = 0x00, - HAL_OCCUPANCY_SENSOR_TYPE_ULTRASONIC = 0x01, - HAL_OCCUPANCY_SENSOR_TYPE_PIR_AND_ULTRASONIC = 0x02, - HAL_OCCUPANCY_SENSOR_TYPE_PHYSICAL = 0x03, +typedef enum +{ + HAL_OCCUPANCY_SENSOR_TYPE_PIR = 0x00, + HAL_OCCUPANCY_SENSOR_TYPE_ULTRASONIC = 0x01, + HAL_OCCUPANCY_SENSOR_TYPE_PIR_AND_ULTRASONIC = 0x02, + HAL_OCCUPANCY_SENSOR_TYPE_PHYSICAL = 0x03, } HalOccupancySensorType; -typedef enum { - HAL_OCCUPANCY_STATE_UNOCCUPIED = 0x00, - HAL_OCCUPANCY_STATE_OCCUPIED = 0x01, +typedef enum +{ + HAL_OCCUPANCY_STATE_UNOCCUPIED = 0x00, + HAL_OCCUPANCY_STATE_OCCUPIED = 0x01, } HalOccupancyState; diff --git a/src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.cpp b/src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.cpp index 73d2e73fdabcc9..c9353911715984 100644 --- a/src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.cpp +++ b/src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.cpp @@ -58,7 +58,6 @@ #include #endif - using namespace chip; //------------------------------------------------------------------------------ @@ -91,40 +90,40 @@ static EmberAfPluginReportingEntry defaultConfiguration = { //****************************************************************************** void emberAfOccupancySensingClusterServerInitCallback(chip::EndpointId endpoint) { - HalOccupancySensorType deviceType; + HalOccupancySensorType deviceType; - checkForReportingConfig(); - deviceType = halOccupancyGetSensorType(endpoint); + checkForReportingConfig(); + deviceType = halOccupancyGetSensorType(endpoint); - emberAfWriteAttribute(endpoint, ZCL_OCCUPANCY_SENSING_CLUSTER_ID, ZCL_OCCUPANCY_SENSOR_TYPE_ATTRIBUTE_ID, CLUSTER_MASK_SERVER, - (uint8_t *) &deviceType, ZCL_ENUM8_ATTRIBUTE_TYPE); + emberAfWriteAttribute(endpoint, ZCL_OCCUPANCY_SENSING_CLUSTER_ID, ZCL_OCCUPANCY_SENSOR_TYPE_ATTRIBUTE_ID, CLUSTER_MASK_SERVER, + (uint8_t *) &deviceType, ZCL_ENUM8_ATTRIBUTE_TYPE); - uint8_t deviceTypeBitmap = 0; - switch (deviceType) { + uint8_t deviceTypeBitmap = 0; + switch (deviceType) + { case HAL_OCCUPANCY_SENSOR_TYPE_PIR: - deviceTypeBitmap = EMBER_AF_OCCUPANCY_SENSOR_TYPE_BITMAP_PIR; - break; + deviceTypeBitmap = EMBER_AF_OCCUPANCY_SENSOR_TYPE_BITMAP_PIR; + break; case HAL_OCCUPANCY_SENSOR_TYPE_ULTRASONIC: - deviceTypeBitmap = EMBER_AF_OCCUPANCY_SENSOR_TYPE_BITMAP_ULTRASONIC; - break; + deviceTypeBitmap = EMBER_AF_OCCUPANCY_SENSOR_TYPE_BITMAP_ULTRASONIC; + break; case HAL_OCCUPANCY_SENSOR_TYPE_PIR_AND_ULTRASONIC: - deviceTypeBitmap = (EMBER_AF_OCCUPANCY_SENSOR_TYPE_BITMAP_PIR - | EMBER_AF_OCCUPANCY_SENSOR_TYPE_BITMAP_ULTRASONIC); - break; + deviceTypeBitmap = (EMBER_AF_OCCUPANCY_SENSOR_TYPE_BITMAP_PIR | EMBER_AF_OCCUPANCY_SENSOR_TYPE_BITMAP_ULTRASONIC); + break; case HAL_OCCUPANCY_SENSOR_TYPE_PHYSICAL: - deviceTypeBitmap = EMBER_AF_OCCUPANCY_SENSOR_TYPE_BITMAP_PHYSICAL_CONTACT; - break; + deviceTypeBitmap = EMBER_AF_OCCUPANCY_SENSOR_TYPE_BITMAP_PHYSICAL_CONTACT; + break; default: - break; - } - emberAfWriteAttribute(endpoint, ZCL_OCCUPANCY_SENSING_CLUSTER_ID, ZCL_OCCUPANCY_SENSOR_TYPE_BITMAP_ATTRIBUTE_ID, CLUSTER_MASK_SERVER, - (uint8_t *) &deviceTypeBitmap, ZCL_BITMAP8_ATTRIBUTE_TYPE); + break; + } + emberAfWriteAttribute(endpoint, ZCL_OCCUPANCY_SENSING_CLUSTER_ID, ZCL_OCCUPANCY_SENSOR_TYPE_BITMAP_ATTRIBUTE_ID, + CLUSTER_MASK_SERVER, (uint8_t *) &deviceTypeBitmap, ZCL_BITMAP8_ATTRIBUTE_TYPE); - emberAfPluginOccupancyClusterServerPostInitCallback(endpoint); + emberAfPluginOccupancyClusterServerPostInitCallback(endpoint); } //****************************************************************************** @@ -132,26 +131,29 @@ void emberAfOccupancySensingClusterServerInitCallback(chip::EndpointId endpoint) //****************************************************************************** void halOccupancyStateChangedCallback(EndpointId endpoint, HalOccupancyState occupancyState) { - if (occupancyState == HAL_OCCUPANCY_STATE_OCCUPIED) { - emberAfOccupancySensingClusterPrintln("Occupancy detected"); - } else { - emberAfOccupancySensingClusterPrintln("Occupancy no longer detected"); - } - - emberAfWriteAttribute(endpoint, ZCL_OCCUPANCY_SENSING_CLUSTER_ID, ZCL_OCCUPANCY_ATTRIBUTE_ID, CLUSTER_MASK_SERVER, - (uint8_t *) &occupancyState, ZCL_BITMAP8_ATTRIBUTE_TYPE); - // emberAfPluginOccupancySensorServerOccupancyStateChangedCallback( - // endpoint, occupancyState); + if (occupancyState == HAL_OCCUPANCY_STATE_OCCUPIED) + { + emberAfOccupancySensingClusterPrintln("Occupancy detected"); + } + else + { + emberAfOccupancySensingClusterPrintln("Occupancy no longer detected"); + } + + emberAfWriteAttribute(endpoint, ZCL_OCCUPANCY_SENSING_CLUSTER_ID, ZCL_OCCUPANCY_ATTRIBUTE_ID, CLUSTER_MASK_SERVER, + (uint8_t *) &occupancyState, ZCL_BITMAP8_ATTRIBUTE_TYPE); + // emberAfPluginOccupancySensorServerOccupancyStateChangedCallback( + // endpoint, occupancyState); } -void emberAfPluginOccupancySensorServerStackStatusCallback( - EndpointId endpoint, EmberStatus status) +void emberAfPluginOccupancySensorServerStackStatusCallback(EndpointId endpoint, EmberStatus status) { - // On network connect, verify that a reporting entry is set up for the - // occupancy sensor - if (status == EMBER_NETWORK_UP) { - checkForReportingConfig(); - } + // On network connect, verify that a reporting entry is set up for the + // occupancy sensor + if (status == EMBER_NETWORK_UP) + { + checkForReportingConfig(); + } } //------------------------------------------------------------------------------ @@ -160,40 +162,41 @@ void emberAfPluginOccupancySensorServerStackStatusCallback( static void checkForReportingConfig(void) { #ifdef EMBER_AF_PLUGIN_REPORTING - // uint16_t i; - // EmberAfPluginReportingEntry entry; - // uint8_t endpoint; - // bool existingEntry = false; - - // // On initialization, cycle through the reporting table to determine if a - // // reporting table entry has been created for the occupancy state attribute - // for (i = 0; i < emAfPluginReportingNumEntries(); i++) { - // emAfPluginReportingGetEntry(i, &entry); - // if ((entry.clusterId == ZCL_OCCUPANCY_SENSING_CLUSTER_ID) - // && (entry.attributeId == ZCL_OCCUPANCY_ATTRIBUTE_ID) - // && (entry.direction == EMBER_ZCL_REPORTING_DIRECTION_REPORTED) - // && (entry.manufacturerCode == EMBER_AF_NULL_MANUFACTURER_CODE)) { - // existingEntry = true; - // } - // } - - // // If no entry is found for the occupancy sensor, a default reporting - // // configuration should be created using the plugin defined options. This - // // needs to be done for all endpoints that support an occupancy sensor server. - // if (!existingEntry) { - // for (i = 0; i < emberAfEndpointCount(); i++) { - // endpoint = emberAfEndpointFromIndex(i); - // defaultConfiguration.endpoint = endpoint; - // if (emberAfContainsServer(endpoint, ZCL_OCCUPANCY_SENSING_CLUSTER_ID)) { - // emAfPluginReportingAppendEntry(&defaultConfiguration); - // } - // } - // } + // uint16_t i; + // EmberAfPluginReportingEntry entry; + // uint8_t endpoint; + // bool existingEntry = false; + + // // On initialization, cycle through the reporting table to determine if a + // // reporting table entry has been created for the occupancy state attribute + // for (i = 0; i < emAfPluginReportingNumEntries(); i++) { + // emAfPluginReportingGetEntry(i, &entry); + // if ((entry.clusterId == ZCL_OCCUPANCY_SENSING_CLUSTER_ID) + // && (entry.attributeId == ZCL_OCCUPANCY_ATTRIBUTE_ID) + // && (entry.direction == EMBER_ZCL_REPORTING_DIRECTION_REPORTED) + // && (entry.manufacturerCode == EMBER_AF_NULL_MANUFACTURER_CODE)) { + // existingEntry = true; + // } + // } + + // // If no entry is found for the occupancy sensor, a default reporting + // // configuration should be created using the plugin defined options. This + // // needs to be done for all endpoints that support an occupancy sensor server. + // if (!existingEntry) { + // for (i = 0; i < emberAfEndpointCount(); i++) { + // endpoint = emberAfEndpointFromIndex(i); + // defaultConfiguration.endpoint = endpoint; + // if (emberAfContainsServer(endpoint, ZCL_OCCUPANCY_SENSING_CLUSTER_ID)) { + // emAfPluginReportingAppendEntry(&defaultConfiguration); + // } + // } + // } #endif } void emberAfPluginOccupancyClusterServerPostInitCallback(EndpointId endpoint) {} -HalOccupancySensorType __attribute__((weak)) halOccupancyGetSensorType(chip::EndpointId endpoint) { +HalOccupancySensorType __attribute__((weak)) halOccupancyGetSensorType(chip::EndpointId endpoint) +{ return HAL_OCCUPANCY_SENSOR_TYPE_PIR; } diff --git a/src/app/zap-templates/templates/app/helper.js b/src/app/zap-templates/templates/app/helper.js index c253620c82c854..2cc69780681bf6 100644 --- a/src/app/zap-templates/templates/app/helper.js +++ b/src/app/zap-templates/templates/app/helper.js @@ -16,14 +16,14 @@ */ // Import helpers from zap core -const zapPath = '../../../../../third_party/zap/repo/src-electron/'; -const queryImpexp = require(zapPath + 'db/query-impexp.js') +const zapPath = '../../../../../third_party/zap/repo/src-electron/'; +const queryImpexp = require(zapPath + 'db/query-impexp.js') const templateUtil = require(zapPath + 'generator/template-util.js') -const zclHelper = require(zapPath + 'generator/helper-zcl.js') -const zclQuery = require(zapPath + 'db/query-zcl.js') -const cHelper = require(zapPath + 'generator/helper-c.js') +const zclHelper = require(zapPath + 'generator/helper-zcl.js') +const zclQuery = require(zapPath + 'db/query-zcl.js') +const cHelper = require(zapPath + 'generator/helper-c.js') -const StringHelper = require('../../common/StringHelper.js'); +const StringHelper = require('../../common/StringHelper.js'); const ChipTypesHelper = require('../../common/ChipTypesHelper.js'); /** @@ -35,35 +35,38 @@ const ChipTypesHelper = require('../../common/ChipTypesHelper.js'); * @param {*} options * @returns True if cluster has enabled commands otherwise false */ -function user_cluster_has_enabled_manufacturer_command(name, side, options) { +function user_cluster_has_enabled_manufacturer_command(name, side, options) +{ return queryImpexp.exportEndPointTypeIds(this.global.db, this.global.sessionId) - .then((endpointTypes) => zclQuery.exportClustersAndEndpointDetailsFromEndpointTypes(this.global.db, endpointTypes)) - .then((endpointsAndClusters) => zclQuery.exportCommandDetailsFromAllEndpointTypesAndClusters( - this.global.db, endpointsAndClusters)) - .then((endpointCommands) => { - return !!endpointCommands.find(cmd => cmd.mfgCode && zclHelper.isStrEqual(name, cmd.clusterName) - && zclHelper.isCommandAvailable(side, cmd.incoming, cmd.outgoing, cmd.commandSource, cmd.name)); - }) + .then((endpointTypes) => zclQuery.exportClustersAndEndpointDetailsFromEndpointTypes(this.global.db, endpointTypes)) + .then((endpointsAndClusters) => zclQuery.exportCommandDetailsFromAllEndpointTypesAndClusters( + this.global.db, endpointsAndClusters)) + .then((endpointCommands) => { + return !!endpointCommands.find(cmd => cmd.mfgCode && zclHelper.isStrEqual(name, cmd.clusterName) + && zclHelper.isCommandAvailable(side, cmd.incoming, cmd.outgoing, cmd.commandSource, cmd.name)); + }) } -function asValueIfNotPresent(type, isArray) { +function asValueIfNotPresent(type, isArray) +{ if (StringHelper.isString(type) || isArray) { return 'NULL'; } - function fn(pkgId) { - const options = { 'hash': {} }; + function fn(pkgId) + { + const options = { 'hash' : {} }; return zclHelper.asUnderlyingZclType.call(this, type, options).then(zclType => { switch (zclType) { - case 'uint8_t': - return 'UINT8_MAX'; - case 'uint16_t': - return 'UINT16_MAX'; - case 'uint32_t': - return 'UINT32_MAX'; - default: - error = 'Unhandled underlying type ' + zclType + ' for original type ' + type; - throw error; + case 'uint8_t': + return 'UINT8_MAX'; + case 'uint16_t': + return 'UINT16_MAX'; + case 'uint32_t': + return 'UINT32_MAX'; + default: + error = 'Unhandled underlying type ' + zclType + ' for original type ' + type; + throw error; } }) } @@ -74,7 +77,8 @@ function asValueIfNotPresent(type, isArray) { // TODO Expose the readTypeLength as an additional member field of {{asUnderlyingZclType}} instead // of having to call this method separately. -function asReadTypeLength(type) { +function asReadTypeLength(type) +{ const db = this.global.db; if (StringHelper.isShortString(type)) { @@ -85,7 +89,8 @@ function asReadTypeLength(type) { return '2u'; } - function fn(pkgId) { + function fn(pkgId) + { const defaultResolver = zclQuery.selectAtomicType(db, pkgId, type); const enumResolver = zclHelper.isEnum(db, type, pkgId).then(result => { @@ -100,7 +105,7 @@ function asReadTypeLength(type) { }); }); - const typeResolver = Promise.all([defaultResolver, enumResolver, bitmapResolver]); + const typeResolver = Promise.all([ defaultResolver, enumResolver, bitmapResolver ]); return typeResolver.then(types => (types.find(type => type)).size); } @@ -110,7 +115,8 @@ function asReadTypeLength(type) { // TODO Expose the readType as an additional member field of {{asUnderlyingZclType}} instead // of having to call this method separately. -function asReadType(type) { +function asReadType(type) +{ if (StringHelper.isShortString(type)) { return 'String'; } @@ -119,29 +125,30 @@ function asReadType(type) { return 'LongString'; } - function fn(pkgId) { - const options = { 'hash': {} }; + function fn(pkgId) + { + const options = { 'hash' : {} }; return zclHelper.asUnderlyingZclType.call(this, type, options).then(zclType => { const basicType = ChipTypesHelper.asBasicType(zclType); switch (basicType) { - case 'int8_t': - case 'uint8_t': - return 'Int8u'; - case 'int16_t': - case 'uint16_t': - return 'Int16u'; - case 'int24_t': - case 'uint24_t': - return 'Int24u'; - case 'int32_t': - case 'uint32_t': - return 'Int32u'; - case 'int64_t': - case 'uint64_t': - return 'Int64u'; - default: - error = 'Unhandled underlying type ' + zclType + ' for original type ' + type; - throw error; + case 'int8_t': + case 'uint8_t': + return 'Int8u'; + case 'int16_t': + case 'uint16_t': + return 'Int16u'; + case 'int24_t': + case 'uint24_t': + return 'Int24u'; + case 'int32_t': + case 'uint32_t': + return 'Int32u'; + case 'int64_t': + case 'uint64_t': + return 'Int64u'; + default: + error = 'Unhandled underlying type ' + zclType + ' for original type ' + type; + throw error; } }) } @@ -159,7 +166,8 @@ function asReadType(type) { * @param {*} label : The xml label of the type. * @param {*} type : The xml type to be converted */ -function asChipUnderlyingType(label, type) { +function asChipUnderlyingType(label, type) +{ if (zclHelper.isStrEqual(label, "endpoint")) { return 'chip::EndpointId'; @@ -176,7 +184,7 @@ function asChipUnderlyingType(label, type) { } else if (type == 'OCTET_STRING') { return 'chip::ByteSpan'; } else { - const options = { 'hash': {} }; + const options = { 'hash' : {} }; return zclHelper.asUnderlyingZclType.call(this, type, options); } } @@ -187,16 +195,18 @@ function asChipUnderlyingType(label, type) { // These helpers only works within the endpoint_config iterator // List of all cluster with generated functions -var endpointClusterWithInit = ['Basic', 'Identify', 'Groups', 'Scenes', 'Occupancy Sensing', 'On/off', 'Level Control', 'Color Control', 'IAS Zone']; -var endpointClusterWithAttributeChanged = ['Identify', 'Door Lock']; -var endpointClusterWithPreAttribute = ['IAS Zone']; -var endpointClusterWithMessageSent = ['IAS Zone']; +var endpointClusterWithInit = + [ 'Basic', 'Identify', 'Groups', 'Scenes', 'Occupancy Sensing', 'On/off', 'Level Control', 'Color Control', 'IAS Zone' ]; +var endpointClusterWithAttributeChanged = [ 'Identify', 'Door Lock' ]; +var endpointClusterWithPreAttribute = [ 'IAS Zone' ]; +var endpointClusterWithMessageSent = [ 'IAS Zone' ]; /** * extract the cluster name from the enpoint cluster comment * @param {*} comments */ -function extract_cluster_name(comments) { +function extract_cluster_name(comments) +{ let secondPart = comments.split(": ").pop(); return secondPart.split(" (")[0]; } @@ -204,11 +214,12 @@ function extract_cluster_name(comments) { /** * Populate the GENERATED_FUNCTIONS field */ -function chip_endpoint_generated_functions() { +function chip_endpoint_generated_functions() +{ let alreadySetCluster = []; - let ret = '\\\n'; + let ret = '\\\n'; this.clusterList.forEach((c) => { - let clusterName = extract_cluster_name(c.comment); + let clusterName = extract_cluster_name(c.comment); let functionList = ''; if (alreadySetCluster.includes(clusterName)) { // Only one array of Generated functions per cluster across all endpoints @@ -216,30 +227,34 @@ function chip_endpoint_generated_functions() { } if (c.comment.includes('server')) { let hasFunctionArray = false - if (endpointClusterWithInit.includes(clusterName)) { + if (endpointClusterWithInit.includes(clusterName)) + { hasFunctionArray = true - functionList = functionList.concat( - ` (EmberAfGenericClusterFunction) emberAf${cHelper.asCamelCased(clusterName, false)}ClusterServerInitCallback,\\\n`) + functionList = functionList.concat( + ` (EmberAfGenericClusterFunction) emberAf${cHelper.asCamelCased(clusterName, false)}ClusterServerInitCallback,\\\n`) } if (endpointClusterWithAttributeChanged.includes(clusterName)) { - functionList = functionList.concat(` (EmberAfGenericClusterFunction) emberAf${cHelper.asCamelCased(clusterName, false)}ClusterServerAttributeChangedCallback,\\\n`) + functionList = functionList.concat(` (EmberAfGenericClusterFunction) emberAf${ + cHelper.asCamelCased(clusterName, false)}ClusterServerAttributeChangedCallback,\\\n`) hasFunctionArray = true } if (endpointClusterWithMessageSent.includes(clusterName)) { - functionList = functionList.concat(` (EmberAfGenericClusterFunction) emberAf${cHelper.asCamelCased(clusterName, false)}ClusterServerMessageSentCallback,\\\n`) + functionList = functionList.concat(` (EmberAfGenericClusterFunction) emberAf${ + cHelper.asCamelCased(clusterName, false)}ClusterServerMessageSentCallback,\\\n`) hasFunctionArray = true } if (endpointClusterWithPreAttribute.includes(clusterName)) { - functionList = functionList.concat(` (EmberAfGenericClusterFunction) emberAf${cHelper.asCamelCased(clusterName, false)}ClusterServerPreAttributeChangedCallback,\\\n`) + functionList = functionList.concat(` (EmberAfGenericClusterFunction) emberAf${ + cHelper.asCamelCased(clusterName, false)}ClusterServerPreAttributeChangedCallback,\\\n`) hasFunctionArray = true } if (hasFunctionArray) { ret = ret.concat( - `const EmberAfGenericClusterFunction chipFuncArray${cHelper.asCamelCased(clusterName, false)}Server[] = {\\\n`) + `const EmberAfGenericClusterFunction chipFuncArray${cHelper.asCamelCased(clusterName, false)}Server[] = {\\\n`) ret = ret.concat(functionList) ret = ret.concat(`};\\\n`) alreadySetCluster.push(clusterName) @@ -254,12 +269,13 @@ function chip_endpoint_generated_functions() { * To be used as a replacement of endpoint_cluster_list since this one * includes the GENERATED_FUNCTIONS array */ -function chip_endpoint_cluster_list() { +function chip_endpoint_cluster_list() +{ let ret = '{ \\\n'; this.clusterList.forEach((c) => { - let mask = ''; + let mask = ''; let functionArray = c.functions; - let clusterName = extract_cluster_name(c.comment); + let clusterName = extract_cluster_name(c.comment); if (c.comment.includes('server')) { let hasFunctionArray = false; @@ -293,45 +309,48 @@ function chip_endpoint_cluster_list() { } else { mask = c.mask.map((m) => `ZAP_CLUSTER_MASK(${m.toUpperCase()})`).join(' | ') } - ret = ret.concat(` { ${c.clusterId}, ZAP_ATTRIBUTE_INDEX(${c.attributeIndex}), ${c.attributeCount}, ${c.attributeSize}, ${mask}, ${functionArray} }, /* ${c.comment} */ \\\n`) + ret = ret.concat(` { ${c.clusterId}, ZAP_ATTRIBUTE_INDEX(${c.attributeIndex}), ${c.attributeCount}, ${c.attributeSize}, ${ + mask}, ${functionArray} }, /* ${c.comment} */ \\\n`) }) return ret.concat('}\n'); } // End of Endpoint-config specific helpers -function asPrintFormat(type) { +function asPrintFormat(type) +{ if (StringHelper.isString(type)) { return '%s'; } - function fn(pkgId) { - const options = { 'hash': {} }; + function fn(pkgId) + { + const options = { 'hash' : {} }; return zclHelper.asUnderlyingZclType.call(this, type, options).then(zclType => { const basicType = ChipTypesHelper.asBasicType(zclType); switch (basicType) { - case 'int8_t': - return '%" PRId8 "'; - case 'uint8_t': - return '%" PRIu8 "'; - case 'int16_t': - return '%" PRId16 "'; - case 'uint16_t': - return '%" PRIu16 "'; - case 'int24_t': - return '%" PRId32 "'; - case 'uint24_t': - return '%" PRIu32 "'; - case 'int32_t': - return '%" PRId32 "'; - case 'uint32_t': - return '%" PRIu32 "'; - case 'int64_t': - return '%" PRId64 "'; - case 'uint64_t': - return '%" PRIu64 "'; - default: - return '%p'; + case 'int8_t': + return '%" PRId8 "'; + case 'uint8_t': + return '%" PRIu8 "'; + case 'int16_t': + return '%" PRId16 "'; + case 'uint16_t': + return '%" PRIu16 "'; + case 'int24_t': + return '%" PRId32 "'; + case 'uint24_t': + return '%" PRIu32 "'; + case 'int32_t': + return '%" PRId32 "'; + case 'uint32_t': + return '%" PRIu32 "'; + case 'int64_t': + return '%" PRId64 "'; + case 'uint64_t': + return '%" PRIu64 "'; + default: + return '%p'; } }) } @@ -340,25 +359,27 @@ function asPrintFormat(type) { return templateUtil.templatePromise(this.global, promise) } -function isFirstElement(index) { +function isFirstElement(index) +{ return index == 0; } -function isStrEndsWith(str, substr) { +function isStrEndsWith(str, substr) +{ return str.endsWith(substr); } // // Module exports // -exports.asPrintFormat = asPrintFormat; -exports.asReadType = asReadType; -exports.asReadTypeLength = asReadTypeLength; -exports.asValueIfNotPresent = asValueIfNotPresent; -exports.asChipUnderlyingType = asChipUnderlyingType; -exports.isFirstElement = isFirstElement; +exports.asPrintFormat = asPrintFormat; +exports.asReadType = asReadType; +exports.asReadTypeLength = asReadTypeLength; +exports.asValueIfNotPresent = asValueIfNotPresent; +exports.asChipUnderlyingType = asChipUnderlyingType; +exports.isFirstElement = isFirstElement; exports.user_cluster_has_enabled_manufacturer_command = user_cluster_has_enabled_manufacturer_command; -exports.chip_endpoint_generated_functions = chip_endpoint_generated_functions -exports.chip_endpoint_cluster_list = chip_endpoint_cluster_list -exports.isSigned = ChipTypesHelper.isSigned; -exports.isStrEndsWith = isStrEndsWith; +exports.chip_endpoint_generated_functions = chip_endpoint_generated_functions +exports.chip_endpoint_cluster_list = chip_endpoint_cluster_list +exports.isSigned = ChipTypesHelper.isSigned; +exports.isStrEndsWith = isStrEndsWith; From e25e508a649a5e572ab624b6af2322e0ee92c454 Mon Sep 17 00:00:00 2001 From: Markus Becker Date: Thu, 29 Apr 2021 15:49:54 +0200 Subject: [PATCH 10/13] Apply review suggestions from Lukas Duda. --- src/app/clusters/occupancy-sensor-server/occupancy-hal.h | 2 -- .../occupancy-sensor-server/occupancy-sensor-server.cpp | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/app/clusters/occupancy-sensor-server/occupancy-hal.h b/src/app/clusters/occupancy-sensor-server/occupancy-hal.h index 60df0ebcba4bed..1943a790e75af1 100644 --- a/src/app/clusters/occupancy-sensor-server/occupancy-hal.h +++ b/src/app/clusters/occupancy-sensor-server/occupancy-hal.h @@ -17,7 +17,6 @@ #pragma once -//#include #include // enum used to track the type of occupancy sensor being implemented @@ -33,7 +32,6 @@ typedef enum { HAL_OCCUPANCY_STATE_UNOCCUPIED = 0x00, HAL_OCCUPANCY_STATE_OCCUPIED = 0x01, - } HalOccupancyState; /** @brief Initializes the occupancy sensor, along with any hardware diff --git a/src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.cpp b/src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.cpp index c9353911715984..03a9021511b331 100644 --- a/src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.cpp +++ b/src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.cpp @@ -121,7 +121,7 @@ void emberAfOccupancySensingClusterServerInitCallback(chip::EndpointId endpoint) break; } emberAfWriteAttribute(endpoint, ZCL_OCCUPANCY_SENSING_CLUSTER_ID, ZCL_OCCUPANCY_SENSOR_TYPE_BITMAP_ATTRIBUTE_ID, - CLUSTER_MASK_SERVER, (uint8_t *) &deviceTypeBitmap, ZCL_BITMAP8_ATTRIBUTE_TYPE); + CLUSTER_MASK_SERVER, &deviceTypeBitmap, ZCL_BITMAP8_ATTRIBUTE_TYPE); emberAfPluginOccupancyClusterServerPostInitCallback(endpoint); } From 0e48c21b779d857cb9d9d5eaa4f1b4d92541ae76 Mon Sep 17 00:00:00 2001 From: Markus Becker Date: Thu, 29 Apr 2021 16:00:38 +0200 Subject: [PATCH 11/13] Remove commented code. --- .../occupancy-sensor-server.cpp | 76 ------------------- 1 file changed, 76 deletions(-) diff --git a/src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.cpp b/src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.cpp index 03a9021511b331..a5f9d2c5bacd5d 100644 --- a/src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.cpp +++ b/src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.cpp @@ -60,31 +60,6 @@ using namespace chip; -//------------------------------------------------------------------------------ -// Plugin private function prototypes -static void checkForReportingConfig(void); - -//------------------------------------------------------------------------------ -// Global variables -/* -// The default configuration to be used if no reporting has been set up -static EmberAfPluginReportingEntry defaultConfiguration = { - EMBER_ZCL_REPORTING_DIRECTION_REPORTED, //direction - 0, //endpoint, which will be set on a per-use basis - ZCL_OCCUPANCY_SENSING_CLUSTER_ID, //clusterId - ZCL_OCCUPANCY_ATTRIBUTE_ID, //attributeId - CLUSTER_MASK_SERVER, //mask - EMBER_AF_NULL_MANUFACTURER_CODE, //manufacturerCode - .data.reported = { - 1, //minInterval - EMBER_AF_PLUGIN_OCCUPANCY_SENSOR_SERVER_DEFAULT_OCCUPANCY_MAX_REPORT_PERIOD_S, //maxInterval - 1 //reportableChange - } -}; -*/ -//------------------------------------------------------------------------------ -// Plugin consumed callback implementations - //****************************************************************************** // Plugin init function //****************************************************************************** @@ -92,7 +67,6 @@ void emberAfOccupancySensingClusterServerInitCallback(chip::EndpointId endpoint) { HalOccupancySensorType deviceType; - checkForReportingConfig(); deviceType = halOccupancyGetSensorType(endpoint); emberAfWriteAttribute(endpoint, ZCL_OCCUPANCY_SENSING_CLUSTER_ID, ZCL_OCCUPANCY_SENSOR_TYPE_ATTRIBUTE_ID, CLUSTER_MASK_SERVER, @@ -142,56 +116,6 @@ void halOccupancyStateChangedCallback(EndpointId endpoint, HalOccupancyState occ emberAfWriteAttribute(endpoint, ZCL_OCCUPANCY_SENSING_CLUSTER_ID, ZCL_OCCUPANCY_ATTRIBUTE_ID, CLUSTER_MASK_SERVER, (uint8_t *) &occupancyState, ZCL_BITMAP8_ATTRIBUTE_TYPE); - // emberAfPluginOccupancySensorServerOccupancyStateChangedCallback( - // endpoint, occupancyState); -} - -void emberAfPluginOccupancySensorServerStackStatusCallback(EndpointId endpoint, EmberStatus status) -{ - // On network connect, verify that a reporting entry is set up for the - // occupancy sensor - if (status == EMBER_NETWORK_UP) - { - checkForReportingConfig(); - } -} - -//------------------------------------------------------------------------------ -// Plugin private functions - -static void checkForReportingConfig(void) -{ -#ifdef EMBER_AF_PLUGIN_REPORTING - // uint16_t i; - // EmberAfPluginReportingEntry entry; - // uint8_t endpoint; - // bool existingEntry = false; - - // // On initialization, cycle through the reporting table to determine if a - // // reporting table entry has been created for the occupancy state attribute - // for (i = 0; i < emAfPluginReportingNumEntries(); i++) { - // emAfPluginReportingGetEntry(i, &entry); - // if ((entry.clusterId == ZCL_OCCUPANCY_SENSING_CLUSTER_ID) - // && (entry.attributeId == ZCL_OCCUPANCY_ATTRIBUTE_ID) - // && (entry.direction == EMBER_ZCL_REPORTING_DIRECTION_REPORTED) - // && (entry.manufacturerCode == EMBER_AF_NULL_MANUFACTURER_CODE)) { - // existingEntry = true; - // } - // } - - // // If no entry is found for the occupancy sensor, a default reporting - // // configuration should be created using the plugin defined options. This - // // needs to be done for all endpoints that support an occupancy sensor server. - // if (!existingEntry) { - // for (i = 0; i < emberAfEndpointCount(); i++) { - // endpoint = emberAfEndpointFromIndex(i); - // defaultConfiguration.endpoint = endpoint; - // if (emberAfContainsServer(endpoint, ZCL_OCCUPANCY_SENSING_CLUSTER_ID)) { - // emAfPluginReportingAppendEntry(&defaultConfiguration); - // } - // } - // } -#endif } void emberAfPluginOccupancyClusterServerPostInitCallback(EndpointId endpoint) {} From 702c12f03fd5a0e62c14a8bb00933b4dbe230fbd Mon Sep 17 00:00:00 2001 From: Markus Becker Date: Tue, 4 May 2021 11:45:47 +0200 Subject: [PATCH 12/13] Enable OCCUPANCY_SENSING_CLUSTER/occupancy-sensor-server in zap_cluster_list.py --- src/app/zap_cluster_list.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/zap_cluster_list.py b/src/app/zap_cluster_list.py index f54cbaf6424aa3..57fe013cc90123 100755 --- a/src/app/zap_cluster_list.py +++ b/src/app/zap_cluster_list.py @@ -36,7 +36,7 @@ 'MEDIA_INPUT_CLUSTER': ['media-input-server'], 'MEDIA_PLAYBACK_CLUSTER': ['media-playback-server'], 'NETWORK_COMMISSIONING_CLUSTER': ['network-commissioning'], - 'OCCUPANCY_SENSING_CLUSTER': [], + 'OCCUPANCY_SENSING_CLUSTER': ['occupancy-sensor-server'], 'ON_OFF_CLUSTER': ['on-off-server'], 'OPERATIONAL_CREDENTIALS_CLUSTER': ['operational-credentials-server'], 'OTA_BOOTLOAD_CLUSTER': [], @@ -88,7 +88,7 @@ 'MEDIA_INPUT_CLUSTER': [], 'MEDIA_PLAYBACK_CLUSTER': [], 'NETWORK_COMMISSIONING_CLUSTER': [], - 'OCCUPANCY_SENSING_CLUSTER': [], + 'OCCUPANCY_SENSING_CLUSTER': ['occupancy-sensor-server'], 'ON_OFF_CLUSTER': [], 'OPERATIONAL_CREDENTIALS_CLUSTER': [], 'OTA_BOOTLOAD_CLUSTER': [], From f3dfe086dce9d9535c57c0bd92a57869621f6d09 Mon Sep 17 00:00:00 2001 From: Markus Becker Date: Wed, 19 May 2021 11:22:44 +0200 Subject: [PATCH 13/13] Add generated modified files --- .../gen/call-command-handler.cpp | 5 ++ .../all-clusters-common/gen/callback-stub.cpp | 8 ++ .../all-clusters-common/gen/callback.h | 79 +++++++++++++++++++ .../all-clusters-common/gen/endpoint_config.h | 32 ++++++-- .../all-clusters-common/gen/gen_config.h | 6 ++ 5 files changed, 124 insertions(+), 6 deletions(-) diff --git a/examples/all-clusters-app/all-clusters-common/gen/call-command-handler.cpp b/examples/all-clusters-app/all-clusters-common/gen/call-command-handler.cpp index 3bd9de82e6fd87..80edb083678ec4 100644 --- a/examples/all-clusters-app/all-clusters-common/gen/call-command-handler.cpp +++ b/examples/all-clusters-app/all-clusters-common/gen/call-command-handler.cpp @@ -47,6 +47,7 @@ EmberAfStatus emberAfLowPowerClusterServerCommandParse(EmberAfClusterCommand * c EmberAfStatus emberAfNetworkCommissioningClusterServerCommandParse(EmberAfClusterCommand * cmd); EmberAfStatus emberAfOtaSoftwareUpdateClientClusterServerCommandParse(EmberAfClusterCommand * cmd); EmberAfStatus emberAfOtaSoftwareUpdateServerClusterServerCommandParse(EmberAfClusterCommand * cmd); +EmberAfStatus emberAfOccupancySensingClusterServerCommandParse(EmberAfClusterCommand * cmd); EmberAfStatus emberAfOnOffClusterServerCommandParse(EmberAfClusterCommand * cmd); EmberAfStatus emberAfOperationalCredentialsClusterServerCommandParse(EmberAfClusterCommand * cmd); EmberAfStatus emberAfPumpConfigurationAndControlClusterServerCommandParse(EmberAfClusterCommand * cmd); @@ -161,6 +162,10 @@ EmberAfStatus emberAfClusterSpecificCommandParse(EmberAfClusterCommand * cmd) case ZCL_OTA_SERVER_CLUSTER_ID: result = emberAfOtaSoftwareUpdateServerClusterServerCommandParse(cmd); break; + case ZCL_OCCUPANCY_SENSING_CLUSTER_ID: + // No commands are enabled for cluster Occupancy Sensing + result = status(false, true, cmd->mfgSpecific); + break; case ZCL_ON_OFF_CLUSTER_ID: result = emberAfOnOffClusterServerCommandParse(cmd); break; diff --git a/examples/all-clusters-app/all-clusters-common/gen/callback-stub.cpp b/examples/all-clusters-app/all-clusters-common/gen/callback-stub.cpp index aba6e42e22b945..b58383c0902168 100644 --- a/examples/all-clusters-app/all-clusters-common/gen/callback-stub.cpp +++ b/examples/all-clusters-app/all-clusters-common/gen/callback-stub.cpp @@ -86,6 +86,9 @@ void emberAfClusterInitCallback(EndpointId endpoint, ClusterId clusterId) case ZCL_OTA_SERVER_CLUSTER_ID: emberAfOtaSoftwareUpdateServerClusterInitCallback(endpoint); break; + case ZCL_OCCUPANCY_SENSING_CLUSTER_ID: + emberAfOccupancySensingClusterInitCallback(endpoint); + break; case ZCL_ON_OFF_CLUSTER_ID: emberAfOnOffClusterInitCallback(endpoint); break; @@ -220,6 +223,11 @@ void __attribute__((weak)) emberAfOtaSoftwareUpdateServerClusterInitCallback(End // To prevent warning (void) endpoint; } +void __attribute__((weak)) emberAfOccupancySensingClusterInitCallback(EndpointId endpoint) +{ + // To prevent warning + (void) endpoint; +} void __attribute__((weak)) emberAfOnOffClusterInitCallback(EndpointId endpoint) { // To prevent warning diff --git a/examples/all-clusters-app/all-clusters-common/gen/callback.h b/examples/all-clusters-app/all-clusters-common/gen/callback.h index 2b6ae92c27e07d..3dbae3f35b85c6 100644 --- a/examples/all-clusters-app/all-clusters-common/gen/callback.h +++ b/examples/all-clusters-app/all-clusters-common/gen/callback.h @@ -192,6 +192,14 @@ void emberAfOtaSoftwareUpdateClientClusterInitCallback(chip::EndpointId endpoint */ void emberAfOtaSoftwareUpdateServerClusterInitCallback(chip::EndpointId endpoint); +/** @brief Occupancy Sensing Cluster Init + * + * Cluster Init + * + * @param endpoint Endpoint that is being initialized + */ +void emberAfOccupancySensingClusterInitCallback(chip::EndpointId endpoint); + /** @brief On/off Cluster Init * * Cluster Init @@ -1623,6 +1631,77 @@ EmberAfStatus emberAfOtaSoftwareUpdateServerClusterServerPreAttributeChangedCall */ void emberAfOtaSoftwareUpdateServerClusterServerTickCallback(chip::EndpointId endpoint); +// +// Occupancy Sensing Cluster server +// + +/** @brief Occupancy Sensing Cluster Server Init + * + * Server Init + * + * @param endpoint Endpoint that is being initialized + */ +void emberAfOccupancySensingClusterServerInitCallback(chip::EndpointId endpoint); + +/** @brief Occupancy Sensing Cluster Server Attribute Changed + * + * Server Attribute Changed + * + * @param endpoint Endpoint that is being initialized + * @param attributeId Attribute that changed + */ +void emberAfOccupancySensingClusterServerAttributeChangedCallback(chip::EndpointId endpoint, chip::AttributeId attributeId); + +/** @brief Occupancy Sensing Cluster Server Manufacturer Specific Attribute Changed + * + * Server Manufacturer Specific Attribute Changed + * + * @param endpoint Endpoint that is being initialized + * @param attributeId Attribute that changed + * @param manufacturerCode Manufacturer Code of the attribute that changed + */ +void emberAfOccupancySensingClusterServerManufacturerSpecificAttributeChangedCallback(chip::EndpointId endpoint, + chip::AttributeId attributeId, + uint16_t manufacturerCode); + +/** @brief Occupancy Sensing Cluster Server Message Sent + * + * Server Message Sent + * + * @param type The type of message sent + * @param destination The destination to which the message was sent + * @param apsFrame The APS frame for the message + * @param msgLen The length of the message + * @param message The message that was sent + * @param status The status of the sent message + */ +void emberAfOccupancySensingClusterServerMessageSentCallback(EmberOutgoingMessageType type, + chip::MessageSendDestination destination, EmberApsFrame * apsFrame, + uint16_t msgLen, uint8_t * message, EmberStatus status); + +/** @brief Occupancy Sensing Cluster Server Pre Attribute Changed + * + * server Pre Attribute Changed + * + * @param endpoint Endpoint that is being initialized + * @param attributeId Attribute to be changed + * @param attributeType Attribute type + * @param size Attribute size + * @param value Attribute value + */ +EmberAfStatus emberAfOccupancySensingClusterServerPreAttributeChangedCallback(chip::EndpointId endpoint, + chip::AttributeId attributeId, + EmberAfAttributeType attributeType, uint16_t size, + uint8_t * value); + +/** @brief Occupancy Sensing Cluster Server Tick + * + * server Tick + * + * @param endpoint Endpoint that is being served + */ +void emberAfOccupancySensingClusterServerTickCallback(chip::EndpointId endpoint); + // // On/off Cluster server // diff --git a/examples/all-clusters-app/all-clusters-common/gen/endpoint_config.h b/examples/all-clusters-app/all-clusters-common/gen/endpoint_config.h index 61a61f39a79be0..8ab197abe41858 100644 --- a/examples/all-clusters-app/all-clusters-common/gen/endpoint_config.h +++ b/examples/all-clusters-app/all-clusters-common/gen/endpoint_config.h @@ -1179,7 +1179,7 @@ #define ZAP_ATTRIBUTE_MASK(mask) ATTRIBUTE_MASK_##mask // This is an array of EmberAfAttributeMetadata structures. -#define GENERATED_ATTRIBUTE_COUNT 250 +#define GENERATED_ATTRIBUTE_COUNT 254 #define GENERATED_ATTRIBUTES \ { \ \ @@ -1512,6 +1512,12 @@ /* Endpoint: 2, Cluster: On/off (server) */ \ { 0x0000, ZAP_TYPE(BOOLEAN), 1, 0, ZAP_SIMPLE_DEFAULT(0x00) }, /* on/off */ \ { 0xFFFD, ZAP_TYPE(INT16U), 2, 0, ZAP_SIMPLE_DEFAULT(2) }, /* cluster revision */ \ + \ + /* Endpoint: 2, Cluster: Occupancy Sensing (server) */ \ + { 0x0000, ZAP_TYPE(BITMAP8), 1, 0, ZAP_EMPTY_DEFAULT() }, /* occupancy */ \ + { 0x0001, ZAP_TYPE(ENUM8), 1, 0, ZAP_EMPTY_DEFAULT() }, /* occupancy sensor type */ \ + { 0x0002, ZAP_TYPE(BITMAP8), 1, 0, ZAP_EMPTY_DEFAULT() }, /* occupancy sensor type bitmap */ \ + { 0xFFFD, ZAP_TYPE(INT16U), 2, 0, ZAP_SIMPLE_DEFAULT(2) }, /* cluster revision */ \ } // This is an array of EmberAfCluster structures. @@ -1548,10 +1554,13 @@ (EmberAfGenericClusterFunction) emberAfIasZoneClusterServerInitCallback, \ (EmberAfGenericClusterFunction) emberAfIasZoneClusterServerMessageSentCallback, \ (EmberAfGenericClusterFunction) emberAfIasZoneClusterServerPreAttributeChangedCallback, \ + }; \ + const EmberAfGenericClusterFunction chipFuncArrayOccupancySensingServer[] = { \ + (EmberAfGenericClusterFunction) emberAfOccupancySensingClusterServerInitCallback, \ }; #define ZAP_CLUSTER_MASK(mask) CLUSTER_MASK_##mask -#define GENERATED_CLUSTER_COUNT 33 +#define GENERATED_CLUSTER_COUNT 34 #define GENERATED_CLUSTERS \ { \ { \ @@ -1684,6 +1693,12 @@ 3, \ ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(INIT_FUNCTION), \ chipFuncArrayOnOffServer }, /* Endpoint: 2, Cluster: On/off (server) */ \ + { 0x0406, \ + ZAP_ATTRIBUTE_INDEX(250), \ + 4, \ + 5, \ + ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(INIT_FUNCTION), \ + chipFuncArrayOccupancySensingServer }, /* Endpoint: 2, Cluster: Occupancy Sensing (server) */ \ } #define ZAP_CLUSTER_INDEX(index) ((EmberAfCluster *) (&generatedClusters[index])) @@ -1691,7 +1706,7 @@ // This is an array of EmberAfEndpointType structures. #define GENERATED_ENDPOINT_TYPES \ { \ - { ZAP_CLUSTER_INDEX(0), 12, 3726 }, { ZAP_CLUSTER_INDEX(12), 20, 2130 }, { ZAP_CLUSTER_INDEX(32), 1, 3 }, \ + { ZAP_CLUSTER_INDEX(0), 12, 3726 }, { ZAP_CLUSTER_INDEX(12), 20, 2130 }, { ZAP_CLUSTER_INDEX(32), 2, 8 }, \ } // Largest attribute size is needed for various buffers @@ -1701,7 +1716,7 @@ #define ATTRIBUTE_SINGLETONS_SIZE (875) // Total size of attribute storage -#define ATTRIBUTE_MAX_SIZE (5859) +#define ATTRIBUTE_MAX_SIZE (5864) // Number of fixed endpoints #define FIXED_ENDPOINT_COUNT (3) @@ -1971,10 +1986,10 @@ #define ZAP_REPORT_DIRECTION(x) ZRD(x) // User options for plugin Reporting -#define EMBER_AF_PLUGIN_REPORTING_TABLE_SIZE (13) +#define EMBER_AF_PLUGIN_REPORTING_TABLE_SIZE (14) #define EMBER_AF_PLUGIN_REPORTING_ENABLE_GROUP_BOUND_REPORTS -#define EMBER_AF_GENERATED_REPORTING_CONFIG_DEFAULTS_TABLE_SIZE (13) +#define EMBER_AF_GENERATED_REPORTING_CONFIG_DEFAULTS_TABLE_SIZE (14) #define EMBER_AF_GENERATED_REPORTING_CONFIG_DEFAULTS \ { \ \ @@ -2034,4 +2049,9 @@ { \ ZAP_REPORT_DIRECTION(REPORTED), 0x0002, 0x0006, 0x0000, ZAP_CLUSTER_MASK(SERVER), 0x0000, { { 0, 65344, 0 } } \ }, /* on/off */ \ + \ + /* Endpoint: 2, Cluster: Occupancy Sensing (server) */ \ + { \ + ZAP_REPORT_DIRECTION(REPORTED), 0x0002, 0x0406, 0x0000, ZAP_CLUSTER_MASK(SERVER), 0x0000, { { 0, 65344, 0 } } \ + }, /* occupancy */ \ } diff --git a/examples/all-clusters-app/all-clusters-common/gen/gen_config.h b/examples/all-clusters-app/all-clusters-common/gen/gen_config.h index b485a36bebf8df..264dd3962c0f07 100644 --- a/examples/all-clusters-app/all-clusters-common/gen/gen_config.h +++ b/examples/all-clusters-app/all-clusters-common/gen/gen_config.h @@ -48,6 +48,7 @@ #define EMBER_AF_NETWORK_COMMISSIONING_CLUSTER_SERVER_ENDPOINT_COUNT (1) #define EMBER_AF_OTA_CLIENT_CLUSTER_SERVER_ENDPOINT_COUNT (1) #define EMBER_AF_OTA_SERVER_CLUSTER_SERVER_ENDPOINT_COUNT (1) +#define EMBER_AF_OCCUPANCY_SENSING_CLUSTER_SERVER_ENDPOINT_COUNT (1) #define EMBER_AF_ON_OFF_CLUSTER_SERVER_ENDPOINT_COUNT (2) #define EMBER_AF_OPERATIONAL_CREDENTIALS_CLUSTER_SERVER_ENDPOINT_COUNT (1) #define EMBER_AF_PUMP_CONFIG_CONTROL_CLUSTER_SERVER_ENDPOINT_COUNT (1) @@ -167,6 +168,11 @@ #define EMBER_AF_PLUGIN_OTA_SOFTWARE_UPDATE_SERVER_SERVER #define EMBER_AF_PLUGIN_OTA_SOFTWARE_UPDATE_SERVER +// Use this macro to check if the server side of the Occupancy Sensing cluster is included +#define ZCL_USING_OCCUPANCY_SENSING_CLUSTER_SERVER +#define EMBER_AF_PLUGIN_OCCUPANCY_SENSING_SERVER +#define EMBER_AF_PLUGIN_OCCUPANCY_SENSING + // Use this macro to check if the server side of the On/off cluster is included #define ZCL_USING_ON_OFF_CLUSTER_SERVER #define EMBER_AF_PLUGIN_ON_OFF_SERVER