From 5bd9f4d05fe5bb01d5f073a51c701fd20716d853 Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Wed, 8 Mar 2023 11:47:24 -0500 Subject: [PATCH] Add M5Stack specific builds for esp32 light (#25550) * Enable builds for m5stack for more apps as m5stack and devkitc are the same MCU except screen support -i.e. defaults should work * start adding some compile options for ESP32 display ... still made a TODO for actual integration * Enable m5stack in Kconfig * Things compile now * Restyle * Remove demo items * Add more config variables to get displays working * Cleanup unused widgets, add callbacks for the wifi one * Make wifi green * Cleanup device with display: no more virtual devices * Restyle * Remove unnedded log * Remove unused variable * Remove useless commment in QRCodeScreen.h * Remove one more useless coment * Update examples/lighting-app/esp32/main/Button.cpp Co-authored-by: Cliff Chung <116232729+cliffamzn@users.noreply.github.com> * Update examples/lighting-app/esp32/main/DeviceWithDisplay.cpp Co-authored-by: Cliff Chung <116232729+cliffamzn@users.noreply.github.com> * Update examples/lighting-app/esp32/main/Globals.cpp Co-authored-by: Cliff Chung <116232729+cliffamzn@users.noreply.github.com> * Update examples/lighting-app/esp32/main/StatusScreen.cpp Co-authored-by: Cliff Chung <116232729+cliffamzn@users.noreply.github.com> * Update copyright dates and remove a bunch of @file comments * Move ifdefs around * Remove useless button.h comments * Move ifdefs a bit - HAVE_DISPLAY is a result of a header --------- Co-authored-by: Andrei Litvin Co-authored-by: Cliff Chung <116232729+cliffamzn@users.noreply.github.com> --- examples/common/screen-framework/Display.cpp | 12 +- examples/lighting-app/esp32/CMakeLists.txt | 8 +- examples/lighting-app/esp32/main/AppTask.cpp | 62 ++++- examples/lighting-app/esp32/main/Button.cpp | 93 ++++++-- .../lighting-app/esp32/main/CMakeLists.txt | 6 +- .../esp32/main/DeviceCallbacks.cpp | 21 +- .../esp32/main/DeviceWithDisplay.cpp | 224 ++++++++++++++++++ .../esp32/main/DeviceWithDisplay.h | 52 ++++ examples/lighting-app/esp32/main/Globals.cpp | 21 ++ .../lighting-app/esp32/main/Kconfig.projbuild | 24 +- .../lighting-app/esp32/main/LEDWidget.cpp | 21 +- .../lighting-app/esp32/main/QRCodeScreen.cpp | 100 ++++++++ .../lighting-app/esp32/main/StatusScreen.cpp | 189 +++++++++++++++ .../lighting-app/esp32/main/WiFiWidget.cpp | 66 ++++++ .../esp32/main/include/AppEvent.h | 3 +- .../lighting-app/esp32/main/include/AppTask.h | 6 +- .../lighting-app/esp32/main/include/Button.h | 32 ++- .../esp32/main/include/DeviceCallbacks.h | 17 +- .../lighting-app/esp32/main/include/Globals.h | 23 ++ .../esp32/main/include/LEDWidget.h | 11 +- .../esp32/main/include/QRCodeScreen.h | 42 ++++ .../esp32/main/include/StatusScreen.h | 38 +++ .../esp32/main/include/WiFiWidget.h | 36 +++ examples/lighting-app/esp32/main/main.cpp | 6 +- .../esp32/sdkconfig_m5stack.defaults | 64 +++++ scripts/build/builders/esp32.py | 3 +- 26 files changed, 1099 insertions(+), 81 deletions(-) create mode 100644 examples/lighting-app/esp32/main/DeviceWithDisplay.cpp create mode 100644 examples/lighting-app/esp32/main/DeviceWithDisplay.h create mode 100644 examples/lighting-app/esp32/main/Globals.cpp create mode 100644 examples/lighting-app/esp32/main/QRCodeScreen.cpp create mode 100644 examples/lighting-app/esp32/main/StatusScreen.cpp create mode 100644 examples/lighting-app/esp32/main/WiFiWidget.cpp create mode 100644 examples/lighting-app/esp32/main/include/Globals.h create mode 100644 examples/lighting-app/esp32/main/include/QRCodeScreen.h create mode 100644 examples/lighting-app/esp32/main/include/StatusScreen.h create mode 100644 examples/lighting-app/esp32/main/include/WiFiWidget.h create mode 100644 examples/lighting-app/esp32/sdkconfig_m5stack.defaults diff --git a/examples/common/screen-framework/Display.cpp b/examples/common/screen-framework/Display.cpp index bd6e363b33c9ac..71e41f10aaa36e 100644 --- a/examples/common/screen-framework/Display.cpp +++ b/examples/common/screen-framework/Display.cpp @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2020-2023 Project CHIP Authors * Copyright (c) 2018 Nest Labs, Inc. * All rights reserved. * @@ -16,14 +16,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/** - * @file Display.cpp - * - * This file implements helper APIs for the M5Stack's display - * - */ - #include #include "driver/ledc.h" @@ -54,7 +46,7 @@ // The M5Stack's backlight is on Channel 7 #define BACKLIGHT_CHANNEL LEDC_CHANNEL_7 -extern const char * TAG; +static const char * TAG = "Display"; uint16_t DisplayHeight = 0; uint16_t DisplayWidth = 0; diff --git a/examples/lighting-app/esp32/CMakeLists.txt b/examples/lighting-app/esp32/CMakeLists.txt index 92f2a10fec2f0b..3b61c69d0e05bd 100644 --- a/examples/lighting-app/esp32/CMakeLists.txt +++ b/examples/lighting-app/esp32/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2021 Project CHIP Authors +# Copyright (c) 2021-2023 Project CHIP Authors # All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -29,6 +29,12 @@ set(EXTRA_COMPONENT_DIRS "${CMAKE_CURRENT_LIST_DIR}/third_party/connectedhomeip/examples/common/QRCode" ) +if(${IDF_TARGET} STREQUAL "esp32") + list(APPEND EXTRA_COMPONENT_DIRS "${CMAKE_CURRENT_LIST_DIR}/third_party/connectedhomeip/examples/common/m5stack-tft/repo/components/tft" + "${CMAKE_CURRENT_LIST_DIR}/third_party/connectedhomeip/examples/common/m5stack-tft/repo/components/spidriver" + "${CMAKE_CURRENT_LIST_DIR}/third_party/connectedhomeip/examples/common/screen-framework") +endif() + project(chip-lighting-app) # C++17 is required for RPC build. diff --git a/examples/lighting-app/esp32/main/AppTask.cpp b/examples/lighting-app/esp32/main/AppTask.cpp index 91f91340e37bca..6369cf91089670 100644 --- a/examples/lighting-app/esp32/main/AppTask.cpp +++ b/examples/lighting-app/esp32/main/AppTask.cpp @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2022 Project CHIP Authors + * Copyright (c) 2022-2023 Project CHIP Authors * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,6 +20,8 @@ #include "esp_log.h" #include "freertos/FreeRTOS.h" +#include "DeviceWithDisplay.h" + #include #define APP_TASK_NAME "APP" @@ -36,7 +38,6 @@ using namespace ::chip::DeviceLayer; static const char * TAG = "app-task"; LEDWidget AppLED; -Button AppButton; namespace { constexpr EndpointId kLightEndpointId = 1; @@ -61,14 +62,59 @@ CHIP_ERROR AppTask::StartAppTask() return (xReturned == pdPASS) ? CHIP_NO_ERROR : APP_ERROR_CREATE_TASK_FAILED; } +void AppTask::ButtonEventHandler(const uint8_t buttonHandle, uint8_t btnAction) +{ + if (btnAction != APP_BUTTON_PRESSED) + { + return; + } + + AppEvent button_event = {}; + button_event.Type = AppEvent::kEventType_Button; + +#if CONFIG_HAVE_DISPLAY + button_event.ButtonEvent.PinNo = buttonHandle; + button_event.ButtonEvent.Action = btnAction; + button_event.mHandler = ButtonPressedAction; +#else + button_event.mHandler = AppTask::LightingActionEventHandler; +#endif + + sAppTask.PostEvent(&button_event); +} + +#if CONFIG_DEVICE_TYPE_M5STACK +void AppTask::ButtonPressedAction(AppEvent * aEvent) +{ + uint32_t io_num = aEvent->ButtonEvent.PinNo; + int level = gpio_get_level((gpio_num_t) io_num); + if (level == 0) + { + bool woken = WakeDisplay(); + if (woken) + { + return; + } + // Button 1 is connected to the pin 39 + // Button 2 is connected to the pin 38 + // Button 3 is connected to the pin 37 + // So we use 40 - io_num to map the pin number to button number + ScreenManager::ButtonPressed(40 - io_num); + } +} +#endif + CHIP_ERROR AppTask::Init() { CHIP_ERROR err = CHIP_NO_ERROR; AppLED.Init(); - AppButton.Init(); - AppButton.SetButtonPressCallback(ButtonPressCallback); +#if CONFIG_HAVE_DISPLAY + InitDeviceDisplay(); + + AppLED.SetVLED(ScreenManager::AddVLED(TFT_YELLOW)); +#endif return err; } @@ -139,14 +185,6 @@ void AppTask::LightingActionEventHandler(AppEvent * aEvent) chip::DeviceLayer::PlatformMgr().UnlockChipStack(); } -void AppTask::ButtonPressCallback() -{ - AppEvent button_event; - button_event.Type = AppEvent::kEventType_Button; - button_event.mHandler = AppTask::LightingActionEventHandler; - sAppTask.PostEvent(&button_event); -} - void AppTask::UpdateClusterState() { ESP_LOGI(TAG, "Writing to OnOff cluster"); diff --git a/examples/lighting-app/esp32/main/Button.cpp b/examples/lighting-app/esp32/main/Button.cpp index aadae002bc2d08..ea4959ff6188cb 100644 --- a/examples/lighting-app/esp32/main/Button.cpp +++ b/examples/lighting-app/esp32/main/Button.cpp @@ -1,6 +1,7 @@ /* * - * Copyright (c) 2022 Project CHIP Authors + * Copyright (c) 2022-2023 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. @@ -14,53 +15,95 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include "driver/gpio.h" +#include "esp_check.h" +#include "esp_log.h" +#include "esp_system.h" +#include "AppTask.h" #include "Button.h" -#include "esp_attr.h" +#include "Globals.h" +#include "ScreenManager.h" +#include +#include +#include -#define GPIO_INPUT_IO_0 9 -#define GPIO_INPUT_PIN_SEL (1ULL << GPIO_INPUT_IO_0) -#define ESP_INTR_FLAG_DEFAULT 0 +static const char * TAG = "Button.cpp"; -static const char * TAG = "Button"; +extern Button gButtons[BUTTON_NUMBER]; -static Button::ButtonPressCallback button_press_handler = nullptr; +Button::Button() {} -static void IRAM_ATTR gpio_isr_handler(void * arg) +Button::Button(gpio_num_t gpioNum) { - if (button_press_handler != nullptr) + mGPIONum = gpioNum; +} + +int32_t Find_Button_Via_Pin(gpio_num_t gpioNum) +{ + for (int i = 0; i < BUTTON_NUMBER; i++) { - button_press_handler(); + if (gButtons[i].GetGPIONum() == gpioNum) + { + return i; + } } + return -1; } -void Button::Init() +void IRAM_ATTR button_isr_handler(void * arg) { - /* Initialize button interrupt*/ - // zero-initialize the config structure. + uint32_t gpio_num = (uint32_t) arg; + int32_t idx = Find_Button_Via_Pin((gpio_num_t) gpio_num); + if (idx == -1) + { + return; + } + BaseType_t taskWoken = pdFALSE; + xTimerStartFromISR(gButtons[idx].mbuttonTimer, + &taskWoken); // If the timer had already been started ,restart it will reset its expiry time +} + +esp_err_t Button::Init() +{ + return Init(mGPIONum); +} + +esp_err_t Button::Init(gpio_num_t gpioNum) +{ + esp_err_t ret = ESP_OK; + + mGPIONum = gpioNum; + // zero-initialize the config structure. gpio_config_t io_conf = {}; - // interrupt of rising edge + // interrupt of falling edge io_conf.intr_type = GPIO_INTR_NEGEDGE; // bit mask of the pins, use GPIO4/5 here - io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL; + io_conf.pin_bit_mask = 1ULL << gpioNum; // set as input mode io_conf.mode = GPIO_MODE_INPUT; // enable pull-up mode io_conf.pull_up_en = GPIO_PULLUP_ENABLE; + gpio_config(&io_conf); - // install gpio isr service - gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT); // hook isr handler for specific gpio pin - gpio_isr_handler_add(static_cast(GPIO_INPUT_IO_0), gpio_isr_handler, (void *) GPIO_INPUT_IO_0); + ret = gpio_isr_handler_add(gpioNum, button_isr_handler, (void *) gpioNum); + ESP_RETURN_ON_ERROR(ret, TAG, "gpio_isr_handler_add failed: %s", esp_err_to_name(ret)); - ESP_LOGI(TAG, "Button initialized.."); -} + mbuttonTimer = xTimerCreate("BtnTmr", // Just a text name, not used by the RTOS kernel + pdMS_TO_TICKS(50), // timer period + false, // no timer reload (==one-shot) + (void *) (int) gpioNum, // init timer id = gpioNum index + TimerCallback // timer callback handler (all buttons use + // the same timer cn function) + ); -void Button::SetButtonPressCallback(ButtonPressCallback button_callback) + return ESP_OK; +} +void Button::TimerCallback(TimerHandle_t xTimer) { - if (button_callback != nullptr) - { - button_press_handler = button_callback; - } + // Get the button index of the expired timer and call button event Handler. + uint32_t gpio_num = (uint32_t) pvTimerGetTimerID(xTimer); + GetAppTask().ButtonEventHandler(gpio_num, APP_BUTTON_PRESSED); } diff --git a/examples/lighting-app/esp32/main/CMakeLists.txt b/examples/lighting-app/esp32/main/CMakeLists.txt index 450a47f7db3fee..fcedfb4774637e 100644 --- a/examples/lighting-app/esp32/main/CMakeLists.txt +++ b/examples/lighting-app/esp32/main/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2021 Project CHIP Authors +# Copyright (c) 2021-2023 Project CHIP Authors # All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -85,6 +85,10 @@ set(SRC_DIRS_LIST "${SRC_DIRS_LIST}" ) endif (CONFIG_ENABLE_PW_RPC) +if ("${CONFIG_DEVICE_TYPE_M5STACK}" STREQUAL "y") + list(APPEND PRIV_REQUIRES_LIST tft screen-framework) +endif() + idf_component_register(PRIV_INCLUDE_DIRS ${PRIV_INCLUDE_DIRS_LIST} SRC_DIRS ${SRC_DIRS_LIST} PRIV_REQUIRES ${PRIV_REQUIRES_LIST}) diff --git a/examples/lighting-app/esp32/main/DeviceCallbacks.cpp b/examples/lighting-app/esp32/main/DeviceCallbacks.cpp index 46983fdf441cd4..dcaaa187186b9e 100644 --- a/examples/lighting-app/esp32/main/DeviceCallbacks.cpp +++ b/examples/lighting-app/esp32/main/DeviceCallbacks.cpp @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2021-2023 Project CHIP Authors * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,17 +15,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/** - * @file DeviceCallbacks.cpp - * - * Implements all the callbacks to the application from the CHIP Stack - * - **/ - #include "AppTask.h" #include "DeviceCallbacks.h" +#include "Globals.h" #include "LEDWidget.h" #include @@ -147,3 +140,13 @@ void emberAfOnOffClusterInitCallback(EndpointId endpoint) ESP_LOGI(TAG, "emberAfOnOffClusterInitCallback"); GetAppTask().UpdateClusterState(); } + +void AppDeviceCallbacksDelegate::OnIPv4ConnectivityEstablished() +{ + wifiLED.Set(true); +} + +void AppDeviceCallbacksDelegate::OnIPv4ConnectivityLost() +{ + wifiLED.Set(false); +} diff --git a/examples/lighting-app/esp32/main/DeviceWithDisplay.cpp b/examples/lighting-app/esp32/main/DeviceWithDisplay.cpp new file mode 100644 index 00000000000000..bbca9845d0662d --- /dev/null +++ b/examples/lighting-app/esp32/main/DeviceWithDisplay.cpp @@ -0,0 +1,224 @@ +/* + * + * Copyright (c) 2023 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 "DeviceWithDisplay.h" + +#if CONFIG_HAVE_DISPLAY + +#include "Globals.h" +#include +#include +#include + +using namespace ::chip; +using namespace ::chip::Credentials; +using namespace ::chip::DeviceManager; +using namespace ::chip::DeviceLayer; + +static const char * TAG = "DeviceWithDisplay"; + +#if CONFIG_DEVICE_TYPE_M5STACK + +Button gButtons[BUTTON_NUMBER] = { Button(BUTTON_1_GPIO_NUM), Button(BUTTON_2_GPIO_NUM), Button(BUTTON_3_GPIO_NUM) }; + +class ActionListModel : public ListScreen::Model +{ + int GetItemCount() override { return static_cast(mActions.size()); } + std::string GetItemText(int i) override { return mActions[i].title.c_str(); } + void ItemAction(int i) override + { + ESP_LOGI(TAG, "generic action %d", i); + mActions[i].action(); + } + +protected: + void AddAction(const char * name, std::function action) { mActions.push_back(Action(name, action)); } + +private: + struct Action + { + std::string title; + std::function action; + + Action(const char * t, std::function a) : title(t), action(a) {} + }; + + std::vector mActions; +}; + +class MdnsDebugListModel : public ActionListModel +{ +public: + std::string GetTitle() override { return "mDNS Debug"; } + + MdnsDebugListModel() { AddAction("(Re-)Init", std::bind(&MdnsDebugListModel::DoReinit, this)); } + +private: + void DoReinit() + { + CHIP_ERROR err = Dnssd::ServiceAdvertiser::Instance().Init(DeviceLayer::UDPEndPointManager()); + if (err != CHIP_NO_ERROR) + { + ESP_LOGE(TAG, "Error initializing: %s", err.AsString()); + } + } +}; + +class TouchesMatterStackModel : public ListScreen::Model +{ + // We could override Action() and then hope focusIndex has not changed by + // the time our queued task runs, but it's cleaner to just capture its value + // now. + struct QueuedAction + { + QueuedAction(TouchesMatterStackModel * selfArg, int iArg) : self(selfArg), i(iArg) {} + TouchesMatterStackModel * self; + int i; + }; + + void ItemAction(int i) final + { + auto * action = chip::Platform::New(this, i); + chip::DeviceLayer::PlatformMgr().ScheduleWork(QueuedActionHandler, reinterpret_cast(action)); + } + + static void QueuedActionHandler(intptr_t closure) + { + auto * queuedAction = reinterpret_cast(closure); + queuedAction->self->DoAction(queuedAction->i); + chip::Platform::Delete(queuedAction); + } + + virtual void DoAction(int i) = 0; +}; + +class SetupListModel : public TouchesMatterStackModel +{ +public: + SetupListModel() + { + std::string resetWiFi = "Reset WiFi"; + std::string resetToFactory = "Reset to factory"; + std::string forceWiFiCommissioningBasic = "Force WiFi commissioning (basic)"; + options.emplace_back(resetWiFi); + options.emplace_back(resetToFactory); + options.emplace_back(forceWiFiCommissioningBasic); + } + virtual std::string GetTitle() { return "Setup"; } + virtual int GetItemCount() { return options.size(); } + virtual std::string GetItemText(int i) { return options.at(i); } + void DoAction(int i) override + { + ESP_LOGI(TAG, "Opening options %d: %s", i, GetItemText(i).c_str()); + if (i == 0) + { + ConnectivityMgr().ClearWiFiStationProvision(); + chip::Server::GetInstance().GetFabricTable().DeleteAllFabrics(); + chip::Server::GetInstance().GetCommissioningWindowManager().OpenBasicCommissioningWindow(); + } + else if (i == 1) + { + chip::Server::GetInstance().ScheduleFactoryReset(); + } + else if (i == 2) + { + chip::Server::GetInstance().GetFabricTable().DeleteAllFabrics(); + auto & commissionMgr = chip::Server::GetInstance().GetCommissioningWindowManager(); + commissionMgr.OpenBasicCommissioningWindow(commissionMgr.MaxCommissioningTimeout(), + CommissioningWindowAdvertisement::kDnssdOnly); + } + } + +private: + std::vector options; +}; + +esp_err_t InitM5Stack(std::string qrCodeText) +{ + esp_err_t err; + // Initialize the buttons. + err = gpio_install_isr_service(0); + ESP_RETURN_ON_ERROR(err, TAG, "Button preInit failed: %s", esp_err_to_name(err)); + for (int i = 0; i < BUTTON_NUMBER; ++i) + { + err = gButtons[i].Init(); + ESP_RETURN_ON_ERROR(err, TAG, "Button.Init() failed: %s", esp_err_to_name(err)); + } + // Push a rudimentary user interface. + ScreenManager::PushScreen(chip::Platform::New( + (chip::Platform::New()) + ->Title("CHIP") + ->Action([](int i) { ESP_LOGI(TAG, "action on item %d", i); }) + ->Item("mDNS Debug", + []() { + ESP_LOGI(TAG, "Opening MDNS debug"); + ScreenManager::PushScreen(chip::Platform::New(chip::Platform::New())); + }) + ->Item("QR Code", + [=]() { + ESP_LOGI(TAG, "Opening QR code screen"); + PrintOnboardingCodes(chip::RendezvousInformationFlags(CONFIG_RENDEZVOUS_MODE)); + ScreenManager::PushScreen(chip::Platform::New(qrCodeText)); + }) + ->Item("Setup", + [=]() { + ESP_LOGI(TAG, "Opening Setup list"); + ScreenManager::PushScreen(chip::Platform::New(chip::Platform::New())); + }) + ->Item("Status", [=]() { + ESP_LOGI(TAG, "Opening Status screen"); + ScreenManager::PushScreen(chip::Platform::New()); + }))); + return ESP_OK; +} +#endif + +void InitDeviceDisplay() +{ + // Create buffer for QR code that can fit max size and null terminator. + char qrCodeBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1]; + chip::MutableCharSpan qrCodeText(qrCodeBuffer); + + // Get QR Code and emulate its content using NFC tag + GetQRCode(qrCodeText, chip::RendezvousInformationFlags(CONFIG_RENDEZVOUS_MODE)); + + // Initialize the display device. + esp_err_t err = InitDisplay(); + if (err != ESP_OK) + { + ESP_LOGE(TAG, "InitDisplay() failed: %s", esp_err_to_name(err)); + return; + } + + // Initialize the screen manager + ScreenManager::Init(); + wifiLED.SetVLED(ScreenManager::AddVLED(TFT_GREEN)); + +#if CONFIG_DEVICE_TYPE_M5STACK + + InitM5Stack(qrCodeText.data()); + +#elif CONFIG_DEVICE_TYPE_ESP32_WROVER_KIT + + // Display the QR Code + QRCodeScreen qrCodeScreen(qrCodeText.data()); + qrCodeScreen.Display(); + +#endif +} +#endif diff --git a/examples/lighting-app/esp32/main/DeviceWithDisplay.h b/examples/lighting-app/esp32/main/DeviceWithDisplay.h new file mode 100644 index 00000000000000..82feb8dbf841b6 --- /dev/null +++ b/examples/lighting-app/esp32/main/DeviceWithDisplay.h @@ -0,0 +1,52 @@ +/* + * + * Copyright (c) 2023 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 "Button.h" +#include "DeviceCallbacks.h" +#include "Display.h" +#include "ListScreen.h" +#include "QRCodeScreen.h" +#include "ScreenManager.h" +#include "StatusScreen.h" +#include "esp_check.h" +#include "esp_log.h" +#include "esp_system.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include +#include + +#if CONFIG_HAVE_DISPLAY + +#include +#include +#include +#include + +#if CONFIG_DEVICE_TYPE_M5STACK +#define BUTTON_1_GPIO_NUM ((gpio_num_t) 39) // Left button on M5Stack +#define BUTTON_2_GPIO_NUM ((gpio_num_t) 38) // Middle button on M5Stack +#define BUTTON_3_GPIO_NUM ((gpio_num_t) 37) // Right button on M5Stack + +esp_err_t InitM5Stack(std::string qrCodeText); +#endif + +void InitDeviceDisplay(); +#endif diff --git a/examples/lighting-app/esp32/main/Globals.cpp b/examples/lighting-app/esp32/main/Globals.cpp new file mode 100644 index 00000000000000..4c0f82bf564efc --- /dev/null +++ b/examples/lighting-app/esp32/main/Globals.cpp @@ -0,0 +1,21 @@ +/* + * + * Copyright (c) 2023 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 "Globals.h" + +WiFiWidget wifiLED; diff --git a/examples/lighting-app/esp32/main/Kconfig.projbuild b/examples/lighting-app/esp32/main/Kconfig.projbuild index b41b4ef0e4fb81..5f3c88166c6dda 100644 --- a/examples/lighting-app/esp32/main/Kconfig.projbuild +++ b/examples/lighting-app/esp32/main/Kconfig.projbuild @@ -1,5 +1,5 @@ # -# Copyright (c) 2021 Project CHIP Authors +# Copyright (c) 2021-2023 Project CHIP Authors # All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -38,6 +38,9 @@ menu "Demo" config DEVICE_TYPE_ESP32_WROVER_KIT bool "ESP32-WROVER-KIT_V4.1" depends on IDF_TARGET_ESP32 + config DEVICE_TYPE_M5STACK + bool "M5Stack" + depends on IDF_TARGET_ESP32 config DEVICE_TYPE_ESP32_C3_DEVKITM bool "ESP32C3-DevKitM" depends on IDF_TARGET_ESP32C3 @@ -82,6 +85,7 @@ menu "Demo" default 26 if DEVICE_TYPE_ESP32_WROVER_KIT default 8 if DEVICE_TYPE_ESP32_C3_DEVKITM || DEVICE_TYPE_ESP32H2_DEVKITC || DEVICE_TYPE_ESP32_C2_DEVKITM default 48 if DEVICE_TYPE_ESP32_S3_DEVKITM + default 5 if DEVICE_TYPE_M5STACK default 5 help GPIO number (IOxx) to blink on and off or the RMT signal for the addressable LED. @@ -102,6 +106,17 @@ menu "Demo" bool "Ethernet" endchoice + # NOTE: This config is not displayed as a input in the Kconfig menu, as its value is + # entirely derived from the Device Type choice. However the CONFIG_EXAMPLE_DISPLAY_TYPE + # define that is produced is needed to configure the TFT library correctly. + config TFT_PREDEFINED_DISPLAY_TYPE + int + range 0 5 + default 0 if DEVICE_TYPE_ESP32_DEVKITC + default 0 if DEVICE_TYPE_ESP32_C3_DEVKITM || DEVICE_TYPE_ESP32_C2_DEVKITM + default 3 if DEVICE_TYPE_M5STACK + default 4 if DEVICE_TYPE_ESP32_WROVER_KIT + config RENDEZVOUS_MODE int range 0 8 @@ -110,6 +125,13 @@ menu "Demo" default 4 if RENDEZVOUS_MODE_THREAD default 8 if RENDEZVOUS_MODE_ETHERNET + config DISPLAY_AUTO_OFF + bool "Automatically turn off the M5Stack's Display after a few seconds" + default "y" + depends on DEVICE_TYPE_M5STACK + help + To reduce wear and heat the M5Stack's Display is automatically switched off after a few seconds + endmenu menu "PW RPC Debug channel" diff --git a/examples/lighting-app/esp32/main/LEDWidget.cpp b/examples/lighting-app/esp32/main/LEDWidget.cpp index 6e65bec7c0c1e5..246b0cec8d2b2d 100644 --- a/examples/lighting-app/esp32/main/LEDWidget.cpp +++ b/examples/lighting-app/esp32/main/LEDWidget.cpp @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2021-2023 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. @@ -17,6 +17,7 @@ #include "LEDWidget.h" #include "ColorFormat.h" +#include "ScreenManager.h" #include "led_strip.h" static const char * TAG = "LEDWidget"; @@ -126,11 +127,27 @@ void LEDWidget::DoSet(void) mStrip->refresh(mStrip, 100); } #else - ESP_LOGI(TAG, "DoSet to GPIO number %d", mGPIONum); if (mGPIONum < GPIO_NUM_MAX) { ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, brightness); ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0); } #endif // CONFIG_LED_TYPE_RMT +#if CONFIG_HAVE_DISPLAY + if (mVirtualLEDIndex != -1) + { + ScreenManager::SetVLED(mVirtualLEDIndex, mState); + } +#endif // CONFIG_HAVE_DISPLAY +} + +#if CONFIG_DEVICE_TYPE_M5STACK +void LEDWidget::SetVLED(int id1) +{ + mVirtualLEDIndex = id1; + if (mVirtualLEDIndex != -1) + { + ScreenManager::SetVLED(mVirtualLEDIndex, mState); + } } +#endif diff --git a/examples/lighting-app/esp32/main/QRCodeScreen.cpp b/examples/lighting-app/esp32/main/QRCodeScreen.cpp new file mode 100644 index 00000000000000..d4113c4d0889b9 --- /dev/null +++ b/examples/lighting-app/esp32/main/QRCodeScreen.cpp @@ -0,0 +1,100 @@ +/* + * + * Copyright (c) 2020-2023 Project CHIP Authors + * Copyright (c) 2018 Nest Labs, Inc. + * 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. + */ + +/** + * @file QRCodeScreen.cpp + * + * Screen which displays a QR code. + * + */ + +#include "QRCodeScreen.h" + +#if CONFIG_HAVE_DISPLAY + +// TODO organize includes below + +#include "esp_log.h" +#include "esp_system.h" +#include "esp_wifi.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include "qrcodegen.h" + +#include +#include +#include + +namespace { + +constexpr int kVersion = 4; +constexpr int kModuleSize = 4; +constexpr int kBorderSize = 1; + +color_t qrCodeColor = TFT_LIGHTGREY; + +}; // namespace + +QRCodeScreen::QRCodeScreen(std::string text, std::string title) : title(title) +{ + constexpr int qrCodeSize = qrcodegen_BUFFER_LEN_FOR_VERSION(kVersion); + + // TODO check text length against max size permitted, or maybe adjust version used accordingly + + std::vector temp(qrCodeSize); + qrCode.resize(qrCodeSize); + + if (!qrcodegen_encodeText(text.c_str(), temp.data(), qrCode.data(), qrcodegen_Ecc_LOW, kVersion, kVersion, qrcodegen_Mask_AUTO, + true)) + { + ESP_LOGE("QRCodeScreen", "qrcodegen_encodeText() failed"); + qrCode.clear(); + } +} + +void QRCodeScreen::Display() +{ + if (qrCode.empty()) + { + return; + } + + const uint8_t * data = qrCode.data(); + const int size = qrcodegen_getSize(data); + const int displaySize = (2 * kBorderSize + size) * kModuleSize; + const int displayX = (DisplayWidth - displaySize) / 2; + const int displayY = ScreenTitleSafeTop + ((DisplayHeight - ScreenTitleSafeTop - ScreenTitleSafeBottom) - displaySize) / 2; + + TFT_fillRect(displayX, displayY, displaySize, displaySize, qrCodeColor); + + for (int y = 0; y < size; ++y) + { + for (int x = 0; x < size; ++x) + { + if (qrcodegen_getModule(data, x, y)) + { + TFT_fillRect(displayX + (kBorderSize + x) * kModuleSize, displayY + (kBorderSize + y) * kModuleSize, kModuleSize, + kModuleSize, TFT_BLACK); + } + } + } +} + +#endif // CONFIG_HAVE_DISPLAY diff --git a/examples/lighting-app/esp32/main/StatusScreen.cpp b/examples/lighting-app/esp32/main/StatusScreen.cpp new file mode 100644 index 00000000000000..698a12d835ce06 --- /dev/null +++ b/examples/lighting-app/esp32/main/StatusScreen.cpp @@ -0,0 +1,189 @@ +/* + * + * Copyright (c) 2023 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. + */ + +/** + * @file StatusScreen.cpp + * + * Screen which displays device state and status: + * - Fabric Index : none | # + * - Fabric ID : none | # + * - Node ID : none | # + * - UDP Port : # + * - IPv4 : none | addr + * - IPv6 LL : none | addr + * - IPv6 ULA : none | addr + */ + +#include "StatusScreen.h" + +#if CONFIG_HAVE_DISPLAY + +#include "esp_log.h" +#include "esp_system.h" +#include "esp_wifi.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include +#include + +#include +#include + +#define MAX_LENGTH_SMALL_FONT 30 + +using namespace chip; + +class StatusListModel : public ListScreen::Model +{ +public: + enum + { + kStatusItemFabricIndex, + kStatusItemFabricId, + kStatusItemNodeId, + kStatusItemPort, + kStatusItemIp4, + kStatusItemIp6LinkLocal, + kStatusItemIp6Ula, + }; + + StatusListModel() + { + options.emplace_back("FabricIndex : none"); + options.emplace_back("FabricID : none"); + options.emplace_back("NodeID : none"); + options.emplace_back("UDP port : " + std::to_string(CHIP_PORT)); + options.emplace_back("IPv4 : none"); + options.emplace_back("IPv6 LL : none"); + options.emplace_back("IPv6 ULA : none"); + } + + virtual std::string GetTitle() { return "Status"; } + + virtual int GetItemCount() { return options.size(); } + virtual std::string GetItemText(int i) + { + std::string itemString = options.at(i); + switch (i) + { + case kStatusItemFabricIndex: { + for (const auto & fb : Server::GetInstance().GetFabricTable()) + { + FabricIndex fabricIndex = fb.GetFabricIndex(); + itemString = "FabricIdx : " + std::to_string(fabricIndex); + break; // Only print first fabric for now + } + break; + } + + case kStatusItemFabricId: { + for (const auto & fb : Server::GetInstance().GetFabricTable()) + { + FabricId fabricId = fb.GetFabricId(); + itemString = "FabricID : " + std::to_string(fabricId); + break; // Only print first fabric for now + } + break; + } + + case kStatusItemNodeId: { + for (const auto & fb : Server::GetInstance().GetFabricTable()) + { + NodeId nodeId = fb.GetNodeId(); + itemString = "NodeID : " + std::to_string(nodeId); + break; // Only print first fabric for now + } + break; + } + + case kStatusItemIp4: { + chip::Inet::IPAddress addr; + for (chip::Inet::InterfaceAddressIterator it; it.HasCurrent(); it.Next()) + { + if ((it.GetAddress(addr) == CHIP_NO_ERROR) && addr.IsIPv4()) + { + char buf[Inet::IPAddress::kMaxStringLength]; + addr.ToString(buf); + itemString = std::string(buf); + break; // Only print first IPv4 address for now + } + } + break; + } + + case kStatusItemIp6LinkLocal: { + chip::Inet::IPAddress addr; + for (chip::Inet::InterfaceAddressIterator it; it.HasCurrent(); it.Next()) + { + if ((it.GetAddress(addr) == CHIP_NO_ERROR) && addr.IsIPv6LinkLocal()) + { + char buf[Inet::IPAddress::kMaxStringLength]; + addr.ToString(buf); + itemString = std::string(buf); + if (itemString.length() < MAX_LENGTH_SMALL_FONT) + { + TFT_setFont(SMALL_FONT, nullptr); + } + else + { + TFT_setFont(DEF_SMALL_FONT, nullptr); + } + break; // Only print first IPv6 LL for now + } + } + break; + } + + case kStatusItemIp6Ula: { + chip::Inet::IPAddress addr; + for (chip::Inet::InterfaceAddressIterator it; it.HasCurrent(); it.Next()) + { + if ((it.GetAddress(addr) == CHIP_NO_ERROR) && addr.IsIPv6ULA()) + { + char buf[Inet::IPAddress::kMaxStringLength]; + addr.ToString(buf); + itemString = std::string(buf); + if (itemString.length() < MAX_LENGTH_SMALL_FONT) + { + TFT_setFont(SMALL_FONT, nullptr); + } + else + { + TFT_setFont(DEF_SMALL_FONT, nullptr); + } + break; // Only print first IPv6 ULA for now + } + } + break; + } + } + ESP_LOGI("M5 UI", "Display status %d: %s", i, itemString.c_str()); + + return itemString; + } + + virtual void ItemAction(int i) {} + +private: + std::vector options; +}; + +StatusScreen::StatusScreen() : ListScreen(chip::Platform::New()) {} + +#endif // CONFIG_HAVE_DISPLAY diff --git a/examples/lighting-app/esp32/main/WiFiWidget.cpp b/examples/lighting-app/esp32/main/WiFiWidget.cpp new file mode 100644 index 00000000000000..4062cc68e237c7 --- /dev/null +++ b/examples/lighting-app/esp32/main/WiFiWidget.cpp @@ -0,0 +1,66 @@ +/* + * + * Copyright (c) 2020-2023 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. + */ + +/** + * @file WiFiWidget.cpp + * + * Implements a WiFi Widget controller that display the state of bluetooth + * connection on display. + */ + +#include "ScreenManager.h" + +#include "WiFiWidget.h" + +#include "esp_log.h" +#include "esp_system.h" + +void WiFiWidget::Init() +{ +#if CONFIG_HAVE_DISPLAY + mVLED = -1; +#endif // CONFIG_HAVE_DISPLAY + + mState = false; +} + +void WiFiWidget::Set(bool state) +{ + bool stateChange = (mState != state); + mState = state; + if (stateChange) + { +#if CONFIG_HAVE_DISPLAY + if (mVLED != -1) + { + ScreenManager::SetVLED(mVLED, mState); + } +#endif // CONFIG_HAVE_DISPLAY + } +} + +#if CONFIG_HAVE_DISPLAY +void WiFiWidget::SetVLED(int id) +{ + mVLED = id; + if (mVLED != -1) + { + ScreenManager::SetVLED(mVLED, mState); + } +} +#endif // CONFIG_HAVE_DISPLAY diff --git a/examples/lighting-app/esp32/main/include/AppEvent.h b/examples/lighting-app/esp32/main/include/AppEvent.h index 65ebd7aedc8157..079109e6fac770 100644 --- a/examples/lighting-app/esp32/main/include/AppEvent.h +++ b/examples/lighting-app/esp32/main/include/AppEvent.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2022 Project CHIP Authors + * Copyright (c) 2022-2023 Project CHIP Authors * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -38,6 +38,7 @@ struct AppEvent struct { uint8_t Action; + uint8_t PinNo; } ButtonEvent; struct { diff --git a/examples/lighting-app/esp32/main/include/AppTask.h b/examples/lighting-app/esp32/main/include/AppTask.h index 9271ebd3499b44..a7ba9387395316 100644 --- a/examples/lighting-app/esp32/main/include/AppTask.h +++ b/examples/lighting-app/esp32/main/include/AppTask.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2022 Project CHIP Authors + * Copyright (c) 2022-2023 Project CHIP Authors * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -57,7 +57,9 @@ class AppTask static void SwitchActionEventHandler(AppEvent * aEvent); static void LightingActionEventHandler(AppEvent * aEvent); - static void ButtonPressCallback(); +#if CONFIG_DEVICE_TYPE_M5STACK + static void ButtonPressedAction(AppEvent * aEvent); +#endif static AppTask sAppTask; }; diff --git a/examples/lighting-app/esp32/main/include/Button.h b/examples/lighting-app/esp32/main/include/Button.h index 17a08d7c1a9496..1251633630e7b5 100644 --- a/examples/lighting-app/esp32/main/include/Button.h +++ b/examples/lighting-app/esp32/main/include/Button.h @@ -1,6 +1,7 @@ /* * - * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2022-2023 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. @@ -14,17 +15,38 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - #pragma once #include "driver/gpio.h" #include "esp_log.h" +#include "esp_system.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/timers.h" +#define APP_BUTTON_PRESSED 0 +#define APP_BUTTON_RELEASED 1 +#define BUTTON_NUMBER 3 class Button { public: - typedef void (*ButtonPressCallback)(void); + Button(); + Button(gpio_num_t gpioNum); + + esp_err_t Init(); + esp_err_t Init(gpio_num_t gpioNum); + + inline gpio_num_t GetGPIONum(); + static void TimerCallback(TimerHandle_t xTimer); - void Init(void); - void SetButtonPressCallback(ButtonPressCallback button_callback); + friend void IRAM_ATTR button_isr_handler(void * arg); + +private: + gpio_num_t mGPIONum; + TimerHandle_t mbuttonTimer; // FreeRTOS timers used for debouncing buttons }; + +inline gpio_num_t Button::GetGPIONum() +{ + return mGPIONum; +} diff --git a/examples/lighting-app/esp32/main/include/DeviceCallbacks.h b/examples/lighting-app/esp32/main/include/DeviceCallbacks.h index 05933202b8c22a..e45a3b21f712bf 100644 --- a/examples/lighting-app/esp32/main/include/DeviceCallbacks.h +++ b/examples/lighting-app/esp32/main/include/DeviceCallbacks.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2021-2023 Project CHIP Authors * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,14 +15,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/** - * @file DeviceCallbacks.h - * - * Implementations for the DeviceManager callbacks for this application - * - **/ - #pragma once #include @@ -44,3 +36,10 @@ class AppDeviceCallbacks : public CommonDeviceCallbacks void OnColorControlAttributeChangeCallback(chip::EndpointId endpointId, chip::AttributeId attributeId, uint8_t * value); #endif }; + +class AppDeviceCallbacksDelegate : public DeviceCallbacksDelegate +{ +public: + void OnIPv4ConnectivityEstablished() override; + void OnIPv4ConnectivityLost() override; +}; diff --git a/examples/lighting-app/esp32/main/include/Globals.h b/examples/lighting-app/esp32/main/include/Globals.h new file mode 100644 index 00000000000000..c26aa66edc7f7d --- /dev/null +++ b/examples/lighting-app/esp32/main/include/Globals.h @@ -0,0 +1,23 @@ +/* + * + * Copyright (c) 2020-2023 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 "WiFiWidget.h" + +extern WiFiWidget wifiLED; diff --git a/examples/lighting-app/esp32/main/include/LEDWidget.h b/examples/lighting-app/esp32/main/include/LEDWidget.h index c390d63ac1024f..a230ae3451353e 100644 --- a/examples/lighting-app/esp32/main/include/LEDWidget.h +++ b/examples/lighting-app/esp32/main/include/LEDWidget.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2021-2023 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. @@ -43,6 +43,11 @@ class LEDWidget uint8_t GetLevel(void); bool IsTurnedOn(void); +#if CONFIG_DEVICE_TYPE_M5STACK + // binds this LED to a virtual LED on a screen + void SetVLED(int id1); +#endif + private: bool mState; uint8_t mBrightness; @@ -55,5 +60,9 @@ class LEDWidget gpio_num_t mGPIONum; #endif +#if CONFIG_DEVICE_TYPE_M5STACK + int mVirtualLEDIndex = -1; +#endif + void DoSet(void); }; diff --git a/examples/lighting-app/esp32/main/include/QRCodeScreen.h b/examples/lighting-app/esp32/main/include/QRCodeScreen.h new file mode 100644 index 00000000000000..f82ad33d8e35b2 --- /dev/null +++ b/examples/lighting-app/esp32/main/include/QRCodeScreen.h @@ -0,0 +1,42 @@ +/* + * + * Copyright (c) 2020-2023 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 "Screen.h" +#include "ScreenManager.h" + +#if CONFIG_HAVE_DISPLAY + +#include +#include + +class QRCodeScreen : public Screen +{ + std::vector qrCode; + std::string title; + +public: + QRCodeScreen(std::string text, std::string title = "QR Code"); + + virtual std::string GetTitle() { return title; } + + virtual void Display(); +}; + +#endif // CONFIG_HAVE_DISPLAY diff --git a/examples/lighting-app/esp32/main/include/StatusScreen.h b/examples/lighting-app/esp32/main/include/StatusScreen.h new file mode 100644 index 00000000000000..3aa537ebf0b9ba --- /dev/null +++ b/examples/lighting-app/esp32/main/include/StatusScreen.h @@ -0,0 +1,38 @@ +/* + * + * Copyright (c) 2022-2023 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 "ListScreen.h" +#include "ScreenManager.h" + +#if CONFIG_HAVE_DISPLAY + +#include +#include + +class StatusScreen : public ListScreen +{ + +public: + StatusScreen(); + + virtual ~StatusScreen() {} +}; + +#endif // CONFIG_HAVE_DISPLAY diff --git a/examples/lighting-app/esp32/main/include/WiFiWidget.h b/examples/lighting-app/esp32/main/include/WiFiWidget.h new file mode 100644 index 00000000000000..cbc128c5ddfca9 --- /dev/null +++ b/examples/lighting-app/esp32/main/include/WiFiWidget.h @@ -0,0 +1,36 @@ +/* + * + * Copyright (c) 2020-2023 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 "Display.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +class WiFiWidget +{ +public: + void Init(); + void Set(bool state); + void SetVLED(int id); + +private: + int mVLED; + bool mState; +}; diff --git a/examples/lighting-app/esp32/main/main.cpp b/examples/lighting-app/esp32/main/main.cpp index 7e872e8f78b0f9..0d0244b7e00059 100644 --- a/examples/lighting-app/esp32/main/main.cpp +++ b/examples/lighting-app/esp32/main/main.cpp @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2021-2023 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. @@ -46,6 +46,8 @@ #include "Rpc.h" #endif +#include "DeviceWithDisplay.h" + #if CONFIG_ENABLE_ESP32_DEVICE_INFO_PROVIDER #include #else @@ -60,6 +62,7 @@ using namespace ::chip::DeviceLayer; static const char * TAG = "light-app"; static AppDeviceCallbacks EchoCallbacks; +static AppDeviceCallbacksDelegate sAppDeviceCallbacksDelegate; namespace { #if CONFIG_ENABLE_ESP32_FACTORY_DATA_PROVIDER @@ -78,6 +81,7 @@ static void InitServer(intptr_t context) // Print QR Code URL PrintOnboardingCodes(chip::RendezvousInformationFlags(CONFIG_RENDEZVOUS_MODE)); + DeviceCallbacksDelegate::Instance().SetAppDelegate(&sAppDeviceCallbacksDelegate); Esp32AppServer::Init(); // Init ZCL Data Model and CHIP App Server AND Initialize device attestation config } diff --git a/examples/lighting-app/esp32/sdkconfig_m5stack.defaults b/examples/lighting-app/esp32/sdkconfig_m5stack.defaults new file mode 100644 index 00000000000000..3f70ee3bfe1c46 --- /dev/null +++ b/examples/lighting-app/esp32/sdkconfig_m5stack.defaults @@ -0,0 +1,64 @@ +# +# Copyright (c) 2021-2023 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. +# +# Description: +# Some useful defaults for the demo app configuration. +# +CONFIG_IDF_TARGET="esp32" +CONFIG_IDF_TARGET_ESP32=y +CONFIG_DEVICE_TYPE_M5STACK=y + +# Default to 921600 baud when flashing and monitoring device +CONFIG_ESPTOOLPY_BAUD_921600B=y +CONFIG_ESPTOOLPY_BAUD=921600 +CONFIG_ESPTOOLPY_COMPRESSED=y +CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y +CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 + +#enable BT +CONFIG_BT_ENABLED=y +CONFIG_BT_NIMBLE_ENABLED=y + +#disable BT connection reattempt +CONFIG_BT_NIMBLE_ENABLE_CONN_REATTEMPT=n + +#enable lwip ipv6 autoconfig +CONFIG_LWIP_IPV6_AUTOCONFIG=y + +#enable debug shell +CONFIG_ENABLE_CHIP_SHELL=y + +# Use a custom partition table +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_FILENAME="partitions.csv" + +#enable lwIP route hooks +CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT=y +CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT=y + +# Main task needs a bit more stack than the default +# default is 3584, bump this up to 5k. +CONFIG_ESP_MAIN_TASK_STACK_SIZE=5120 + +# Serial Flasher config +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y +CONFIG_ESPTOOLPY_FLASHSIZE="4MB" + +# Disable softap support by default +CONFIG_ESP_WIFI_SOFTAP_SUPPORT=n +# This example uses the older version of RMT driver to work with both +# idf-v4.4.3 and idf-v5.0, so supressing the warnings by setting below option +CONFIG_RMT_SUPPRESS_DEPRECATE_WARN=y diff --git a/scripts/build/builders/esp32.py b/scripts/build/builders/esp32.py index f9b50927dd41ab..9c7f62915686d2 100644 --- a/scripts/build/builders/esp32.py +++ b/scripts/build/builders/esp32.py @@ -1,4 +1,4 @@ -# Copyright (c) 2021 Project CHIP Authors +# Copyright (c) 2021-2023 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. @@ -126,6 +126,7 @@ def DefaultsFileName(board: Esp32Board, app: Esp32App, enable_rpcs: bool): specific_apps = { Esp32App.ALL_CLUSTERS, Esp32App.ALL_CLUSTERS_MINIMAL, + Esp32App.LIGHT, Esp32App.OTA_REQUESTOR, } if app in specific_apps: