diff --git a/examples/platform/efr32/TemperatureSensor.cpp b/examples/platform/efr32/TemperatureSensor.cpp new file mode 100644 index 00000000000000..69ba106fd69872 --- /dev/null +++ b/examples/platform/efr32/TemperatureSensor.cpp @@ -0,0 +1,49 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * 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. + */ + +#include "TemperatureSensor.h" + +#ifdef __cplusplus +extern "C" { +#endif +// This is a C implementation. Need the ifdef __cplusplus else we get linking issues +#include "sl_sensor_rht.h" + +#ifdef __cplusplus +} +#endif + +namespace TemperatureSensor { +constexpr uint16_t kSensorTemperatureOffset = 800; + +sl_status_t Init() +{ + return sl_sensor_rht_init(); +} + +sl_status_t GetTemp(uint32_t * relativeHumidity, int16_t * temperature) +{ + // Sensor resolution 0.001 C + // DataModel resolution 0.01 C + int32_t temp; + sl_status_t status = sl_sensor_rht_get(relativeHumidity, &temp); + *temperature = static_cast(temp / 10) - kSensorTemperatureOffset; + return status; +} +}; // namespace TemperatureSensor diff --git a/examples/platform/efr32/TemperatureSensor.h b/examples/platform/efr32/TemperatureSensor.h new file mode 100644 index 00000000000000..116287e9a37155 --- /dev/null +++ b/examples/platform/efr32/TemperatureSensor.h @@ -0,0 +1,28 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * 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 "sl_status.h" +#include + +namespace TemperatureSensor { +sl_status_t Init(); +sl_status_t GetTemp(uint32_t * relativeHumidity, int16_t * temperature); +}; // namespace TemperatureSensor diff --git a/examples/platform/efr32/display/lcd.cpp b/examples/platform/efr32/display/lcd.cpp index e73770259358e8..8e6b38eb4ca0a8 100644 --- a/examples/platform/efr32/display/lcd.cpp +++ b/examples/platform/efr32/display/lcd.cpp @@ -135,8 +135,20 @@ void SilabsLCD::WriteDemoUI(bool state) void SilabsLCD::WriteDemoUI() { Clear(); - demoUIClearMainScreen(mName); - demoUIDisplayApp(dState.mainState); + if (customUI != nullptr) + { + customUI(&glibContext); + } + else + { + demoUIClearMainScreen(mName); + demoUIDisplayApp(dState.mainState); + } +} + +void SilabsLCD::SetCustomUI(customUICB cb) +{ + customUI = cb; } #ifdef QR_CODE_ENABLED diff --git a/examples/platform/efr32/display/lcd.h b/examples/platform/efr32/display/lcd.h index c9729e15d05de4..d375b7a133c9aa 100644 --- a/examples/platform/efr32/display/lcd.h +++ b/examples/platform/efr32/display/lcd.h @@ -33,12 +33,15 @@ class SilabsLCD { public: + typedef void (*customUICB)(GLIB_Context_t * context); CHIP_ERROR Init(uint8_t * name = nullptr, bool initialState = false); void * Context(); int Clear(void); int DrawPixel(void * pContext, int32_t x, int32_t y); int Update(void); void WriteDemoUI(bool state); + void SetCustomUI(customUICB cb); + #ifdef QR_CODE_ENABLED void SetQRCode(uint8_t * str, uint32_t size); void ShowQRCode(bool show, bool forceRefresh = false); @@ -66,6 +69,6 @@ class SilabsLCD #else uint8_t mName[APP_NAME_MAX_LENGTH + 1]; #endif - - DemoState_t dState; + customUICB customUI = nullptr; + DemoState_t dState; }; diff --git a/examples/thermostat/efr32/BUILD.gn b/examples/thermostat/efr32/BUILD.gn index da732a26122b1d..690023d185c835 100644 --- a/examples/thermostat/efr32/BUILD.gn +++ b/examples/thermostat/efr32/BUILD.gn @@ -33,6 +33,7 @@ assert(current_os == "freertos") efr32_project_dir = "${chip_root}/examples/thermostat/efr32" examples_plat_dir = "${chip_root}/examples/platform/efr32" +efr32_sdk_root = "${chip_root}/third_party/silabs/gecko_sdk" declare_args() { # Dump memory usage at link time. @@ -59,6 +60,10 @@ declare_args() { # Argument to Disable IPv4 for wifi(rs911) chip_enable_wifi_ipv4 = false + + # Enable the temperature sensor + # Some boards do not have a temperature sensor + use_temp_sensor = silabs_board != "BRD2703A" && silabs_board != "BRD4319A" } declare_args() { @@ -133,6 +138,7 @@ efr32_sdk("sdk") { "${efr32_project_dir}/include", "${examples_plat_dir}", "${chip_root}/src/lib", + "${efr32_sdk_root}/app/common/util/app_assert", ] defines = [ @@ -172,6 +178,18 @@ efr32_sdk("sdk") { defines += [ "SL_WFX_CONFIG_SCAN" ] } } + if (use_temp_sensor) { + include_dirs += [ + "${efr32_sdk_root}/platform/driver/i2cspm/inc", + "${efr32_sdk_root}/app/bluetooth/common/sensor_rht", + "${efr32_sdk_root}/app/bluetooth/common/sensor_rht/config", + "${efr32_sdk_root}/hardware/driver/si70xx/inc", + "${efr32_sdk_root}/app/bluetooth/common/sensor_select", + "${efr32_sdk_root}/platform/common/config", + ] + + defines += [ "USE_TEMP_SENSOR" ] + } } efr32_executable("thermostat_app") { @@ -186,6 +204,8 @@ efr32_executable("thermostat_app") { "${examples_plat_dir}/init_efrPlatform.cpp", "${examples_plat_dir}/matter_config.cpp", "src/AppTask.cpp", + "src/SensorManager.cpp", + "src/TemperatureManager.cpp", "src/ZclCallbacks.cpp", "src/main.cpp", ] @@ -194,6 +214,19 @@ efr32_executable("thermostat_app") { sources += [ "${examples_plat_dir}/LEDWidget.cpp" ] } + if (use_temp_sensor) { + sources += [ + "${efr32_sdk_root}/app/bluetooth/common/sensor_rht/sl_sensor_rht.c", + "${efr32_sdk_root}/app/bluetooth/common/sensor_select/sl_sensor_select.c", + "${efr32_sdk_root}/hardware/driver/si70xx/src/sl_si70xx.c", + "${efr32_sdk_root}/platform/common/src/sl_status.c", + "${efr32_sdk_root}/platform/driver/i2cspm/src/sl_i2cspm.c", + "${efr32_sdk_root}/platform/emlib/src/em_i2c.c", + "${examples_plat_dir}/TemperatureSensor.cpp", + "${sdk_support_root}/matter/efr32/${silabs_family}/${silabs_board}/autogen/sl_i2cspm_init.c", + ] + } + if (chip_enable_pw_rpc || chip_build_libshell || enable_openthread_cli || use_wf200 || use_rs911x) { sources += [ "${examples_plat_dir}/uart.cpp" ] @@ -268,6 +301,7 @@ efr32_executable("thermostat_app") { sources += [ "${examples_plat_dir}/display/demo-ui.c", "${examples_plat_dir}/display/lcd.cpp", + "src/ThermostatUI.cpp", ] include_dirs += [ "${examples_plat_dir}/display" ] defines += [ diff --git a/examples/thermostat/efr32/include/AppEvent.h b/examples/thermostat/efr32/include/AppEvent.h index 7a19b719edad25..d8d7de44079886 100644 --- a/examples/thermostat/efr32/include/AppEvent.h +++ b/examples/thermostat/efr32/include/AppEvent.h @@ -28,7 +28,6 @@ struct AppEvent { kEventType_Button = 0, kEventType_Timer, - kEventType_Light, kEventType_Install, }; @@ -44,11 +43,6 @@ struct AppEvent { void * Context; } TimerEvent; - struct - { - uint8_t Action; - int32_t Actor; - } LightEvent; }; EventHandler Handler; diff --git a/examples/thermostat/efr32/include/AppTask.h b/examples/thermostat/efr32/include/AppTask.h index 800dda99ad37ac..ce4fa6f0fef43c 100644 --- a/examples/thermostat/efr32/include/AppTask.h +++ b/examples/thermostat/efr32/include/AppTask.h @@ -26,9 +26,15 @@ #include #include +#ifdef DISPLAY_ENABLED +#include "ThermostatUI.h" +#endif + #include "AppEvent.h" #include "BaseApplication.h" #include "FreeRTOS.h" +#include "SensorManager.h" +#include "TemperatureManager.h" #include "sl_simple_button_instances.h" #include "timers.h" // provides FreeRTOS timer support #include @@ -69,6 +75,11 @@ class AppTask : public BaseApplication CHIP_ERROR StartAppTask(); + /** + * @brief Request an update of the Thermostat LCD UI + */ + void UpdateThermoStatUI(); + /** * @brief Event handler when a button is pressed * Function posts an event for button processing @@ -112,11 +123,5 @@ class AppTask : public BaseApplication */ static void ButtonHandler(AppEvent * aEvent); - /** - * @brief PB1 Button event processing function - * Function triggers a thermostat action sent to the CHIP task - * - * @param aEvent button event being processed - */ static void ThermostatActionEventHandler(AppEvent * aEvent); }; diff --git a/examples/thermostat/efr32/include/CHIPProjectConfig.h b/examples/thermostat/efr32/include/CHIPProjectConfig.h index 94c82dcbb0281d..35f6d54e785c70 100644 --- a/examples/thermostat/efr32/include/CHIPProjectConfig.h +++ b/examples/thermostat/efr32/include/CHIPProjectConfig.h @@ -57,7 +57,7 @@ * * 0x8005: example lighting app */ -#define CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID 0x8004 +#define CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID 0x800E /** * CHIP_DEVICE_CONFIG_DEVICE_HARDWARE_VERSION @@ -97,6 +97,14 @@ */ #define CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE 1 +/** + * CHIP_DEVICE_CONFIG_ENABLE_CHIP_TIME_SERVICE_TIME_SYNC + * + * Enables synchronizing the device's real time clock with a remote Chip Time service + * using the Chip Time Sync protocol. + */ +#define CHIP_DEVICE_CONFIG_ENABLE_CHIP_TIME_SERVICE_TIME_SYNC 0 + /** * CHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER * diff --git a/examples/thermostat/efr32/include/SensorManager.h b/examples/thermostat/efr32/include/SensorManager.h new file mode 100644 index 00000000000000..9c910abb35881e --- /dev/null +++ b/examples/thermostat/efr32/include/SensorManager.h @@ -0,0 +1,48 @@ +/* + * + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * 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 + +#include "AppEvent.h" + +#include "FreeRTOS.h" +#include "timers.h" // provides FreeRTOS timer support +#include +#include + +class SensorManager +{ +public: + CHIP_ERROR Init(); + +private: + friend SensorManager & SensorMgr(); + + // Reads new generated sensor value, stores it, and updates local temperature attribute + static void SensorTimerEventHandler(TimerHandle_t xTimer); + + static SensorManager sSensorManager; +}; + +inline SensorManager & SensorMgr() +{ + return SensorManager::sSensorManager; +} diff --git a/examples/thermostat/efr32/include/TemperatureManager.h b/examples/thermostat/efr32/include/TemperatureManager.h new file mode 100644 index 00000000000000..1005a6753fe450 --- /dev/null +++ b/examples/thermostat/efr32/include/TemperatureManager.h @@ -0,0 +1,69 @@ +/* + * + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * 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 + +#include "AppEvent.h" + +#include "FreeRTOS.h" +#include "timers.h" // provides FreeRTOS timer support +#include + +#include + +using namespace chip; + +// AppCluster Spec Table 85. +enum ThermMode +{ + OFF = 0, + AUTO, + NOT_USED, + COOL, + HEAT, +}; + +class TemperatureManager +{ +public: + CHIP_ERROR Init(); + void AttributeChangeHandler(EndpointId endpointId, AttributeId attributeId, uint8_t * value, uint16_t size); + uint8_t GetMode(); + int8_t GetCurrentTemp(); + int8_t GetHeatingSetPoint(); + int8_t GetCoolingSetPoint(); + +private: + friend TemperatureManager & TempMgr(); + + int8_t mCurrentTempCelsius; + int8_t mCoolingCelsiusSetPoint; + int8_t mHeatingCelsiusSetPoint; + uint8_t mThermMode; + + int8_t ConvertToPrintableTemp(int16_t temperature); + static TemperatureManager sTempMgr; +}; + +inline TemperatureManager & TempMgr() +{ + return TemperatureManager::sTempMgr; +} diff --git a/examples/thermostat/efr32/include/ThermostatIcons.h b/examples/thermostat/efr32/include/ThermostatIcons.h new file mode 100644 index 00000000000000..094775fa9f2141 --- /dev/null +++ b/examples/thermostat/efr32/include/ThermostatIcons.h @@ -0,0 +1,218 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * All rights reserved. + * + * 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 + +#define SILABS_LOGO_WIDTH 47 +#define SILABS_LOGO_HEIGHT 18 +#define BLUETOOTH_ICON_SIZE 18 + +// Status Icon defines +#define STATUS_ICON_LINE 0 +#define SILABS_ICON_POSITION_X 0 +#define BLE_ICON_POSITION_X 72 +#define NETWORK_ICON_POSITION_X 90 +#define MATTER_ICON_POSITION_X 108 + +// Heating/Cooling position +#define HEATING_COOLING_X 90 +#define HEATING_COOLING_Y 40 + +#define BLUETOOTH_ICON_SMALL \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0x7F, 0xFE, 0xEF, 0xF1, 0x7F, 0x9F, 0xFF, 0x7B, 0xFF, 0x1F, 0xFE, 0xFF, 0xFC, 0xFF, \ + 0xF3, 0xFF, 0x87, 0xFF, 0xEF, 0xFD, 0xDF, 0xE7, 0xBF, 0xC7, 0xFF, 0x9F, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F + +#define SILABS_LOGO_SMALL \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, \ + 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x80, 0x3F, 0xFF, 0xFF, 0xFF, 0x00, 0xE0, 0x9F, 0xFF, 0xE7, 0x3F, 0xE0, 0xF1, 0x83, \ + 0xFF, 0xF9, 0xEF, 0xFF, 0x3F, 0xE0, 0x3F, 0xFC, 0xFF, 0xFF, 0x7F, 0xF8, 0x0F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFE, 0x03, 0xFC, \ + 0xFF, 0xF7, 0x9F, 0xFF, 0x81, 0x07, 0x02, 0xF8, 0xFF, 0xFF, 0xE0, 0x07, 0x00, 0xFE, 0xFF, 0xFF, 0xF8, 0x03, 0xC0, 0xFF, \ + 0xFF, 0xFF, 0xFE, 0x9F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0x3F + +#define HEATING_BITMAP \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFE, 0xFF, 0xFF, \ + 0x3F, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xFE, 0x7F, 0xFC, 0x1F, \ + 0x1F, 0xF8, 0xF8, 0x3F, 0x07, 0xE0, 0xFC, 0xBF, 0xC7, 0xE3, 0xFD, 0xFF, 0xE3, 0xC7, 0xFF, 0xFF, 0xF3, 0xCF, 0xFF, 0xFF, \ + 0xF3, 0xCF, 0xFF, 0xFF, 0xF3, 0xCF, 0xFF, 0xFF, 0xF3, 0xCF, 0xFF, 0xFF, 0xE3, 0xC7, 0xFF, 0xBF, 0xC7, 0xE3, 0xFD, 0x3F, \ + 0x07, 0xE0, 0xFC, 0x1F, 0x1F, 0xF8, 0xF8, 0x3F, 0xFE, 0x7F, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xBF, 0xFD, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x7F, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + +#define HEATING_WIDTH 32 +#define HEATING_HEIGHT 32 + +#define COOLING_BITMAP \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0xFD, 0xFF, 0xFF, 0x1F, 0xF8, 0xFF, 0xFF, \ + 0x3F, 0xFC, 0xFF, 0xFF, 0x7F, 0xFE, 0xFF, 0xFF, 0x7F, 0xFE, 0xFF, 0x3F, 0x7F, 0xFE, 0xFC, 0x3F, 0x7F, 0xFE, 0xFC, 0x3F, \ + 0x3E, 0x7C, 0xFC, 0x0F, 0x0C, 0x30, 0xF0, 0xCF, 0x80, 0x01, 0xF3, 0xFF, 0xE3, 0xC7, 0xFF, 0xFF, 0xF3, 0xCF, 0xFF, 0xFF, \ + 0xF3, 0xCF, 0xFF, 0xFF, 0xF3, 0xCF, 0xFF, 0xFF, 0xF3, 0xCF, 0xFF, 0xFF, 0xE3, 0xC7, 0xFF, 0xCF, 0x80, 0x01, 0xF3, 0x0F, \ + 0x0C, 0x30, 0xF0, 0x3F, 0x3E, 0x7C, 0xFC, 0x3F, 0x7F, 0xFE, 0xFC, 0x3F, 0x7F, 0xFE, 0xFC, 0xFF, 0x7F, 0xFE, 0xFF, 0xFF, \ + 0x7F, 0xFE, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x1F, 0xF8, 0xFF, 0xFF, 0xBF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + +#define HEATING_COOLING_BITMAP \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFC, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, \ + 0xFC, 0xE0, 0xFF, 0xFF, 0xFC, 0xF9, 0xF7, 0x7F, 0xFC, 0xF8, 0xF3, 0x1F, 0xFC, 0xFC, 0xF9, 0x1F, 0x78, 0xFC, 0xFC, 0xFF, \ + 0x01, 0x7C, 0xFE, 0xFF, 0x03, 0x3C, 0xFF, 0xFF, 0xE3, 0x9F, 0xFF, 0xFF, 0xF3, 0x8F, 0xF3, 0xFF, 0xF3, 0x87, 0xE3, 0xFF, \ + 0xF3, 0x83, 0xF7, 0xC7, 0xF0, 0x01, 0xF7, 0x07, 0xF0, 0x00, 0xFF, 0x0F, 0x7F, 0x00, 0xFF, 0xCF, 0x3F, 0x80, 0xFF, 0xCF, \ + 0x1F, 0x80, 0xFF, 0xFF, 0x0F, 0xC0, 0xFF, 0xFF, 0x07, 0xE0, 0xFD, 0xFF, 0xF3, 0xF8, 0xFD, 0xFF, 0xF9, 0xFF, 0xFC, 0xFF, \ + 0xFC, 0x3F, 0xFC, 0x7F, 0xDE, 0xFF, 0xFF, 0x3F, 0x1F, 0xFE, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + +#define COOLING_WIDTH 32 +#define COOLING_HEIGHT 32 + +// Font for temperature +#define CELSIUS_INDEX 2320 +#define FAHRENHEIT_INDEX 2370 +#define DEGREE_INDEX 2420 + +#define MONACO_FONT_WIDTH 29 +#define MONACO_FONT_NB_LENGTH 232 +#define MONACO_FONT_CH_LENGTH 50 + +#define MONACO_48PT \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xFC, 0xFF, 0xFF, \ + 0x00, 0xF0, 0xFF, 0x7F, 0x00, 0xC0, 0xFF, 0x3F, 0x00, 0x80, 0xFF, 0x1F, 0x60, 0x00, 0xFF, 0x1F, 0xF8, 0x03, 0xFF, 0x0F, \ + 0xFC, 0x07, 0xFE, 0x07, 0xFE, 0x07, 0xFE, 0x07, 0xFE, 0x07, 0xFC, 0x07, 0xFF, 0x03, 0xFC, 0x03, 0xFF, 0x03, 0xFC, 0x03, \ + 0xFF, 0x01, 0xF8, 0x83, 0xFF, 0x00, 0xF8, 0x83, 0xFF, 0x00, 0xF8, 0x83, 0x7F, 0x30, 0xF8, 0x83, 0x3F, 0x30, 0xF8, 0x83, \ + 0x3F, 0x38, 0xF8, 0x81, 0x1F, 0x3C, 0xF8, 0x81, 0x0F, 0x3C, 0xF8, 0x81, 0x0F, 0x3E, 0xF8, 0x81, 0x07, 0x3E, 0xF8, 0x81, \ + 0x07, 0x3F, 0xF8, 0x83, 0x83, 0x3F, 0xF8, 0x83, 0x81, 0x3F, 0xF8, 0x83, 0xC1, 0x3F, 0xF8, 0x83, 0xE0, 0x1F, 0xF8, 0x03, \ + 0xE0, 0x1F, 0xF8, 0x03, 0xF0, 0x1F, 0xF8, 0x03, 0xF8, 0x1F, 0xFC, 0x07, 0xF8, 0x0F, 0xFC, 0x07, 0xFC, 0x0F, 0xFC, 0x07, \ + 0xFC, 0x07, 0xFE, 0x0F, 0xFC, 0x07, 0xFE, 0x0F, 0xF8, 0x03, 0xFF, 0x1F, 0xE0, 0x00, 0xFF, 0x3F, 0x00, 0x80, 0xFF, 0x7F, \ + 0x00, 0xC0, 0xFF, 0xFF, 0x00, 0xE0, 0xFF, 0xFF, 0x03, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* Character 0x30 (48: '0')*/ \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0x0F, 0xFC, 0xFF, 0xFF, 0x07, 0xFC, 0xFF, 0xFF, 0x03, 0xFC, 0xFF, 0xFF, 0x00, 0xFC, 0xFF, 0x3F, 0x00, 0xFC, 0xFF, \ + 0x1F, 0x00, 0xFC, 0xFF, 0x0F, 0x10, 0xFC, 0xFF, 0x0F, 0x1C, 0xFC, 0xFF, 0x0F, 0x1E, 0xFC, 0xFF, 0xCF, 0x1F, 0xFC, 0xFF, \ + 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, \ + 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, \ + 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, \ + 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, \ + 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0x0F, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xF8, \ + 0x0F, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* Character 0x31 (49: '1')*/ \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xF8, 0xFF, \ + 0x3F, 0x00, 0xC0, 0xFF, 0x0F, 0x00, 0x80, 0xFF, 0x0F, 0x00, 0x00, 0xFF, 0x0F, 0xF8, 0x00, 0xFF, 0x0F, 0xFF, 0x03, 0xFE, \ + 0xEF, 0xFF, 0x07, 0xFE, 0xFF, 0xFF, 0x0F, 0xFE, 0xFF, 0xFF, 0x0F, 0xFE, 0xFF, 0xFF, 0x0F, 0xFE, 0xFF, 0xFF, 0x0F, 0xFE, \ + 0xFF, 0xFF, 0x07, 0xFE, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, \ + 0xFF, 0x7F, 0xC0, 0xFF, 0xFF, 0x3F, 0xE0, 0xFF, 0xFF, 0x1F, 0xF0, 0xFF, 0xFF, 0x0F, 0xF8, 0xFF, 0xFF, 0x07, 0xFC, 0xFF, \ + 0xFF, 0x03, 0xFE, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0x7F, 0xE0, 0xFF, 0xFF, \ + 0x3F, 0xF0, 0xFF, 0xFF, 0x1F, 0xF8, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x0F, 0xFC, 0xFF, 0xFF, 0x0F, 0xFE, 0xFF, 0xFF, \ + 0x0F, 0xFE, 0xFF, 0xFF, 0x07, 0xFE, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0xFE, 0x07, 0x00, 0x00, 0xFC, 0x07, 0x00, 0x00, 0xFC, \ + 0x07, 0x00, 0x00, 0xFC, 0x07, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* Character 0x32 (50: '2')*/ \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFE, 0xFF, \ + 0x0F, 0x00, 0xF0, 0xFF, 0x0F, 0x00, 0xC0, 0xFF, 0x0F, 0x00, 0xC0, 0xFF, 0x0F, 0x7C, 0x80, 0xFF, 0x8F, 0xFF, 0x01, 0xFF, \ + 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, \ + 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0x7F, 0xC0, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, \ + 0x7F, 0x00, 0xF0, 0xFF, 0x7F, 0x00, 0xF8, 0xFF, 0x7F, 0x00, 0xE0, 0xFF, 0x7F, 0x00, 0x80, 0xFF, 0xFF, 0x7F, 0x00, 0xFF, \ + 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0x07, 0xFE, 0xFF, 0xFF, 0x07, 0xFE, 0xFF, 0xFF, 0x0F, 0xFC, 0xFF, 0xFF, 0x0F, 0xFC, \ + 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x0F, 0xFC, 0xFF, 0xFF, 0x0F, 0xFC, 0xFF, 0xFF, 0x0F, 0xFC, \ + 0xFF, 0xFF, 0x07, 0xFE, 0xF7, 0xFF, 0x07, 0xFE, 0x87, 0xFF, 0x01, 0xFF, 0x07, 0x7C, 0x80, 0xFF, 0x07, 0x00, 0xC0, 0xFF, \ + 0x07, 0x00, 0xE0, 0xFF, 0x0F, 0x00, 0xF0, 0xFF, 0x7F, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* Character 0x33 (51: '3')*/ \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0x7F, 0xE0, 0xFF, 0xFF, 0x7F, 0xE0, 0xFF, 0xFF, 0x3F, 0xE0, 0xFF, 0xFF, 0x1F, 0xE0, 0xFF, \ + 0xFF, 0x1F, 0xE0, 0xFF, 0xFF, 0x0F, 0xE0, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0x83, 0xE0, 0xFF, \ + 0xFF, 0x81, 0xE0, 0xFF, 0xFF, 0xC0, 0xE0, 0xFF, 0xFF, 0xE0, 0xE0, 0xFF, 0x7F, 0xE0, 0xE0, 0xFF, 0x3F, 0xF0, 0xE0, 0xFF, \ + 0x3F, 0xF8, 0xE0, 0xFF, 0x1F, 0xF8, 0xE0, 0xFF, 0x0F, 0xFC, 0xE0, 0xFF, 0x0F, 0xFE, 0xE0, 0xFF, 0x07, 0xFE, 0xE0, 0xFF, \ + 0x03, 0xFF, 0xE0, 0xFF, 0x83, 0xFF, 0xE0, 0xFF, 0x81, 0xFF, 0xC0, 0xFF, 0x01, 0x00, 0x00, 0xF0, 0x01, 0x00, 0x00, 0xF0, \ + 0x01, 0x00, 0x00, 0xF0, 0x01, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, \ + 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, \ + 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* Character 0x34 (52: '4')*/ \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0x0F, 0x00, 0x00, 0xFE, 0x0F, 0x00, 0x00, 0xFE, 0x0F, 0x00, 0x00, 0xFE, 0x0F, 0x00, 0x00, 0xFE, 0x0F, 0x00, 0x00, 0xFE, \ + 0x0F, 0xFE, 0xFF, 0xFF, 0x0F, 0xFE, 0xFF, 0xFF, 0x0F, 0xFE, 0xFF, 0xFF, 0x0F, 0xFE, 0xFF, 0xFF, 0x0F, 0xFE, 0xFF, 0xFF, \ + 0x0F, 0xFE, 0xFF, 0xFF, 0x0F, 0xFE, 0xFF, 0xFF, 0x0F, 0xFE, 0xFF, 0xFF, 0x0F, 0xC0, 0xFF, 0xFF, 0x0F, 0x00, 0xFC, 0xFF, \ + 0x0F, 0x00, 0xF0, 0xFF, 0x0F, 0x00, 0xC0, 0xFF, 0x0F, 0x00, 0x80, 0xFF, 0xFF, 0x0F, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFE, \ + 0xFF, 0xFF, 0x03, 0xFE, 0xFF, 0xFF, 0x07, 0xFE, 0xFF, 0xFF, 0x07, 0xFC, 0xFF, 0xFF, 0x0F, 0xFC, 0xFF, 0xFF, 0x0F, 0xFC, \ + 0xFF, 0xFF, 0x0F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x0F, 0xFC, 0xFF, 0xFF, 0x0F, 0xFC, 0xFF, 0xFF, 0x0F, 0xFC, \ + 0xFF, 0xFF, 0x07, 0xFE, 0xEF, 0xFF, 0x03, 0xFE, 0x07, 0xFF, 0x00, 0xFF, 0x07, 0x00, 0x80, 0xFF, 0x07, 0x00, 0xC0, 0xFF, \ + 0x07, 0x00, 0xE0, 0xFF, 0x0F, 0x00, 0xF0, 0xFF, 0xFF, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* Character 0x35 (53: '5')*/ \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xC0, 0xFF, \ + 0xFF, 0x07, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0xFE, 0x7F, 0x80, 0x07, 0xFE, 0x3F, 0xE0, 0x7F, 0xFE, \ + 0x1F, 0xF0, 0xFF, 0xFF, 0x1F, 0xF8, 0xFF, 0xFF, 0x0F, 0xFC, 0xFF, 0xFF, 0x0F, 0xFE, 0xFF, 0xFF, 0x07, 0xFE, 0xFF, 0xFF, \ + 0x07, 0xFE, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0x03, 0x0F, 0xE0, 0xFF, \ + 0x83, 0x03, 0x80, 0xFF, 0x83, 0x01, 0x00, 0xFF, 0x83, 0x00, 0x00, 0xFE, 0x03, 0xC0, 0x07, 0xFC, 0x03, 0xF0, 0x0F, 0xFC, \ + 0x03, 0xF8, 0x1F, 0xF8, 0x03, 0xFC, 0x3F, 0xF8, 0x03, 0xFC, 0x3F, 0xF8, 0x07, 0xFE, 0x3F, 0xF8, 0x07, 0xFE, 0x3F, 0xF8, \ + 0x07, 0xFE, 0x3F, 0xF8, 0x07, 0xFE, 0x3F, 0xF8, 0x07, 0xFE, 0x3F, 0xF8, 0x0F, 0xFE, 0x3F, 0xF8, 0x0F, 0xFC, 0x1F, 0xF8, \ + 0x0F, 0xFC, 0x1F, 0xFC, 0x1F, 0xF8, 0x0F, 0xFC, 0x1F, 0xF0, 0x07, 0xFE, 0x3F, 0xC0, 0x01, 0xFE, 0x7F, 0x00, 0x00, 0xFF, \ + 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x01, 0xE0, 0xFF, 0xFF, 0x07, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* Character 0x36 (54: '6')*/ \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0x0F, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xF8, \ + 0xFF, 0xFF, 0x3F, 0xF8, 0xFF, 0xFF, 0x1F, 0xF8, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x0F, 0xFE, 0xFF, 0xFF, 0x0F, 0xFE, \ + 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0xFF, 0xC1, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, \ + 0xFF, 0x7F, 0xE0, 0xFF, 0xFF, 0x3F, 0xF0, 0xFF, 0xFF, 0x3F, 0xF8, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x0F, 0xFC, 0xFF, \ + 0xFF, 0x07, 0xFE, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, \ + 0xFF, 0xC1, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0x7F, 0xE0, 0xFF, 0xFF, \ + 0x7F, 0xE0, 0xFF, 0xFF, 0x7F, 0xE0, 0xFF, 0xFF, 0x7F, 0xE0, 0xFF, 0xFF, 0x7F, 0xE0, 0xFF, 0xFF, 0x7F, 0xF0, 0xFF, 0xFF, \ + 0x7F, 0xF0, 0xFF, 0xFF, 0x7F, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* Character 0x37 (55: '7')*/ \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xF8, 0xFF, \ + 0xFF, 0x01, 0xE0, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0x7F, 0x00, 0x80, 0xFF, 0x3F, 0xE0, 0x00, 0xFF, 0x3F, 0xF8, 0x03, 0xFF, \ + 0x1F, 0xFC, 0x07, 0xFE, 0x1F, 0xFC, 0x0F, 0xFE, 0x1F, 0xFC, 0x0F, 0xFE, 0x1F, 0xFC, 0x0F, 0xFE, 0x1F, 0xFC, 0x07, 0xFE, \ + 0x1F, 0xF8, 0x07, 0xFF, 0x3F, 0xF0, 0x03, 0xFF, 0x3F, 0xE0, 0x81, 0xFF, 0x7F, 0xC0, 0x80, 0xFF, 0x7F, 0x00, 0xC0, 0xFF, \ + 0xFF, 0x00, 0xE0, 0xFF, 0xFF, 0x01, 0xF0, 0xFF, 0xFF, 0x03, 0xF8, 0xFF, 0xFF, 0x00, 0xE0, 0xFF, 0x7F, 0x00, 0xC0, 0xFF, \ + 0x3F, 0x60, 0x80, 0xFF, 0x1F, 0xF0, 0x00, 0xFF, 0x1F, 0xF8, 0x01, 0xFE, 0x0F, 0xFC, 0x03, 0xFE, 0x0F, 0xFC, 0x07, 0xFC, \ + 0x07, 0xFE, 0x0F, 0xFC, 0x07, 0xFE, 0x0F, 0xFC, 0x07, 0xFF, 0x1F, 0xFC, 0x07, 0xFF, 0x1F, 0xFC, 0x07, 0xFF, 0x1F, 0xFC, \ + 0x07, 0xFE, 0x0F, 0xFC, 0x07, 0xFC, 0x0F, 0xFC, 0x0F, 0xF8, 0x07, 0xFE, 0x0F, 0xE0, 0x01, 0xFE, 0x1F, 0x00, 0x00, 0xFF, \ + 0x3F, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0xE0, 0xFF, 0xFF, 0x03, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* Character 0x38 (56: '8')*/ \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xFE, 0xFF, \ + 0xFF, 0x00, 0xF0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x1F, 0x00, 0xC0, 0xFF, 0x0F, 0x70, 0x80, 0xFF, 0x07, 0xFC, 0x01, 0xFF, \ + 0x07, 0xFE, 0x03, 0xFF, 0x03, 0xFF, 0x03, 0xFF, 0x83, 0xFF, 0x07, 0xFE, 0x83, 0xFF, 0x07, 0xFE, 0x83, 0xFF, 0x0F, 0xFC, \ + 0xC1, 0xFF, 0x0F, 0xFC, 0xC1, 0xFF, 0x0F, 0xFC, 0xC1, 0xFF, 0x0F, 0xFC, 0x83, 0xFF, 0x07, 0xFC, 0x83, 0xFF, 0x07, 0xFC, \ + 0x83, 0xFF, 0x07, 0xFC, 0x03, 0xFF, 0x03, 0xF8, 0x03, 0xFE, 0x01, 0xF8, 0x07, 0x7C, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xF8, \ + 0x1F, 0x00, 0x10, 0xF8, 0x3F, 0x00, 0x1C, 0xFC, 0xFF, 0x00, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, \ + 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x0F, 0xFC, 0xFF, 0xFF, 0x0F, 0xFE, 0xFF, 0xFF, 0x07, 0xFE, 0xFF, 0xFF, 0x07, 0xFE, \ + 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0x81, 0xFF, 0xCF, 0xFF, 0x80, 0xFF, 0x0F, 0x3E, 0xC0, 0xFF, 0x0F, 0x00, 0xE0, 0xFF, \ + 0x0F, 0x00, 0xF0, 0xFF, 0x0F, 0x00, 0xFC, 0xFF, 0x3F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* Character 0x39 (57: '9')*/ \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFC, 0x1F, 0xE0, 0x0F, 0xE3, 0xC7, 0xFF, \ + 0xE3, 0xFF, 0xE3, 0xFF, 0xE3, 0xFF, 0xE3, 0xFF, 0xE3, 0xFF, 0xE3, 0xFF, 0xC3, 0xFF, 0x87, 0xEF, 0x0F, 0xE0, 0x1F, 0xE0, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* Character 0x63 (99: 'c')*/ \ + 0xFF, 0xFB, 0x7F, 0xC0, 0x3F, 0xC0, 0x1F, 0xFF, 0x1F, 0xFF, 0x9F, 0xFF, 0x9F, 0xFF, 0x9F, 0xFF, 0x03, 0xF0, 0x03, 0xF0, \ + 0x9F, 0xFF, 0x9F, 0xFF, 0x9F, 0xFF, 0x9F, 0xFF, 0x9F, 0xFF, 0x9F, 0xFF, 0x9F, 0xFF, 0x9F, 0xFF, 0x9F, 0xFF, 0x9F, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* Character 0x66 (102: 'f')*/ \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0xFF, 0xDD, 0xFF, 0xDD, 0xFF, 0xDD, 0xFF, 0xE3, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* Character 0x20 (32: 'degree')*/ diff --git a/examples/thermostat/efr32/include/ThermostatUI.h b/examples/thermostat/efr32/include/ThermostatUI.h new file mode 100644 index 00000000000000..671bbf8605952b --- /dev/null +++ b/examples/thermostat/efr32/include/ThermostatUI.h @@ -0,0 +1,52 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * All rights reserved. + * + * 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 "ThermostatIcons.h" +#include "glib.h" +#include "lcd.h" + +class ThermostatUI +{ + +public: + // AppCluster Spec Table 85. + enum HVACMode + { + MODE_OFF = 0, + HEATING_COOLING, + NOT_USED, + COOLING, + HEATING, + }; + + static void DrawUI(GLIB_Context_t * glibContext); + static void SetHeatingSetPoint(int8_t temp); + static void SetCoolingSetPoint(int8_t temp); + static void SetCurrentTemp(int8_t temp); + static void SetMode(uint8_t mode); + +private: + static void DrawHeader(GLIB_Context_t * glibContext); + static void DrawFooter(GLIB_Context_t * glibContext, bool autoMode = true); + static void DrawCurrentTemp(GLIB_Context_t * glibContext, int8_t temp, bool isCelsius = true); + static void DrawFont(GLIB_Context_t * glibContext, uint8_t initial_x, uint8_t initial_y, uint8_t width, uint8_t * data, + uint32_t size); + static void DrawSetPoint(GLIB_Context_t * glibContext, int8_t setPoint, bool secondLine); +}; diff --git a/examples/thermostat/efr32/src/AppTask.cpp b/examples/thermostat/efr32/src/AppTask.cpp index 37ab028045fe35..64af0859e887c3 100644 --- a/examples/thermostat/efr32/src/AppTask.cpp +++ b/examples/thermostat/efr32/src/AppTask.cpp @@ -31,6 +31,7 @@ #endif // ENABLE_WSTK_LEDS #ifdef DISPLAY_ENABLED +#include "ThermostatUI.h" #include "lcd.h" #ifdef QR_CODE_ENABLED #include "qrcodegen.h" @@ -39,7 +40,13 @@ #include #include +#include +#include #include +#include +#include +#include +#include #include #include #include @@ -56,7 +63,10 @@ #define APP_FUNCTION_BUTTON &sl_button_btn0 #define APP_THERMOSTAT &sl_button_btn1 +#define MODE_TIMER 1000 // 1s timer period + using namespace chip; +using namespace chip::TLV; using namespace ::chip::DeviceLayer; /********************************************************** @@ -129,9 +139,6 @@ Identify gIdentify = { } // namespace -using namespace chip::TLV; -using namespace ::chip::DeviceLayer; - /********************************************************** * AppTask Definitions *********************************************************/ @@ -144,6 +151,7 @@ CHIP_ERROR AppTask::Init() #ifdef DISPLAY_ENABLED GetLCD().Init((uint8_t *) "Thermostat-App"); + GetLCD().SetCustomUI(ThermostatUI::DrawUI); #endif err = BaseApplication::Init(&gIdentify); @@ -152,6 +160,18 @@ CHIP_ERROR AppTask::Init() EFR32_LOG("BaseApplication::Init() failed"); appError(err); } + err = SensorMgr().Init(); + if (err != CHIP_NO_ERROR) + { + EFR32_LOG("SensorMgr::Init() failed"); + appError(err); + } + err = TempMgr().Init(); + if (err != CHIP_NO_ERROR) + { + EFR32_LOG("TempMgr::Init() failed"); + appError(err); + } return err; } @@ -207,34 +227,42 @@ void AppTask::OnIdentifyStop(Identify * identify) #endif } -void AppTask::ThermostatActionEventHandler(AppEvent * aEvent) +void AppTask::UpdateThermoStatUI() { - if (aEvent->Type == AppEvent::kEventType_Button) +#ifdef DISPLAY_ENABLED + ThermostatUI::SetMode(TempMgr().GetMode()); + ThermostatUI::SetHeatingSetPoint(TempMgr().GetHeatingSetPoint()); + ThermostatUI::SetCoolingSetPoint(TempMgr().GetCoolingSetPoint()); + ThermostatUI::SetCurrentTemp(TempMgr().GetCurrentTemp()); + +#ifdef SL_WIFI + if (ConnectivityMgr().IsWiFiStationProvisioned()) +#else + if (ConnectivityMgr().IsThreadProvisioned()) +#endif /* !SL_WIFI */ { - EFR32_LOG("App Button was pressed!"); - // TODO: Implement button functionnality + AppTask::GetAppTask().GetLCD().WriteDemoUI(false); // State doesn't Matter } +#else + EFR32_LOG("Thermostat Status - M:%d T:%d'C H:%d'C C:%d'C", TempMgr().GetMode(), TempMgr().GetCurrentTemp(), + TempMgr().GetHeatingSetPoint(), TempMgr().GetCoolingSetPoint()); +#endif // DISPLAY_ENABLED } void AppTask::ButtonEventHandler(const sl_button_t * buttonHandle, uint8_t btnAction) { - if (buttonHandle == NULL) + if (buttonHandle == nullptr) { return; } - AppEvent button_event = {}; - button_event.Type = AppEvent::kEventType_Button; - button_event.ButtonEvent.Action = btnAction; + AppEvent aEvent = {}; + aEvent.Type = AppEvent::kEventType_Button; + aEvent.ButtonEvent.Action = btnAction; - if (buttonHandle == APP_THERMOSTAT && btnAction == SL_SIMPLE_BUTTON_PRESSED) - { - button_event.Handler = ThermostatActionEventHandler; - sAppTask.PostEvent(&button_event); - } - else if (buttonHandle == APP_FUNCTION_BUTTON) + if (buttonHandle == APP_FUNCTION_BUTTON) { - button_event.Handler = BaseApplication::ButtonHandler; - sAppTask.PostEvent(&button_event); + aEvent.Handler = BaseApplication::ButtonHandler; + sAppTask.PostEvent(&aEvent); } } diff --git a/examples/thermostat/efr32/src/SensorManager.cpp b/examples/thermostat/efr32/src/SensorManager.cpp new file mode 100644 index 00000000000000..4a60846fae950c --- /dev/null +++ b/examples/thermostat/efr32/src/SensorManager.cpp @@ -0,0 +1,133 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * 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. + */ + +/********************************************************** + * Includes + *********************************************************/ + +#include "SensorManager.h" +#include "AppConfig.h" +#include "AppEvent.h" +#include "AppTask.h" + +#ifdef USE_TEMP_SENSOR +#include "TemperatureSensor.h" +#endif +/********************************************************** + * Defines and Constants + *********************************************************/ + +using namespace chip; +using namespace ::chip::DeviceLayer; + +constexpr EndpointId kThermostatEndpoint = 1; +constexpr uint16_t kSensorTImerPeriodMs = 30000; // 30s timer period +constexpr uint16_t kMinTemperatureDelta = 50; // 0.5 degree Celcius + +/********************************************************** + * Variable declarations + *********************************************************/ + +TimerHandle_t sSensorTimer; +StaticTimer_t sStaticSensorTimerStruct; + +SensorManager SensorManager::sSensorManager; + +#ifndef USE_TEMP_SENSOR +constexpr uint16_t kSimulatedReadingFrequency = (60000 / kSensorTImerPeriodMs); // Change Simulated number at each minutes +static int16_t mSimulatedTemp[] = { 2300, 2400, 2800, 2550, 2200, 2125, 2100, 2600, 1800, 2700 }; +#endif + +CHIP_ERROR SensorManager::Init() +{ + // Create FreeRTOS sw timer for temp sensor timer. + sSensorTimer = xTimerCreateStatic("sensorTmr", pdMS_TO_TICKS(kSensorTImerPeriodMs), true, nullptr, SensorTimerEventHandler, + &sStaticSensorTimerStruct); + + if (sSensorTimer == NULL) + { + EFR32_LOG("sSensorTimer timer create failed"); + return APP_ERROR_CREATE_TIMER_FAILED; + } + +#ifdef USE_TEMP_SENSOR + if (SL_STATUS_OK != TemperatureSensor::Init()) + { + EFR32_LOG("Failed to Init Sensor"); + return CHIP_ERROR_INTERNAL; + } +#endif + + // Update Temp immediatly at bootup + SensorTimerEventHandler(sSensorTimer); + + // Trigger periodic update + xTimerStart(sSensorTimer, portMAX_DELAY); + + return CHIP_NO_ERROR; +} + +void SensorManager::SensorTimerEventHandler(TimerHandle_t xTimer) +{ + int16_t temperature = 0; + static int16_t lastTemperature = 0; + +#ifdef USE_TEMP_SENSOR + int32_t tempSum = 0; + uint32_t humidity = 0; + + for (uint8_t i = 0; i < 100; i++) + { + if (SL_STATUS_OK != TemperatureSensor::GetTemp(&humidity, &temperature)) + { + EFR32_LOG("Failed to read Temperature !!!"); + } + tempSum += temperature; + } + temperature = static_cast(tempSum / 100); +#else + static uint8_t nbOfRepetition = 0; + static uint8_t simulatedIndex = 0; + if (simulatedIndex >= sizeof(mSimulatedTemp)) + { + simulatedIndex = 0; + } + temperature = mSimulatedTemp[simulatedIndex]; + + nbOfRepetition++; + if (nbOfRepetition >= kSimulatedReadingFrequency) + { + simulatedIndex++; + nbOfRepetition = 0; + } +#endif // USE_TEMP_SENSOR + + EFR32_LOG("Sensor Temp is : %d", temperature); + + if ((temperature >= (lastTemperature + kMinTemperatureDelta)) || temperature <= (lastTemperature - kMinTemperatureDelta)) + { + lastTemperature = temperature; + PlatformMgr().LockChipStack(); + // The SensorMagager shouldn't be aware of the Endpoint ID TODO Fix this. + // TODO Per Spec we should also apply the Offset stored in the same cluster before saving the temp + + app::Clusters::Thermostat::Attributes::LocalTemperature::Set(kThermostatEndpoint, temperature); + PlatformMgr().UnlockChipStack(); + } +} diff --git a/examples/thermostat/efr32/src/TemperatureManager.cpp b/examples/thermostat/efr32/src/TemperatureManager.cpp new file mode 100644 index 00000000000000..8b0d6c7f8413cc --- /dev/null +++ b/examples/thermostat/efr32/src/TemperatureManager.cpp @@ -0,0 +1,149 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * 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. + */ + +/********************************************************** + * Includes + *********************************************************/ + +#include "TemperatureManager.h" +#include "AppConfig.h" +#include "AppEvent.h" +#include "AppTask.h" +#include "semphr.h" + +/********************************************************** + * Defines and Constants + *********************************************************/ + +using namespace chip; +using namespace ::chip::DeviceLayer; + +constexpr EndpointId kThermostatEndpoint = 1; + +namespace ThermAttr = chip::app::Clusters::Thermostat::Attributes; +/********************************************************** + * Variable declarations + *********************************************************/ + +TemperatureManager TemperatureManager::sTempMgr; + +CHIP_ERROR TemperatureManager::Init() +{ + app::DataModel::Nullable temp; + int16_t heatingSetpoint, coolingSetpoint; + uint8_t systemMode; + + PlatformMgr().LockChipStack(); + ThermAttr::LocalTemperature::Get(kThermostatEndpoint, temp); + ThermAttr::OccupiedCoolingSetpoint::Get(kThermostatEndpoint, &coolingSetpoint); + ThermAttr::OccupiedHeatingSetpoint::Get(kThermostatEndpoint, &heatingSetpoint); + ThermAttr::SystemMode::Get(kThermostatEndpoint, &systemMode); + PlatformMgr().UnlockChipStack(); + + mCurrentTempCelsius = ConvertToPrintableTemp(temp.Value()); + mHeatingCelsiusSetPoint = ConvertToPrintableTemp(coolingSetpoint); + mCoolingCelsiusSetPoint = ConvertToPrintableTemp(heatingSetpoint); + mThermMode = systemMode; + + AppTask::GetAppTask().UpdateThermoStatUI(); + + return CHIP_NO_ERROR; +} + +int8_t TemperatureManager::ConvertToPrintableTemp(int16_t temperature) +{ + constexpr uint8_t kRoundUpValue = 50; + + // Round up the temperature as we won't print decimals on LCD + // Is it a negative temperature + if (temperature < 0) + { + temperature -= kRoundUpValue; + } + else + { + temperature += kRoundUpValue; + } + + return static_cast(temperature / 100); +} + +void TemperatureManager::AttributeChangeHandler(EndpointId endpointId, AttributeId attributeId, uint8_t * value, uint16_t size) +{ + switch (attributeId) + { + case ThermAttr::LocalTemperature::Id: { + int8_t Temp = ConvertToPrintableTemp(*((int16_t *) value)); + EFR32_LOG("Local temp %d", Temp); + mCurrentTempCelsius = Temp; + } + break; + + case ThermAttr::OccupiedCoolingSetpoint::Id: { + int8_t coolingTemp = ConvertToPrintableTemp(*((int16_t *) value)); + EFR32_LOG("CoolingSetpoint %d", coolingTemp); + mCoolingCelsiusSetPoint = coolingTemp; + } + break; + + case ThermAttr::OccupiedHeatingSetpoint::Id: { + int8_t heatingTemp = ConvertToPrintableTemp(*((int16_t *) value)); + EFR32_LOG("HeatingSetpoint %d", heatingTemp); + mHeatingCelsiusSetPoint = heatingTemp; + } + break; + + case ThermAttr::SystemMode::Id: { + EFR32_LOG("SystemMode %d", static_cast(*value)); + uint8_t mode = static_cast(*value); + if (mThermMode != mode) + { + mThermMode = mode; + } + } + break; + + default: { + EFR32_LOG("Unhandled thermostat attribute %x", attributeId); + return; + } + break; + } + + AppTask::GetAppTask().UpdateThermoStatUI(); +} + +uint8_t TemperatureManager::GetMode() +{ + return mThermMode; +} + +int8_t TemperatureManager::GetCurrentTemp() +{ + return mCurrentTempCelsius; +} +int8_t TemperatureManager::GetHeatingSetPoint() +{ + return mHeatingCelsiusSetPoint; +} + +int8_t TemperatureManager::GetCoolingSetPoint() +{ + return mCoolingCelsiusSetPoint; +} diff --git a/examples/thermostat/efr32/src/ThermostatUI.cpp b/examples/thermostat/efr32/src/ThermostatUI.cpp new file mode 100644 index 00000000000000..9336d356770d48 --- /dev/null +++ b/examples/thermostat/efr32/src/ThermostatUI.cpp @@ -0,0 +1,255 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * All rights reserved. + * + * 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. + */ + +#include +#include + +#include "ThermostatUI.h" +#include "demo-ui-bitmaps.h" +#include "dmd.h" +#include "glib.h" +#include "lcd.h" + +// LCD line define +constexpr uint8_t kTempLcdInitialX = 30; + +// Bitmap +static const uint8_t silabsLogo[] = { SILABS_LOGO_SMALL }; +static const uint8_t matterLogoBitmap[] = { MATTER_LOGO_BITMAP }; + +static const uint8_t wifiLogo[] = { WIFI_BITMAP }; +static const uint8_t threadLogo[] = { THREAD_BITMAP }; +static const uint8_t bleLogo[] = { BLUETOOTH_ICON_SMALL }; + +static const unsigned char monaco_48pt[] = { MONACO_48PT }; +static const unsigned char heating_bits[] = { HEATING_BITMAP }; +static const unsigned char cooling_bits[] = { COOLING_BITMAP }; +static const unsigned char heating_cooling_bits[] = { HEATING_COOLING_BITMAP }; + +static int8_t mHeatingCelsiusSetPoint; +static int8_t mCoolingCelsiusSetPoint; +static int8_t mCurrentTempCelsius; +static uint8_t mMode; + +#ifdef SL_WIFI +#define UI_WIFI 1 +#else +#define UI_WIFI 0 +#endif + +void ThermostatUI::DrawUI(GLIB_Context_t * glibContext) +{ + if (glibContext == nullptr) + { + EFR32_LOG("Context is null"); + return; + } + + GLIB_clear(glibContext); + DrawHeader(glibContext); + DrawCurrentTemp(glibContext, mCurrentTempCelsius); + DrawFooter(glibContext, false); + + DMD_updateDisplay(); +} + +void ThermostatUI::SetHeatingSetPoint(int8_t temp) +{ + mHeatingCelsiusSetPoint = temp; +} + +void ThermostatUI::SetCoolingSetPoint(int8_t temp) +{ + mCoolingCelsiusSetPoint = temp; +} + +void ThermostatUI::SetCurrentTemp(int8_t temp) +{ + mCurrentTempCelsius = temp; +} +void ThermostatUI::SetMode(uint8_t mode) +{ + mMode = mode; +} + +void ThermostatUI::DrawHeader(GLIB_Context_t * glibContext) +{ + // Draw Silabs Corner icon + GLIB_drawBitmap(glibContext, SILABS_ICON_POSITION_X, STATUS_ICON_LINE, SILABS_LOGO_WIDTH, SILABS_LOGO_HEIGHT, silabsLogo); + // Draw BLE Icon + GLIB_drawBitmap(glibContext, BLE_ICON_POSITION_X, STATUS_ICON_LINE, BLUETOOTH_ICON_SIZE, BLUETOOTH_ICON_SIZE, bleLogo); + // Draw WiFi/OpenThread Icon + GLIB_drawBitmap(glibContext, NETWORK_ICON_POSITION_X, STATUS_ICON_LINE, (UI_WIFI) ? WIFI_BITMAP_HEIGHT : THREAD_BITMAP_WIDTH, + WIFI_BITMAP_HEIGHT, (UI_WIFI) ? wifiLogo : threadLogo); + // Draw Matter Icon + GLIB_drawBitmap(glibContext, MATTER_ICON_POSITION_X, STATUS_ICON_LINE, MATTER_LOGO_WIDTH, MATTER_LOGO_HEIGHT, matterLogoBitmap); + DMD_updateDisplay(); +} + +void ThermostatUI::DrawFooter(GLIB_Context_t * glibContext, bool autoMode) +{ + switch (static_cast(mMode)) + { + case HVACMode::HEATING: + GLIB_drawStringOnLine(glibContext, "Mode : Heating", 11, GLIB_ALIGN_LEFT, 0, 0, true); + GLIB_drawBitmap(glibContext, HEATING_COOLING_X, HEATING_COOLING_Y, COOLING_WIDTH, COOLING_HEIGHT, heating_bits); + DrawSetPoint(glibContext, mHeatingCelsiusSetPoint, false); + break; + case HVACMode::COOLING: + GLIB_drawStringOnLine(glibContext, "Mode : Cooling", 11, GLIB_ALIGN_LEFT, 0, 0, true); + GLIB_drawBitmap(glibContext, HEATING_COOLING_X, HEATING_COOLING_Y, COOLING_WIDTH, COOLING_HEIGHT, cooling_bits); + DrawSetPoint(glibContext, mCoolingCelsiusSetPoint, false); + break; + case HVACMode::HEATING_COOLING: + GLIB_drawStringOnLine(glibContext, "Mode : Auto", 11, GLIB_ALIGN_LEFT, 0, 0, true); + GLIB_drawBitmap(glibContext, HEATING_COOLING_X, HEATING_COOLING_Y, COOLING_WIDTH, COOLING_HEIGHT, heating_cooling_bits); + DrawSetPoint(glibContext, mHeatingCelsiusSetPoint, false); + DrawSetPoint(glibContext, mCoolingCelsiusSetPoint, true); + break; + case HVACMode::MODE_OFF: + DrawSetPoint(glibContext, 0, false); + GLIB_drawStringOnLine(glibContext, "Mode : OFF", 11, GLIB_ALIGN_LEFT, 0, 0, true); + break; + default: + break; + } + + DMD_updateDisplay(); +} + +/** + * @brief Draw a 2 digit Temp of screen. Because of this Celsius is used by default + * @param GLIB_Context_t * pointer to the context for the GLIB library + * @param int8_t current Temperature in Celsius + * @param int8_t setPoint in Celsius + * @param bool isCelsius By default set to True. For future development + */ +void ThermostatUI::DrawCurrentTemp(GLIB_Context_t * glibContext, int8_t temp, bool isCelsius) +{ + uint8_t tempArray[2]; + uint8_t position_x = 10; + uint8_t * data; + + if (temp > 99 || temp < -99) + { + // Invalid temp for a house thermostat + return; + } + + if (temp < 0) + { + for (uint8_t y = 60; y < 64; y++) + { + for (uint8_t x = 1; x < 10; x++) + { + GLIB_drawPixel(glibContext, x, y); + } + } + + temp = temp * -1; + } + + // Draw Unit + if (isCelsius) + { + data = (uint8_t *) &monaco_48pt[DEGREE_INDEX]; + DrawFont(glibContext, 65, kTempLcdInitialX, 15, data, MONACO_FONT_CH_LENGTH); + data = (uint8_t *) &monaco_48pt[CELSIUS_INDEX]; + DrawFont(glibContext, 70, kTempLcdInitialX, 15, data, MONACO_FONT_CH_LENGTH); + } + else + { + data = (uint8_t *) &monaco_48pt[DEGREE_INDEX]; + DrawFont(glibContext, 65, 25, 15, data, MONACO_FONT_CH_LENGTH); // 25 to fit with f of fahrenheint + data = (uint8_t *) &monaco_48pt[FAHRENHEIT_INDEX]; + DrawFont(glibContext, 70, kTempLcdInitialX, 15, data, MONACO_FONT_CH_LENGTH); + } + + // Print Current temp + tempArray[0] = (uint8_t)((temp / 10)); + tempArray[1] = (uint8_t)((temp % 10)); + + for (uint8_t ch = 0; ch < 2; ch++) + { + data = (uint8_t *) &monaco_48pt[tempArray[ch] * MONACO_FONT_NB_LENGTH]; + DrawFont(glibContext, position_x, kTempLcdInitialX, MONACO_FONT_WIDTH, data, MONACO_FONT_NB_LENGTH); + position_x += MONACO_FONT_WIDTH; + } +} + +void ThermostatUI::DrawFont(GLIB_Context_t * glibContext, uint8_t initial_x, uint8_t initial_y, uint8_t width, uint8_t * data, + uint32_t size) +{ + uint8_t x = initial_x, y = initial_y; + for (uint16_t i = 0; i < size; i++) + { + for (uint8_t mask = 0; mask < 8; mask++) + { + if (!(data[i] & (0x01 << mask))) + { + GLIB_drawPixel(glibContext, x, y); + } + // Check line changes + if (((x - initial_x) % width) == 0 && x != initial_x) + { + x = initial_x; + y++; + // Font is 8 bit align with paddings bits; + mask = 8; + } + else + { + x++; + } + } + } +} + +void ThermostatUI::DrawSetPoint(GLIB_Context_t * glibContext, int8_t setPoint, bool secondLine) +{ + char setPointLine[] = { '-', 'X', 'X', '\0' }; + + if (setPoint > 99 || setPoint < -99) + { + return; + } + + // Update SetPoint string + if (static_cast(mMode) == ThermostatUI::HVACMode::MODE_OFF) + { + setPointLine[0] = '-'; + setPointLine[1] = '-'; + setPointLine[2] = '\0'; + } + else if (setPoint < 0) + { + setPointLine[0] = (setPoint < 0) ? '-' : ' '; + setPoint *= -1; + setPointLine[1] = ((setPoint / 10) + 0x30); + setPointLine[2] = ((setPoint % 10) + 0x30); + } + else + { + setPointLine[0] = ((setPoint / 10) + 0x30); + setPointLine[1] = ((setPoint % 10) + 0x30); + setPointLine[2] = '\0'; + } + + // Print SetPoint + GLIB_drawStringOnLine(glibContext, setPointLine, (secondLine) ? 8 : 7, GLIB_ALIGN_LEFT, 67, 0, true); +} diff --git a/examples/thermostat/efr32/src/ZclCallbacks.cpp b/examples/thermostat/efr32/src/ZclCallbacks.cpp index f89d4aaa8cd581..734637d91be401 100644 --- a/examples/thermostat/efr32/src/ZclCallbacks.cpp +++ b/examples/thermostat/efr32/src/ZclCallbacks.cpp @@ -22,6 +22,7 @@ #include "AppConfig.h" +#include "TemperatureManager.h" #include #include #include @@ -42,24 +43,8 @@ void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & ChipLogProgress(Zcl, "Identify attribute ID: " ChipLogFormatMEI " Type: %u Value: %u, length %u", ChipLogValueMEI(attributeId), type, *value, size); } -} - -/** @brief OnOff Cluster Init - * - * This function is called when a specific cluster is initialized. It gives the - * application an opportunity to take care of cluster initialization procedures. - * It is called exactly once for each endpoint where cluster is present. - * - * @param endpoint Ver.: always - * - * TODO Issue #3841 - * emberAfOnOffClusterInitCallback happens before the stack initialize the cluster - * attributes to the default value. - * The logic here expects something similar to the deprecated Plugins callback - * emberAfPluginOnOffClusterServerPostInitCallback. - * - */ -void emberAfOnOffClusterInitCallback(EndpointId endpoint) -{ - // TODO: implement any additional Cluster Server init actions + else if (clusterId == Thermostat::Id) + { + TempMgr().AttributeChangeHandler(attributePath.mEndpointId, attributeId, value, size); + } } diff --git a/examples/thermostat/thermostat-common/thermostat.matter b/examples/thermostat/thermostat-common/thermostat.matter index 9b104b990f3159..15933ed93c52d3 100644 --- a/examples/thermostat/thermostat-common/thermostat.matter +++ b/examples/thermostat/thermostat-common/thermostat.matter @@ -1436,6 +1436,16 @@ server cluster Thermostat = 513 { command SetpointRaiseLower(SetpointRaiseLowerRequest): DefaultSuccess = 0; } +server cluster ThermostatUserInterfaceConfiguration = 516 { + attribute enum8 temperatureDisplayMode = 0; + attribute access(write: manage) enum8 keypadLockout = 1; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; +} + endpoint 0 { device type rootdevice = 22; binding cluster OtaSoftwareUpdateProvider; @@ -1743,29 +1753,13 @@ endpoint 1 { ram attribute clusterRevision default = 4; } - server cluster Basic { - callback attribute dataModelRevision default = 10; - callback attribute vendorName; - callback attribute vendorID; - callback attribute productName; - callback attribute productID; - persist attribute nodeLabel; - callback attribute location default = "XX"; - callback attribute hardwareVersion; - callback attribute hardwareVersionString; - callback attribute softwareVersion; - callback attribute softwareVersionString; - callback attribute manufacturingDate default = "20210614123456ZZ"; - callback attribute partNumber; - callback attribute productURL; - callback attribute productLabel; - callback attribute serialNumber; - persist attribute localConfigDisabled; - ram attribute reachable default = 1; - callback attribute uniqueID; - callback attribute capabilityMinima; + server cluster Descriptor { + callback attribute deviceTypeList; + callback attribute serverList; + callback attribute clientList; + callback attribute partsList; ram attribute featureMap; - ram attribute clusterRevision default = 1; + callback attribute clusterRevision default = 1; } server cluster Thermostat { @@ -1774,21 +1768,31 @@ endpoint 1 { ram attribute absMaxHeatSetpointLimit default = 3000; ram attribute absMinCoolSetpointLimit default = 1600; ram attribute absMaxCoolSetpointLimit default = 3200; - ram attribute occupiedCoolingSetpoint default = 0x0A28; - ram attribute occupiedHeatingSetpoint default = 0x07D0; + persist attribute occupiedCoolingSetpoint default = 0x0A28; + persist attribute occupiedHeatingSetpoint default = 0x07D0; ram attribute minHeatSetpointLimit default = 700; ram attribute maxHeatSetpointLimit default = 3000; ram attribute minCoolSetpointLimit default = 1600; ram attribute maxCoolSetpointLimit default = 3200; ram attribute minSetpointDeadBand default = 0x19; ram attribute controlSequenceOfOperation default = 0x04; - ram attribute systemMode default = 0x01; + persist attribute systemMode default = 0x01; callback attribute generatedCommandList; callback attribute acceptedCommandList; callback attribute attributeList; ram attribute featureMap default = 0x23; ram attribute clusterRevision default = 5; } + + server cluster ThermostatUserInterfaceConfiguration { + ram attribute temperatureDisplayMode; + ram attribute keypadLockout; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + ram attribute featureMap; + ram attribute clusterRevision default = 1; + } } diff --git a/examples/thermostat/thermostat-common/thermostat.zap b/examples/thermostat/thermostat-common/thermostat.zap index 601a871112cf16..ca91d4a2332a90 100644 --- a/examples/thermostat/thermostat-common/thermostat.zap +++ b/examples/thermostat/thermostat-common/thermostat.zap @@ -1,5 +1,5 @@ { - "featureLevel": 81, + "featureLevel": 85, "creator": "zap", "keyValuePairs": [ { @@ -8592,7 +8592,7 @@ "mfgCode": null, "define": "DESCRIPTOR_CLUSTER", "side": "server", - "enabled": 0, + "enabled": 1, "attributes": [ { "name": "DeviceTypeList", @@ -8658,6 +8658,22 @@ "maxInterval": 65344, "reportableChange": 0 }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, { "name": "ClusterRevision", "code": 65533, @@ -8776,7 +8792,7 @@ "mfgCode": null, "define": "BASIC_CLUSTER", "side": "server", - "enabled": 1, + "enabled": 0, "attributes": [ { "name": "DataModelRevision", @@ -11119,7 +11135,7 @@ "side": "server", "type": "int16s", "included": 1, - "storageOption": "RAM", + "storageOption": "NVM", "singleton": 0, "bounded": 0, "defaultValue": "0x0A28", @@ -11135,7 +11151,7 @@ "side": "server", "type": "int16s", "included": 1, - "storageOption": "RAM", + "storageOption": "NVM", "singleton": 0, "bounded": 0, "defaultValue": "0x07D0", @@ -11247,7 +11263,7 @@ "side": "server", "type": "enum8", "included": 1, - "storageOption": "RAM", + "storageOption": "NVM", "singleton": 0, "bounded": 0, "defaultValue": "0x01", @@ -11386,6 +11402,186 @@ } ] }, + { + "name": "Thermostat User Interface Configuration", + "code": 516, + "mfgCode": null, + "define": "THERMOSTAT_USER_INTERFACE_CONFIGURATION_CLUSTER", + "side": "client", + "enabled": 0, + "attributes": [ + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "client", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Thermostat User Interface Configuration", + "code": 516, + "mfgCode": null, + "define": "THERMOSTAT_USER_INTERFACE_CONFIGURATION_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "temperature display mode", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "enum8", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "keypad lockout", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "enum8", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "schedule programming visibility", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "enum8", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, { "name": "Color Control", "code": 768, @@ -14354,5 +14550,6 @@ "endpointVersion": 1, "deviceIdentifier": 769 } - ] + ], + "log": [] } \ No newline at end of file diff --git a/zzz_generated/thermostat/zap-generated/access.h b/zzz_generated/thermostat/zap-generated/access.h index 8babb2f23818a1..794789b5c57838 100644 --- a/zzz_generated/thermostat/zap-generated/access.h +++ b/zzz_generated/thermostat/zap-generated/access.h @@ -54,6 +54,7 @@ /* Cluster: Thermostat, Attribute: MinSetpointDeadBand, Privilege: view */ \ /* Cluster: Thermostat, Attribute: ControlSequenceOfOperation, Privilege: view */ \ /* Cluster: Thermostat, Attribute: SystemMode, Privilege: view */ \ + /* Cluster: Thermostat User Interface Configuration, Attribute: keypad lockout, Privilege: view */ \ } // Parallel array data (cluster, *attribute*, privilege) for read attribute @@ -83,6 +84,7 @@ /* Cluster: Thermostat, Attribute: MinSetpointDeadBand, Privilege: view */ \ /* Cluster: Thermostat, Attribute: ControlSequenceOfOperation, Privilege: view */ \ /* Cluster: Thermostat, Attribute: SystemMode, Privilege: view */ \ + /* Cluster: Thermostat User Interface Configuration, Attribute: keypad lockout, Privilege: view */ \ } // Parallel array data (cluster, attribute, *privilege*) for read attribute @@ -112,6 +114,7 @@ /* Cluster: Thermostat, Attribute: MinSetpointDeadBand, Privilege: view */ \ /* Cluster: Thermostat, Attribute: ControlSequenceOfOperation, Privilege: view */ \ /* Cluster: Thermostat, Attribute: SystemMode, Privilege: view */ \ + /* Cluster: Thermostat User Interface Configuration, Attribute: keypad lockout, Privilege: view */ \ } //////////////////////////////////////////////////////////////////////////////// @@ -134,6 +137,7 @@ 513, /* Cluster: Thermostat, Attribute: MinSetpointDeadBand, Privilege: manage */ \ 513, /* Cluster: Thermostat, Attribute: ControlSequenceOfOperation, Privilege: manage */ \ 513, /* Cluster: Thermostat, Attribute: SystemMode, Privilege: manage */ \ + 516, /* Cluster: Thermostat User Interface Configuration, Attribute: keypad lockout, Privilege: manage */ \ } // Parallel array data (cluster, *attribute*, privilege) for write attribute @@ -154,6 +158,7 @@ 25, /* Cluster: Thermostat, Attribute: MinSetpointDeadBand, Privilege: manage */ \ 27, /* Cluster: Thermostat, Attribute: ControlSequenceOfOperation, Privilege: manage */ \ 28, /* Cluster: Thermostat, Attribute: SystemMode, Privilege: manage */ \ + 1, /* Cluster: Thermostat User Interface Configuration, Attribute: keypad lockout, Privilege: manage */ \ } // Parallel array data (cluster, attribute, *privilege*) for write attribute @@ -174,6 +179,7 @@ kMatterAccessPrivilegeManage, /* Cluster: Thermostat, Attribute: MinSetpointDeadBand, Privilege: manage */ \ kMatterAccessPrivilegeManage, /* Cluster: Thermostat, Attribute: ControlSequenceOfOperation, Privilege: manage */ \ kMatterAccessPrivilegeManage, /* Cluster: Thermostat, Attribute: SystemMode, Privilege: manage */ \ + kMatterAccessPrivilegeManage, /* Cluster: Thermostat User Interface Configuration, Attribute: keypad lockout, Privilege: manage */ \ } //////////////////////////////////////////////////////////////////////////////// diff --git a/zzz_generated/thermostat/zap-generated/callback-stub.cpp b/zzz_generated/thermostat/zap-generated/callback-stub.cpp index 9e6402a1003382..d000ee8a6cd453 100644 --- a/zzz_generated/thermostat/zap-generated/callback-stub.cpp +++ b/zzz_generated/thermostat/zap-generated/callback-stub.cpp @@ -92,6 +92,9 @@ void emberAfClusterInitCallback(EndpointId endpoint, ClusterId clusterId) case ZCL_THERMOSTAT_CLUSTER_ID: emberAfThermostatClusterInitCallback(endpoint); break; + case ZCL_THERMOSTAT_USER_INTERFACE_CONFIGURATION_CLUSTER_ID: + emberAfThermostatUserInterfaceConfigurationClusterInitCallback(endpoint); + break; case ZCL_THREAD_NETWORK_DIAGNOSTICS_CLUSTER_ID: emberAfThreadNetworkDiagnosticsClusterInitCallback(endpoint); break; @@ -218,6 +221,11 @@ void __attribute__((weak)) emberAfThermostatClusterInitCallback(EndpointId endpo // To prevent warning (void) endpoint; } +void __attribute__((weak)) emberAfThermostatUserInterfaceConfigurationClusterInitCallback(EndpointId endpoint) +{ + // To prevent warning + (void) endpoint; +} void __attribute__((weak)) emberAfThreadNetworkDiagnosticsClusterInitCallback(EndpointId endpoint) { // To prevent warning diff --git a/zzz_generated/thermostat/zap-generated/endpoint_config.h b/zzz_generated/thermostat/zap-generated/endpoint_config.h index 6205237faed904..083e077e91e35a 100644 --- a/zzz_generated/thermostat/zap-generated/endpoint_config.h +++ b/zzz_generated/thermostat/zap-generated/endpoint_config.h @@ -78,7 +78,7 @@ } // This is an array of EmberAfAttributeMinMaxValue structures. -#define GENERATED_MIN_MAX_DEFAULT_COUNT 11 +#define GENERATED_MIN_MAX_DEFAULT_COUNT 13 #define GENERATED_MIN_MAX_DEFAULTS \ { \ \ @@ -97,14 +97,18 @@ { (uint16_t) 0xC80, (uint16_t) -0x6AB3, (uint16_t) 0x7FFF }, /* MaxCoolSetpointLimit */ \ { (uint16_t) 0x19, (uint16_t) 0x0, (uint16_t) 0x19 }, /* MinSetpointDeadBand */ \ { (uint16_t) 0x4, (uint16_t) 0x0, (uint16_t) 0x5 }, /* ControlSequenceOfOperation */ \ + { (uint16_t) 0x1, (uint16_t) 0x0, (uint16_t) 0x7 }, /* SystemMode */ \ + \ + /* Endpoint: 1, Cluster: Thermostat User Interface Configuration (server) */ \ + { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0x1 }, /* temperature display mode */ \ { \ - (uint16_t) 0x1, (uint16_t) 0x0, (uint16_t) 0x7 \ - } /* SystemMode */ \ + (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0x5 \ + } /* keypad lockout */ \ } #define ZAP_ATTRIBUTE_MASK(mask) ATTRIBUTE_MASK_##mask // This is an array of EmberAfAttributeMetadata structures. -#define GENERATED_ATTRIBUTE_COUNT 261 +#define GENERATED_ATTRIBUTE_COUNT 249 #define GENERATED_ATTRIBUTES \ { \ \ @@ -483,50 +487,13 @@ { 0x0000FFFC, ZAP_TYPE(BITMAP32), 4, 0, ZAP_SIMPLE_DEFAULT(0) }, /* FeatureMap */ \ { 0x0000FFFD, ZAP_TYPE(INT16U), 2, 0, ZAP_SIMPLE_DEFAULT(4) }, /* ClusterRevision */ \ \ - /* Endpoint: 1, Cluster: Basic (server) */ \ - { 0x00000000, ZAP_TYPE(INT16U), 2, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE) | ZAP_ATTRIBUTE_MASK(SINGLETON), \ - ZAP_EMPTY_DEFAULT() }, /* DataModelRevision */ \ - { 0x00000001, ZAP_TYPE(CHAR_STRING), 33, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE) | ZAP_ATTRIBUTE_MASK(SINGLETON), \ - ZAP_EMPTY_DEFAULT() }, /* VendorName */ \ - { 0x00000002, ZAP_TYPE(VENDOR_ID), 2, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE) | ZAP_ATTRIBUTE_MASK(SINGLETON), \ - ZAP_EMPTY_DEFAULT() }, /* VendorID */ \ - { 0x00000003, ZAP_TYPE(CHAR_STRING), 33, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE) | ZAP_ATTRIBUTE_MASK(SINGLETON), \ - ZAP_EMPTY_DEFAULT() }, /* ProductName */ \ - { 0x00000004, ZAP_TYPE(INT16U), 2, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE) | ZAP_ATTRIBUTE_MASK(SINGLETON), \ - ZAP_EMPTY_DEFAULT() }, /* ProductID */ \ - { 0x00000005, ZAP_TYPE(CHAR_STRING), 33, \ - ZAP_ATTRIBUTE_MASK(TOKENIZE) | ZAP_ATTRIBUTE_MASK(SINGLETON) | ZAP_ATTRIBUTE_MASK(WRITABLE), \ - ZAP_EMPTY_DEFAULT() }, /* NodeLabel */ \ - { 0x00000006, ZAP_TYPE(CHAR_STRING), 3, \ - ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE) | ZAP_ATTRIBUTE_MASK(SINGLETON) | ZAP_ATTRIBUTE_MASK(WRITABLE), \ - ZAP_EMPTY_DEFAULT() }, /* Location */ \ - { 0x00000007, ZAP_TYPE(INT16U), 2, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE) | ZAP_ATTRIBUTE_MASK(SINGLETON), \ - ZAP_EMPTY_DEFAULT() }, /* HardwareVersion */ \ - { 0x00000008, ZAP_TYPE(CHAR_STRING), 65, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE) | ZAP_ATTRIBUTE_MASK(SINGLETON), \ - ZAP_EMPTY_DEFAULT() }, /* HardwareVersionString */ \ - { 0x00000009, ZAP_TYPE(INT32U), 4, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE) | ZAP_ATTRIBUTE_MASK(SINGLETON), \ - ZAP_EMPTY_DEFAULT() }, /* SoftwareVersion */ \ - { 0x0000000A, ZAP_TYPE(CHAR_STRING), 65, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE) | ZAP_ATTRIBUTE_MASK(SINGLETON), \ - ZAP_EMPTY_DEFAULT() }, /* SoftwareVersionString */ \ - { 0x0000000B, ZAP_TYPE(CHAR_STRING), 17, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE) | ZAP_ATTRIBUTE_MASK(SINGLETON), \ - ZAP_EMPTY_DEFAULT() }, /* ManufacturingDate */ \ - { 0x0000000C, ZAP_TYPE(CHAR_STRING), 33, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE) | ZAP_ATTRIBUTE_MASK(SINGLETON), \ - ZAP_EMPTY_DEFAULT() }, /* PartNumber */ \ - { 0x0000000D, ZAP_TYPE(LONG_CHAR_STRING), 258, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE) | ZAP_ATTRIBUTE_MASK(SINGLETON), \ - ZAP_EMPTY_DEFAULT() }, /* ProductURL */ \ - { 0x0000000E, ZAP_TYPE(CHAR_STRING), 65, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE) | ZAP_ATTRIBUTE_MASK(SINGLETON), \ - ZAP_EMPTY_DEFAULT() }, /* ProductLabel */ \ - { 0x0000000F, ZAP_TYPE(CHAR_STRING), 33, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE) | ZAP_ATTRIBUTE_MASK(SINGLETON), \ - ZAP_EMPTY_DEFAULT() }, /* SerialNumber */ \ - { 0x00000010, ZAP_TYPE(BOOLEAN), 1, \ - ZAP_ATTRIBUTE_MASK(TOKENIZE) | ZAP_ATTRIBUTE_MASK(SINGLETON) | ZAP_ATTRIBUTE_MASK(WRITABLE), \ - ZAP_SIMPLE_DEFAULT(0) }, /* LocalConfigDisabled */ \ - { 0x00000011, ZAP_TYPE(BOOLEAN), 1, ZAP_ATTRIBUTE_MASK(SINGLETON), ZAP_SIMPLE_DEFAULT(1) }, /* Reachable */ \ - { 0x00000012, ZAP_TYPE(CHAR_STRING), 33, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE) | ZAP_ATTRIBUTE_MASK(SINGLETON), \ - ZAP_EMPTY_DEFAULT() }, /* UniqueID */ \ - { 0x00000013, ZAP_TYPE(STRUCT), 0, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE), ZAP_EMPTY_DEFAULT() }, /* CapabilityMinima */ \ + /* Endpoint: 1, Cluster: Descriptor (server) */ \ + { 0x00000000, ZAP_TYPE(ARRAY), 0, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE), ZAP_EMPTY_DEFAULT() }, /* DeviceTypeList */ \ + { 0x00000001, ZAP_TYPE(ARRAY), 0, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE), ZAP_EMPTY_DEFAULT() }, /* ServerList */ \ + { 0x00000002, ZAP_TYPE(ARRAY), 0, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE), ZAP_EMPTY_DEFAULT() }, /* ClientList */ \ + { 0x00000003, ZAP_TYPE(ARRAY), 0, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE), ZAP_EMPTY_DEFAULT() }, /* PartsList */ \ { 0x0000FFFC, ZAP_TYPE(BITMAP32), 4, 0, ZAP_SIMPLE_DEFAULT(0) }, /* FeatureMap */ \ - { 0x0000FFFD, ZAP_TYPE(INT16U), 2, ZAP_ATTRIBUTE_MASK(SINGLETON), ZAP_SIMPLE_DEFAULT(1) }, /* ClusterRevision */ \ + { 0x0000FFFD, ZAP_TYPE(INT16U), 2, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE), ZAP_EMPTY_DEFAULT() }, /* ClusterRevision */ \ \ /* Endpoint: 1, Cluster: Thermostat (server) */ \ { 0x00000000, ZAP_TYPE(INT16S), 2, ZAP_ATTRIBUTE_MASK(NULLABLE), ZAP_EMPTY_DEFAULT() }, /* LocalTemperature */ \ @@ -534,9 +501,11 @@ { 0x00000004, ZAP_TYPE(INT16S), 2, 0, ZAP_SIMPLE_DEFAULT(3000) }, /* AbsMaxHeatSetpointLimit */ \ { 0x00000005, ZAP_TYPE(INT16S), 2, 0, ZAP_SIMPLE_DEFAULT(1600) }, /* AbsMinCoolSetpointLimit */ \ { 0x00000006, ZAP_TYPE(INT16S), 2, 0, ZAP_SIMPLE_DEFAULT(3200) }, /* AbsMaxCoolSetpointLimit */ \ - { 0x00000011, ZAP_TYPE(INT16S), 2, ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE), \ + { 0x00000011, ZAP_TYPE(INT16S), 2, \ + ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(TOKENIZE) | ZAP_ATTRIBUTE_MASK(WRITABLE), \ ZAP_MIN_MAX_DEFAULTS_INDEX(2) }, /* OccupiedCoolingSetpoint */ \ - { 0x00000012, ZAP_TYPE(INT16S), 2, ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE), \ + { 0x00000012, ZAP_TYPE(INT16S), 2, \ + ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(TOKENIZE) | ZAP_ATTRIBUTE_MASK(WRITABLE), \ ZAP_MIN_MAX_DEFAULTS_INDEX(3) }, /* OccupiedHeatingSetpoint */ \ { 0x00000015, ZAP_TYPE(INT16S), 2, ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE), \ ZAP_MIN_MAX_DEFAULTS_INDEX(4) }, /* MinHeatSetpointLimit */ \ @@ -550,10 +519,19 @@ ZAP_MIN_MAX_DEFAULTS_INDEX(8) }, /* MinSetpointDeadBand */ \ { 0x0000001B, ZAP_TYPE(ENUM8), 1, ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE), \ ZAP_MIN_MAX_DEFAULTS_INDEX(9) }, /* ControlSequenceOfOperation */ \ - { 0x0000001C, ZAP_TYPE(ENUM8), 1, ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE), \ + { 0x0000001C, ZAP_TYPE(ENUM8), 1, \ + ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(TOKENIZE) | ZAP_ATTRIBUTE_MASK(WRITABLE), \ ZAP_MIN_MAX_DEFAULTS_INDEX(10) }, /* SystemMode */ \ { 0x0000FFFC, ZAP_TYPE(BITMAP32), 4, 0, ZAP_SIMPLE_DEFAULT(0x23) }, /* FeatureMap */ \ { 0x0000FFFD, ZAP_TYPE(INT16U), 2, 0, ZAP_SIMPLE_DEFAULT(5) }, /* ClusterRevision */ \ + \ + /* Endpoint: 1, Cluster: Thermostat User Interface Configuration (server) */ \ + { 0x00000000, ZAP_TYPE(ENUM8), 1, ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE), \ + ZAP_MIN_MAX_DEFAULTS_INDEX(11) }, /* temperature display mode */ \ + { 0x00000001, ZAP_TYPE(ENUM8), 1, ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE), \ + ZAP_MIN_MAX_DEFAULTS_INDEX(12) }, /* keypad lockout */ \ + { 0x0000FFFC, ZAP_TYPE(BITMAP32), 4, 0, ZAP_SIMPLE_DEFAULT(0) }, /* FeatureMap */ \ + { 0x0000FFFD, ZAP_TYPE(INT16U), 2, 0, ZAP_SIMPLE_DEFAULT(1) }, /* ClusterRevision */ \ } // This is an array of EmberAfCluster structures. @@ -587,6 +565,9 @@ const EmberAfGenericClusterFunction chipFuncArrayThermostatServer[] = { \ (EmberAfGenericClusterFunction) emberAfThermostatClusterServerInitCallback, \ (EmberAfGenericClusterFunction) MatterThermostatClusterServerPreAttributeChangedCallback, \ + }; \ + const EmberAfGenericClusterFunction chipFuncArrayThermostatUserInterfaceConfigurationServer[] = { \ + (EmberAfGenericClusterFunction) MatterThermostatUserInterfaceConfigurationClusterServerPreAttributeChangedCallback, \ }; // clang-format off @@ -704,7 +685,7 @@ // clang-format on #define ZAP_CLUSTER_MASK(mask) CLUSTER_MASK_##mask -#define GENERATED_CLUSTER_COUNT 29 +#define GENERATED_CLUSTER_COUNT 30 // clang-format off #define GENERATED_CLUSTERS { \ @@ -1006,20 +987,20 @@ .generatedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 69 ) ,\ },\ { \ - /* Endpoint: 1, Cluster: Basic (server) */ \ - .clusterId = 0x00000028, \ + /* Endpoint: 1, Cluster: Descriptor (server) */ \ + .clusterId = 0x0000001D, \ .attributes = ZAP_ATTRIBUTE_INDEX(223), \ - .attributeCount = 22, \ - .clusterSize = 41, \ - .mask = ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(INIT_FUNCTION), \ - .functions = chipFuncArrayBasicServer, \ + .attributeCount = 6, \ + .clusterSize = 4, \ + .mask = ZAP_CLUSTER_MASK(SERVER), \ + .functions = NULL, \ .acceptedCommandList = nullptr ,\ .generatedCommandList = nullptr ,\ },\ { \ /* Endpoint: 1, Cluster: Thermostat (server) */ \ .clusterId = 0x00000201, \ - .attributes = ZAP_ATTRIBUTE_INDEX(245), \ + .attributes = ZAP_ATTRIBUTE_INDEX(229), \ .attributeCount = 16, \ .clusterSize = 31, \ .mask = ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(INIT_FUNCTION) | ZAP_CLUSTER_MASK(PRE_ATTRIBUTE_CHANGED_FUNCTION), \ @@ -1027,18 +1008,29 @@ .acceptedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 76 ) ,\ .generatedCommandList = nullptr ,\ },\ + { \ + /* Endpoint: 1, Cluster: Thermostat User Interface Configuration (server) */ \ + .clusterId = 0x00000204, \ + .attributes = ZAP_ATTRIBUTE_INDEX(245), \ + .attributeCount = 4, \ + .clusterSize = 8, \ + .mask = ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(PRE_ATTRIBUTE_CHANGED_FUNCTION), \ + .functions = chipFuncArrayThermostatUserInterfaceConfigurationServer, \ + .acceptedCommandList = nullptr ,\ + .generatedCommandList = nullptr ,\ + },\ } // clang-format on #define ZAP_CLUSTER_INDEX(index) (&generatedClusters[index]) -#define ZAP_FIXED_ENDPOINT_DATA_VERSION_COUNT 27 +#define ZAP_FIXED_ENDPOINT_DATA_VERSION_COUNT 28 // This is an array of EmberAfEndpointType structures. #define GENERATED_ENDPOINT_TYPES \ { \ - { ZAP_CLUSTER_INDEX(0), 23, 259 }, { ZAP_CLUSTER_INDEX(23), 6, 100 }, \ + { ZAP_CLUSTER_INDEX(0), 23, 259 }, { ZAP_CLUSTER_INDEX(23), 7, 71 }, \ } // Largest attribute size is needed for various buffers @@ -1047,10 +1039,10 @@ static_assert(ATTRIBUTE_LARGEST <= CHIP_CONFIG_MAX_ATTRIBUTE_STORE_ELEMENT_SIZE, "ATTRIBUTE_LARGEST larger than expected"); // Total size of singleton attributes -#define ATTRIBUTE_SINGLETONS_SIZE (74) +#define ATTRIBUTE_SINGLETONS_SIZE (37) // Total size of attribute storage -#define ATTRIBUTE_MAX_SIZE (359) +#define ATTRIBUTE_MAX_SIZE (330) // Number of fixed endpoints #define FIXED_ENDPOINT_COUNT (2) diff --git a/zzz_generated/thermostat/zap-generated/gen_config.h b/zzz_generated/thermostat/zap-generated/gen_config.h index 0f3fd1f8c1698d..86a851c2c39483 100644 --- a/zzz_generated/thermostat/zap-generated/gen_config.h +++ b/zzz_generated/thermostat/zap-generated/gen_config.h @@ -33,10 +33,10 @@ #define EMBER_AF_IDENTIFY_CLUSTER_SERVER_ENDPOINT_COUNT (2) #define EMBER_AF_GROUPS_CLUSTER_SERVER_ENDPOINT_COUNT (1) #define EMBER_AF_SCENES_CLUSTER_SERVER_ENDPOINT_COUNT (1) -#define EMBER_AF_DESCRIPTOR_CLUSTER_SERVER_ENDPOINT_COUNT (1) +#define EMBER_AF_DESCRIPTOR_CLUSTER_SERVER_ENDPOINT_COUNT (2) #define EMBER_AF_BINDING_CLUSTER_SERVER_ENDPOINT_COUNT (1) #define EMBER_AF_ACCESS_CONTROL_CLUSTER_SERVER_ENDPOINT_COUNT (1) -#define EMBER_AF_BASIC_CLUSTER_SERVER_ENDPOINT_COUNT (2) +#define EMBER_AF_BASIC_CLUSTER_SERVER_ENDPOINT_COUNT (1) #define EMBER_AF_OTA_SOFTWARE_UPDATE_PROVIDER_CLUSTER_CLIENT_ENDPOINT_COUNT (1) #define EMBER_AF_OTA_SOFTWARE_UPDATE_REQUESTOR_CLUSTER_SERVER_ENDPOINT_COUNT (1) #define EMBER_AF_LOCALIZATION_CONFIGURATION_CLUSTER_SERVER_ENDPOINT_COUNT (1) @@ -56,6 +56,7 @@ #define EMBER_AF_FIXED_LABEL_CLUSTER_SERVER_ENDPOINT_COUNT (1) #define EMBER_AF_USER_LABEL_CLUSTER_SERVER_ENDPOINT_COUNT (1) #define EMBER_AF_THERMOSTAT_CLUSTER_SERVER_ENDPOINT_COUNT (1) +#define EMBER_AF_THERMOSTAT_USER_INTERFACE_CONFIGURATION_CLUSTER_SERVER_ENDPOINT_COUNT (1) /**** Cluster Plugins ****/ @@ -203,3 +204,8 @@ #define ZCL_USING_THERMOSTAT_CLUSTER_SERVER #define EMBER_AF_PLUGIN_THERMOSTAT_SERVER #define EMBER_AF_PLUGIN_THERMOSTAT + +// Use this macro to check if the server side of the Thermostat User Interface Configuration cluster is included +#define ZCL_USING_THERMOSTAT_USER_INTERFACE_CONFIGURATION_CLUSTER_SERVER +#define EMBER_AF_PLUGIN_THERMOSTAT_USER_INTERFACE_CONFIGURATION_SERVER +#define EMBER_AF_PLUGIN_THERMOSTAT_USER_INTERFACE_CONFIGURATION