diff --git a/ESP32-C3_Table-Lamp/.devcontainer/Dockerfile b/ESP32-C3_Table-Lamp/.devcontainer/Dockerfile new file mode 100644 index 000000000..8d7b92d61 --- /dev/null +++ b/ESP32-C3_Table-Lamp/.devcontainer/Dockerfile @@ -0,0 +1,47 @@ +FROM espressif/idf + +ARG DEBIAN_FRONTEND=nointeractive +ARG CONTAINER_USER=esp +ARG USER_UID=1050 +ARG USER_GID=$USER_UID + +RUN apt-get update \ + && apt install -y -q \ + cmake \ + git \ + libglib2.0-0 \ + libnuma1 \ + libpixman-1-0 \ + && rm -rf /var/lib/apt/lists/* + +# QEMU +ENV QEMU_REL=esp_develop_8.2.0_20240122 +ENV QEMU_SHA256=e7c72ef5705ad1444d391711088c8717fc89f42e9bf6d1487f9c2a326b8cfa83 +ENV QEMU_DIST=qemu-xtensa-softmmu-${QEMU_REL}-x86_64-linux-gnu.tar.xz +ENV QEMU_URL=https://github.com/espressif/qemu/releases/download/esp-develop-8.2.0-20240122/${QEMU_DIST} + +ENV LC_ALL=C.UTF-8 +ENV LANG=C.UTF-8 + +RUN wget --no-verbose ${QEMU_URL} \ + && echo "${QEMU_SHA256} *${QEMU_DIST}" | sha256sum --check --strict - \ + && tar -xf $QEMU_DIST -C /opt \ + && rm ${QEMU_DIST} + +ENV PATH=/opt/qemu/bin:${PATH} + +RUN groupadd --gid $USER_GID $CONTAINER_USER \ + && adduser --uid $USER_UID --gid $USER_GID --disabled-password --gecos "" ${CONTAINER_USER} \ + && usermod -a -G root $CONTAINER_USER && usermod -a -G dialout $CONTAINER_USER + +RUN chmod -R 775 /opt/esp/python_env/ + +USER ${CONTAINER_USER} +ENV USER=${CONTAINER_USER} +WORKDIR /home/${CONTAINER_USER} + +RUN echo "source /opt/esp/idf/export.sh > /dev/null 2>&1" >> ~/.bashrc + +ENTRYPOINT [ "/opt/esp/entrypoint.sh" ] + +CMD ["/bin/bash", "-c"] \ No newline at end of file diff --git a/ESP32-C3_Table-Lamp/.devcontainer/devcontainer.json b/ESP32-C3_Table-Lamp/.devcontainer/devcontainer.json new file mode 100644 index 000000000..09d3b422a --- /dev/null +++ b/ESP32-C3_Table-Lamp/.devcontainer/devcontainer.json @@ -0,0 +1,36 @@ +{ + "name": "ESP-IDF QEMU", + "build": { + "dockerfile": "Dockerfile" + }, + "customizations": { + "vscode": { + "settings": { + "terminal.integrated.defaultProfile.linux": "bash", + "idf.espIdfPath": "/opt/esp/idf", + "idf.customExtraPaths": "", + "idf.pythonBinPath": "/opt/esp/python_env/idf5.4_py3.12_env/bin/python", + "idf.toolsPath": "/opt/esp", + "idf.gitPath": "/usr/bin/git" + }, + "extensions": [ + "espressif.esp-idf-extension" + ] + }, + "codespaces": { + "settings": { + "terminal.integrated.defaultProfile.linux": "bash", + "idf.espIdfPath": "/opt/esp/idf", + "idf.customExtraPaths": "", + "idf.pythonBinPath": "/opt/esp/python_env/idf5.4_py3.12_env/bin/python", + "idf.toolsPath": "/opt/esp", + "idf.gitPath": "/usr/bin/git" + }, + "extensions": [ + "espressif.esp-idf-extension", + "espressif.esp-idf-web" + ] + } + }, + "runArgs": ["--privileged"] +} \ No newline at end of file diff --git a/ESP32-C3_Table-Lamp/.vscode/c_cpp_properties.json b/ESP32-C3_Table-Lamp/.vscode/c_cpp_properties.json new file mode 100644 index 000000000..898498cab --- /dev/null +++ b/ESP32-C3_Table-Lamp/.vscode/c_cpp_properties.json @@ -0,0 +1,23 @@ +{ + "configurations": [ + { + "name": "ESP-IDF", + "compilerPath": "${config:idf.toolsPathWin}\\tools\\xtensa-esp-elf\\esp-13.2.0_20230928\\xtensa-esp-elf\\bin\\xtensa-esp32-elf-gcc.exe", + "compileCommands": "${config:idf.buildPath}/compile_commands.json", + "includePath": [ + "${config:idf.espIdfPath}/components/**", + "${config:idf.espIdfPathWin}/components/**", + "${workspaceFolder}/**" + ], + "browse": { + "path": [ + "${config:idf.espIdfPath}/components", + "${config:idf.espIdfPathWin}/components", + "${workspaceFolder}" + ], + "limitSymbolsToIncludedHeaders": true + } + } + ], + "version": 4 +} diff --git a/ESP32-C3_Table-Lamp/.vscode/launch.json b/ESP32-C3_Table-Lamp/.vscode/launch.json new file mode 100644 index 000000000..2511a38aa --- /dev/null +++ b/ESP32-C3_Table-Lamp/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "gdbtarget", + "request": "attach", + "name": "Eclipse CDT GDB Adapter" + }, + { + "type": "espidf", + "name": "Launch", + "request": "launch" + } + ] +} \ No newline at end of file diff --git a/ESP32-C3_Table-Lamp/.vscode/settings.json b/ESP32-C3_Table-Lamp/.vscode/settings.json new file mode 100644 index 000000000..a82b4f848 --- /dev/null +++ b/ESP32-C3_Table-Lamp/.vscode/settings.json @@ -0,0 +1,18 @@ +{ + "C_Cpp.intelliSenseEngine": "default", + "idf.adapterTargetName": "esp32", + "idf.customExtraPaths": "c:\\Users\\alex\\.espressif\\tools\\tools\\xtensa-esp-elf-gdb\\14.2_20240403\\xtensa-esp-elf-gdb\\bin;c:\\Users\\alex\\.espressif\\tools\\tools\\riscv32-esp-elf-gdb\\14.2_20240403\\riscv32-esp-elf-gdb\\bin;c:\\Users\\alex\\.espressif\\tools\\tools\\xtensa-esp-elf\\esp-13.2.0_20230928\\xtensa-esp-elf\\bin;c:\\Users\\alex\\.espressif\\tools\\tools\\riscv32-esp-elf\\esp-13.2.0_20230928\\riscv32-esp-elf\\bin;c:\\Users\\alex\\.espressif\\tools\\tools\\esp32ulp-elf\\2.35_20220830\\esp32ulp-elf\\bin;c:\\Users\\alex\\.espressif\\tools\\tools\\cmake\\3.24.0\\bin;c:\\Users\\alex\\.espressif\\tools\\tools\\openocd-esp32\\v0.12.0-esp32-20240318\\openocd-esp32\\bin;c:\\Users\\alex\\.espressif\\tools\\tools\\ninja\\1.11.1;c:\\Users\\alex\\.espressif\\tools\\tools\\idf-exe\\1.0.3;c:\\Users\\alex\\.espressif\\tools\\tools\\ccache\\4.8\\ccache-4.8-windows-x86_64;c:\\Users\\alex\\.espressif\\tools\\tools\\dfu-util\\0.11\\dfu-util-0.11-win64;c:\\Users\\alex\\.espressif\\tools\\tools\\esp-rom-elfs\\20230320", + "idf.customExtraVars": { + "OPENOCD_SCRIPTS": "c:\\Users\\alex\\.espressif\\tools\\tools\\openocd-esp32\\v0.12.0-esp32-20240318/openocd-esp32/share/openocd/scripts", + "IDF_CCACHE_ENABLE": "1", + "ESP_ROM_ELF_DIR": "c:\\Users\\alex\\.espressif\\tools\\tools\\esp-rom-elfs\\20230320/" + }, + "idf.espIdfPathWin": "C:\\Users\\alex\\esp\\v5.2.2\\esp-idf", + "idf.espAdfPathWin": "C:\\Users\\alex\\.espressif\\esp-adf", + "idf.openOcdConfigs": [ + "board/esp32-wrover-kit-3.3v.cfg" + ], + "idf.portWin": "COM27", + "idf.pythonBinPathWin": "c:\\Users\\alex\\.espressif\\tools\\python_env\\idf5.2_py3.11_env\\Scripts\\python.exe", + "idf.toolsPathWin": "c:\\Users\\alex\\.espressif\\tools" +} diff --git a/ESP32-C3_Table-Lamp/.vscode/tasks.json b/ESP32-C3_Table-Lamp/.vscode/tasks.json new file mode 100644 index 000000000..1dc791585 --- /dev/null +++ b/ESP32-C3_Table-Lamp/.vscode/tasks.json @@ -0,0 +1,259 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Build - Build project", + "type": "shell", + "command": "${config:idf.pythonBinPath} ${config:idf.espIdfPath}/tools/idf.py build", + "windows": { + "command": "${config:idf.pythonBinPathWin} ${config:idf.espIdfPathWin}\\tools\\idf.py build", + "options": { + "env": { + "PATH": "${env:PATH};${config:idf.customExtraPaths}" + } + } + }, + "options": { + "env": { + "PATH": "${env:PATH}:${config:idf.customExtraPaths}" + } + }, + "problemMatcher": [ + { + "owner": "cpp", + "fileLocation": [ + "autoDetect", + "${workspaceFolder}" + ], + "pattern": { + "regexp": "^(.*?):(\\d+):(\\d*):?\\s+(?:fatal\\s+)?(warning|error):\\s+(.*)$", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + } + } + ], + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "label": "Set ESP-IDF Target", + "type": "shell", + "command": "${command:espIdf.setTarget}", + "problemMatcher": { + "owner": "cpp", + "fileLocation": [ + "autoDetect", + "${workspaceFolder}" + ], + "pattern": { + "regexp": "^(.*?):(\\d+):(\\d*):?\\s+(?:fatal\\s+)?(warning|error):\\s+(.*)$", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + } + } + }, + { + "label": "Clean - Clean the project", + "type": "shell", + "command": "${config:idf.pythonBinPath} ${config:idf.espIdfPath}/tools/idf.py fullclean", + "windows": { + "command": "${config:idf.pythonBinPathWin} ${config:idf.espIdfPathWin}\\tools\\idf.py fullclean", + "options": { + "env": { + "PATH": "${env:PATH};${config:idf.customExtraPaths}" + } + } + }, + "options": { + "env": { + "PATH": "${env:PATH}:${config:idf.customExtraPaths}" + } + }, + "problemMatcher": [ + { + "owner": "cpp", + "fileLocation": [ + "autoDetect", + "${workspaceFolder}" + ], + "pattern": { + "regexp": "^(.*?):(\\d+):(\\d*):?\\s+(?:fatal\\s+)?(warning|error):\\s+(.*)$", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + } + } + ] + }, + { + "label": "Flash - Flash the device", + "type": "shell", + "command": "${config:idf.pythonBinPath} ${config:idf.espIdfPath}/tools/idf.py -p ${config:idf.port} -b ${config:idf.flashBaudRate} flash", + "windows": { + "command": "${config:idf.pythonBinPathWin} ${config:idf.espIdfPathWin}\\tools\\idf.py flash -p ${config:idf.portWin} -b ${config:idf.flashBaudRate}", + "options": { + "env": { + "PATH": "${env:PATH};${config:idf.customExtraPaths}" + } + } + }, + "options": { + "env": { + "PATH": "${env:PATH}:${config:idf.customExtraPaths}" + } + }, + "problemMatcher": [ + { + "owner": "cpp", + "fileLocation": [ + "autoDetect", + "${workspaceFolder}" + ], + "pattern": { + "regexp": "^(.*?):(\\d+):(\\d*):?\\s+(?:fatal\\s+)?(warning|error):\\s+(.*)$", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + } + } + ] + }, + { + "label": "Monitor: Start the monitor", + "type": "shell", + "command": "${config:idf.pythonBinPath} ${config:idf.espIdfPath}/tools/idf.py -p ${config:idf.port} monitor", + "windows": { + "command": "${config:idf.pythonBinPathWin} ${config:idf.espIdfPathWin}\\tools\\idf.py -p ${config:idf.portWin} monitor", + "options": { + "env": { + "PATH": "${env:PATH};${config:idf.customExtraPaths}" + } + } + }, + "options": { + "env": { + "PATH": "${env:PATH}:${config:idf.customExtraPaths}" + } + }, + "problemMatcher": [ + { + "owner": "cpp", + "fileLocation": [ + "autoDetect", + "${workspaceFolder}" + ], + "pattern": { + "regexp": "^(.*?):(\\d+):(\\d*):?\\s+(?:fatal\\s+)?(warning|error):\\s+(.*)$", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + } + } + ], + "dependsOn": "Flash - Flash the device" + }, + { + "label": "OpenOCD: Start openOCD", + "type": "shell", + "presentation": { + "echo": true, + "reveal": "never", + "focus": false, + "panel": "new" + }, + "command": "openocd -s ${command:espIdf.getOpenOcdScriptValue} ${command:espIdf.getOpenOcdConfigs}", + "windows": { + "command": "openocd.exe -s ${command:espIdf.getOpenOcdScriptValue} ${command:espIdf.getOpenOcdConfigs}", + "options": { + "env": { + "PATH": "${env:PATH};${config:idf.customExtraPaths}" + } + } + }, + "options": { + "env": { + "PATH": "${env:PATH}:${config:idf.customExtraPaths}" + } + }, + "problemMatcher": { + "owner": "cpp", + "fileLocation": [ + "autoDetect", + "${workspaceFolder}" + ], + "pattern": { + "regexp": "^(.*?):(\\d+):(\\d*):?\\s+(?:fatal\\s+)?(warning|error):\\s+(.*)$", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + } + } + }, + { + "label": "adapter", + "type": "shell", + "command": "${config:idf.pythonBinPath}", + "isBackground": true, + "options": { + "env": { + "PATH": "${env:PATH}:${config:idf.customExtraPaths}", + "PYTHONPATH": "${command:espIdf.getExtensionPath}/esp_debug_adapter/debug_adapter" + } + }, + "problemMatcher": { + "background": { + "beginsPattern": "\bDEBUG_ADAPTER_STARTED\b", + "endsPattern": "DEBUG_ADAPTER_READY2CONNECT", + "activeOnStart": true + }, + "pattern": { + "regexp": "(\\d+)-(\\d+)-(\\d+)\\s(\\d+):(\\d+):(\\d+),(\\d+)\\s-(.+)\\s(ERROR)", + "file": 8, + "line": 2, + "column": 3, + "severity": 4, + "message": 9 + } + }, + "args": [ + "${command:espIdf.getExtensionPath}/esp_debug_adapter/debug_adapter_main.py", + "-e", + "${workspaceFolder}/build/${command:espIdf.getProjectName}.elf", + "-s", + "$OPENOCD_SCRIPTS", + "-dn", + "esp32", + "-om", + "connect_to_instance", + "-t", + "xtensa-esp32-elf-" + + ], + "windows": { + "command": "${config:idf.pythonBinPathWin}", + "options": { + "env": { + "PATH": "${env:PATH};${config:idf.customExtraPaths}", + "PYTHONPATH": "${command:espIdf.getExtensionPath}/esp_debug_adapter/debug_adapter" + } + } + } + } + ] +} \ No newline at end of file diff --git a/ESP32-C3_Table-Lamp/CMakeLists.txt b/ESP32-C3_Table-Lamp/CMakeLists.txt new file mode 100644 index 000000000..c734a2efa --- /dev/null +++ b/ESP32-C3_Table-Lamp/CMakeLists.txt @@ -0,0 +1,16 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +if(DEFINED ENV{RMAKER_PATH}) + set(RMAKER_PATH $ENV{RMAKER_PATH}) +else() + set(RMAKER_PATH ${CMAKE_CURRENT_LIST_DIR}/../..) +endif(DEFINED ENV{RMAKER_PATH}) + +# Add RainMaker components and other common application components +set(EXTRA_COMPONENT_DIRS ${RMAKER_PATH}/components/esp-insights/components ${RMAKER_PATH}/components ${RMAKER_PATH}/examples/common) + +set(PROJECT_VER "1.0") +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(ESP32-C3_Table-Lamp) diff --git a/ESP32-C3_Table-Lamp/Makefile b/ESP32-C3_Table-Lamp/Makefile new file mode 100644 index 000000000..a65c6568d --- /dev/null +++ b/ESP32-C3_Table-Lamp/Makefile @@ -0,0 +1,12 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := switch +PROJECT_VER := 1.0 + +# Add RainMaker components and other common application components +EXTRA_COMPONENT_DIRS += $(PROJECT_PATH)/../../components $(PROJECT_PATH)/../common + +include $(IDF_PATH)/make/project.mk diff --git a/ESP32-C3_Table-Lamp/README.md b/ESP32-C3_Table-Lamp/README.md new file mode 100644 index 000000000..800861971 --- /dev/null +++ b/ESP32-C3_Table-Lamp/README.md @@ -0,0 +1,24 @@ +# Switch Example + +## Build and Flash firmware + +Follow the ESP RainMaker Documentation [Get Started](https://rainmaker.espressif.com/docs/get-started.html) section to build and flash this firmware. Just note the path of this example. + +## What to expect in this example? + +- This example uses the BOOT button and RGB LED on the ESP32-S2-Saola-1/ESP32-C3-DevKitC board to demonstrate a switch. +- The LED state (green color) indicates the state of the switch. +- Pressing the BOOT button will toggle the state of the switch and hence the LED. This will also reflect on the phone app. +- Toggling the button on the phone app should toggle the LED on your board, and also print messages like these on the ESP32-S2 monitor: + +``` +I (16073) app_main: Received value = true for Switch - power +``` + +### LED not working? + +The ESP32-S2-Saola-1 board has the RGB LED connected to GPIO 18. However, a few earlier boards may have it on GPIO 17. Please use `CONFIG_WS2812_LED_GPIO` to set the appropriate value. + +### Reset to Factory + +Press and hold the BOOT button for more than 3 seconds to reset the board to factory defaults. You will have to provision the board again to use it. diff --git a/ESP32-C3_Table-Lamp/main/CMakeLists.txt b/ESP32-C3_Table-Lamp/main/CMakeLists.txt new file mode 100644 index 000000000..81b0f302c --- /dev/null +++ b/ESP32-C3_Table-Lamp/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS ./app_driver.c ./app_main.c + INCLUDE_DIRS ".") diff --git a/ESP32-C3_Table-Lamp/main/Kconfig.projbuild b/ESP32-C3_Table-Lamp/main/Kconfig.projbuild new file mode 100644 index 000000000..bdf738c36 --- /dev/null +++ b/ESP32-C3_Table-Lamp/main/Kconfig.projbuild @@ -0,0 +1,26 @@ +menu "Example Configuration" + + config EXAMPLE_BOARD_BUTTON_GPIO + int "Boot Button GPIO" + default 9 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C6 + default 0 + help + GPIO number on which the "Boot" button is connected. This is generally used + by the application for custom operations like toggling states, resetting to defaults, etc. + + config EXAMPLE_ENABLE_TEST_NOTIFICATIONS + bool "Test Notifications" + default n + help + Enable this option to test mobile push notifications. When enabled, turning on the switch using + push button will trigger a parameter notification {"Switch":{"Power":true}} and turning off will + trigger an alert "Switch was turned off". + + config EXAMPLE_OUTPUT_GPIO + int "Output GPIO" + default 19 + help + This is an output GPIO that will be connected to a relay or other driver circuit in most cases. + If the power changes, this GPIO output level will also change. + +endmenu diff --git a/ESP32-C3_Table-Lamp/main/app_driver.c b/ESP32-C3_Table-Lamp/main/app_driver.c new file mode 100644 index 000000000..e62e99afb --- /dev/null +++ b/ESP32-C3_Table-Lamp/main/app_driver.c @@ -0,0 +1,116 @@ +/* Switch demo implementation using button and RGB LED + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include + +#include +#include +#include + +#include +#include +#include "app_priv.h" + +/* This is the button that is used for toggling the power */ +#define BUTTON_GPIO CONFIG_EXAMPLE_BOARD_BUTTON_GPIO +#define BUTTON_ACTIVE_LEVEL 0 + +/* This is the GPIO on which the power will be set */ +#define OUTPUT_GPIO CONFIG_EXAMPLE_OUTPUT_GPIO +static bool g_power_state = DEFAULT_POWER; + +/* These values correspoind to H,S,V = 120,100,10 */ +#define DEFAULT_RED 0 +#define DEFAULT_GREEN 25 +#define DEFAULT_BLUE 0 + +#define WIFI_RESET_BUTTON_TIMEOUT 3 +#define FACTORY_RESET_BUTTON_TIMEOUT 10 + +static void app_indicator_set(bool state) +{ + if (state) { + ws2812_led_set_rgb(DEFAULT_RED, DEFAULT_GREEN, DEFAULT_BLUE); + } else { + ws2812_led_clear(); + } +} + +static void app_indicator_init(void) +{ + ws2812_led_init(); + app_indicator_set(g_power_state); +} +static void push_btn_cb(void *arg) +{ + bool new_state = !g_power_state; + app_driver_set_state(new_state); +#ifdef CONFIG_EXAMPLE_ENABLE_TEST_NOTIFICATIONS + /* This snippet has been added just to demonstrate how the APIs esp_rmaker_param_update_and_notify() + * and esp_rmaker_raise_alert() can be used to trigger push notifications on the phone apps. + * Normally, there should not be a need to use these APIs for such simple operations. Please check + * API documentation for details. + */ + if (new_state) { + esp_rmaker_param_update_and_notify( + esp_rmaker_device_get_param_by_name(switch_device, ESP_RMAKER_DEF_POWER_NAME), + esp_rmaker_bool(new_state)); + } else { + esp_rmaker_param_update_and_report( + esp_rmaker_device_get_param_by_name(switch_device, ESP_RMAKER_DEF_POWER_NAME), + esp_rmaker_bool(new_state)); + esp_rmaker_raise_alert("Switch was turned off"); + } +#else + esp_rmaker_param_update_and_report( + esp_rmaker_device_get_param_by_name(switch_device, ESP_RMAKER_DEF_POWER_NAME), + esp_rmaker_bool(new_state)); +#endif +} + +static void set_power_state(bool target) +{ + gpio_set_level(OUTPUT_GPIO, target); + app_indicator_set(target); +} + +void app_driver_init() +{ + button_handle_t btn_handle = iot_button_create(BUTTON_GPIO, BUTTON_ACTIVE_LEVEL); + if (btn_handle) { + /* Register a callback for a button tap (short press) event */ + iot_button_set_evt_cb(btn_handle, BUTTON_CB_TAP, push_btn_cb, NULL); + /* Register Wi-Fi reset and factory reset functionality on same button */ + app_reset_button_register(btn_handle, WIFI_RESET_BUTTON_TIMEOUT, FACTORY_RESET_BUTTON_TIMEOUT); + } + + /* Configure power */ + gpio_config_t io_conf = { + .mode = GPIO_MODE_OUTPUT, + .pull_up_en = 1, + }; + io_conf.pin_bit_mask = ((uint64_t)1 << OUTPUT_GPIO); + /* Configure the GPIO */ + gpio_config(&io_conf); + app_indicator_init(); +} + +int IRAM_ATTR app_driver_set_state(bool state) +{ + if(g_power_state != state) { + g_power_state = state; + set_power_state(g_power_state); + } + return ESP_OK; +} + +bool app_driver_get_state(void) +{ + return g_power_state; +} diff --git a/ESP32-C3_Table-Lamp/main/app_main.c b/ESP32-C3_Table-Lamp/main/app_main.c new file mode 100644 index 000000000..3a7dcfa1f --- /dev/null +++ b/ESP32-C3_Table-Lamp/main/app_main.c @@ -0,0 +1,255 @@ +/* Switch Example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "app_priv.h" + +static const char *TAG = "app_main"; +esp_rmaker_device_t *switch_device; + +/* Callback to handle commands received from the RainMaker cloud */ +static esp_err_t write_cb(const esp_rmaker_device_t *device, const esp_rmaker_param_t *param, + const esp_rmaker_param_val_t val, void *priv_data, esp_rmaker_write_ctx_t *ctx) +{ + if (ctx) { + ESP_LOGI(TAG, "Received write request via : %s", esp_rmaker_device_cb_src_to_str(ctx->src)); + } + if (strcmp(esp_rmaker_param_get_name(param), ESP_RMAKER_DEF_POWER_NAME) == 0) { + ESP_LOGI(TAG, "Received value = %s for %s - %s", + val.val.b? "true" : "false", esp_rmaker_device_get_name(device), + esp_rmaker_param_get_name(param)); + app_driver_set_state(val.val.b); + esp_rmaker_param_update_and_report(param, val); + } + return ESP_OK; +} +/* Event handler for catching RainMaker events */ +static void event_handler(void* arg, esp_event_base_t event_base, + int32_t event_id, void* event_data) +{ + if (event_base == RMAKER_EVENT) { + switch (event_id) { + case RMAKER_EVENT_INIT_DONE: + ESP_LOGI(TAG, "RainMaker Initialised."); + break; + case RMAKER_EVENT_CLAIM_STARTED: + ESP_LOGI(TAG, "RainMaker Claim Started."); + break; + case RMAKER_EVENT_CLAIM_SUCCESSFUL: + ESP_LOGI(TAG, "RainMaker Claim Successful."); + break; + case RMAKER_EVENT_CLAIM_FAILED: + ESP_LOGI(TAG, "RainMaker Claim Failed."); + break; + case RMAKER_EVENT_LOCAL_CTRL_STARTED: + ESP_LOGI(TAG, "Local Control Started."); + break; + case RMAKER_EVENT_LOCAL_CTRL_STOPPED: + ESP_LOGI(TAG, "Local Control Stopped."); + break; + default: + ESP_LOGW(TAG, "Unhandled RainMaker Event: %"PRIi32, event_id); + } + } else if (event_base == RMAKER_COMMON_EVENT) { + switch (event_id) { + case RMAKER_EVENT_REBOOT: + ESP_LOGI(TAG, "Rebooting in %d seconds.", *((uint8_t *)event_data)); + break; + case RMAKER_EVENT_WIFI_RESET: + ESP_LOGI(TAG, "Wi-Fi credentials reset."); + break; + case RMAKER_EVENT_FACTORY_RESET: + ESP_LOGI(TAG, "Node reset to factory defaults."); + break; + case RMAKER_MQTT_EVENT_CONNECTED: + ESP_LOGI(TAG, "MQTT Connected."); + break; + case RMAKER_MQTT_EVENT_DISCONNECTED: + ESP_LOGI(TAG, "MQTT Disconnected."); + break; + case RMAKER_MQTT_EVENT_PUBLISHED: + ESP_LOGI(TAG, "MQTT Published. Msg id: %d.", *((int *)event_data)); + break; + default: + ESP_LOGW(TAG, "Unhandled RainMaker Common Event: %"PRIi32, event_id); + } + } else if (event_base == APP_WIFI_EVENT) { + switch (event_id) { + case APP_WIFI_EVENT_QR_DISPLAY: + ESP_LOGI(TAG, "Provisioning QR : %s", (char *)event_data); + break; + case APP_WIFI_EVENT_PROV_TIMEOUT: + ESP_LOGI(TAG, "Provisioning Timed Out. Please reboot."); + break; + case APP_WIFI_EVENT_PROV_RESTART: + ESP_LOGI(TAG, "Provisioning has restarted due to failures."); + break; + default: + ESP_LOGW(TAG, "Unhandled App Wi-Fi Event: %"PRIi32, event_id); + break; + } + } else if (event_base == RMAKER_OTA_EVENT) { + switch(event_id) { + case RMAKER_OTA_EVENT_STARTING: + ESP_LOGI(TAG, "Starting OTA."); + break; + case RMAKER_OTA_EVENT_IN_PROGRESS: + ESP_LOGI(TAG, "OTA is in progress."); + break; + case RMAKER_OTA_EVENT_SUCCESSFUL: + ESP_LOGI(TAG, "OTA successful."); + break; + case RMAKER_OTA_EVENT_FAILED: + ESP_LOGI(TAG, "OTA Failed."); + break; + case RMAKER_OTA_EVENT_REJECTED: + ESP_LOGI(TAG, "OTA Rejected."); + break; + case RMAKER_OTA_EVENT_DELAYED: + ESP_LOGI(TAG, "OTA Delayed."); + break; + case RMAKER_OTA_EVENT_REQ_FOR_REBOOT: + ESP_LOGI(TAG, "Firmware image downloaded. Please reboot your device to apply the upgrade."); + break; + default: + ESP_LOGW(TAG, "Unhandled OTA Event: %"PRIi32, event_id); + break; + } + } else { + ESP_LOGW(TAG, "Invalid event received!"); + } +} + +void app_main() +{ + /* Initialize Application specific hardware drivers and + * set initial state. + */ + esp_rmaker_console_init(); + app_driver_init(); + app_driver_set_state(DEFAULT_POWER); + + /* Initialize NVS. */ + esp_err_t err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + err = nvs_flash_init(); + } + ESP_ERROR_CHECK( err ); + + /* Initialize Wi-Fi. Note that, this should be called before esp_rmaker_node_init() + */ + app_wifi_init(); + + /* Register an event handler to catch RainMaker events */ + ESP_ERROR_CHECK(esp_event_handler_register(RMAKER_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL)); + ESP_ERROR_CHECK(esp_event_handler_register(RMAKER_COMMON_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL)); + ESP_ERROR_CHECK(esp_event_handler_register(APP_WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL)); + ESP_ERROR_CHECK(esp_event_handler_register(RMAKER_OTA_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL)); + + /* Initialize the ESP RainMaker Agent. + * Note that this should be called after app_wifi_init() but before app_wifi_start() + * */ + esp_rmaker_config_t rainmaker_cfg = { + .enable_time_sync = false, + }; + esp_rmaker_node_t *node = esp_rmaker_node_init(&rainmaker_cfg, "ESP RainMaker Device", "Switch"); + if (!node) { + ESP_LOGE(TAG, "Could not initialise node. Aborting!!!"); + vTaskDelay(5000/portTICK_PERIOD_MS); + abort(); + } + + /* Create a Switch device. + * You can optionally use the helper API esp_rmaker_switch_device_create() to + * avoid writing code for adding the name and power parameters. + */ + switch_device = esp_rmaker_device_create("Switch", ESP_RMAKER_DEVICE_SWITCH, NULL); + + /* Add the write callback for the device. We aren't registering any read callback yet as + * it is for future use. + */ + esp_rmaker_device_add_cb(switch_device, write_cb, NULL); + + /* Add the standard name parameter (type: esp.param.name), which allows setting a persistent, + * user friendly custom name from the phone apps. All devices are recommended to have this + * parameter. + */ + esp_rmaker_device_add_param(switch_device, esp_rmaker_name_param_create(ESP_RMAKER_DEF_NAME_PARAM, "Switch")); + + /* Add the standard power parameter (type: esp.param.power), which adds a boolean param + * with a toggle switch ui-type. + */ + esp_rmaker_param_t *power_param = esp_rmaker_power_param_create(ESP_RMAKER_DEF_POWER_NAME, DEFAULT_POWER); + esp_rmaker_device_add_param(switch_device, power_param); + + /* Assign the power parameter as the primary, so that it can be controlled from the + * home screen of the phone apps. + */ + esp_rmaker_device_assign_primary_param(switch_device, power_param); + + /* Add this switch device to the node */ + esp_rmaker_node_add_device(node, switch_device); + + /* Enable OTA */ + esp_rmaker_ota_enable_default(); + + /* Enable timezone service which will be require for setting appropriate timezone + * from the phone apps for scheduling to work correctly. + * For more information on the various ways of setting timezone, please check + * https://rainmaker.espressif.com/docs/time-service.html. + */ + esp_rmaker_timezone_service_enable(); + + /* Enable scheduling. */ + esp_rmaker_schedule_enable(); + + /* Enable Scenes */ + esp_rmaker_scenes_enable(); + + /* Enable Insights. Requires CONFIG_ESP_INSIGHTS_ENABLED=y */ + app_insights_enable(); + + /* Start the ESP RainMaker Agent */ + esp_rmaker_start(); + + err = app_wifi_set_custom_mfg_data(MGF_DATA_DEVICE_TYPE_SWITCH, MFG_DATA_DEVICE_SUBTYPE_SWITCH); + /* Start the Wi-Fi. + * If the node is provisioned, it will start connection attempts, + * else, it will start Wi-Fi provisioning. The function will return + * after a connection has been successfully established + */ + err = app_wifi_start(POP_TYPE_RANDOM); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Could not start Wifi. Aborting!!!"); + vTaskDelay(5000/portTICK_PERIOD_MS); + abort(); + } +} diff --git a/ESP32-C3_Table-Lamp/main/app_priv.h b/ESP32-C3_Table-Lamp/main/app_priv.h new file mode 100644 index 000000000..8c8b5ab4c --- /dev/null +++ b/ESP32-C3_Table-Lamp/main/app_priv.h @@ -0,0 +1,16 @@ +/* + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ +#pragma once +#include +#include + +#define DEFAULT_POWER true +extern esp_rmaker_device_t *switch_device; +void app_driver_init(void); +int app_driver_set_state(bool state); +bool app_driver_get_state(void); diff --git a/ESP32-C3_Table-Lamp/main/component.mk b/ESP32-C3_Table-Lamp/main/component.mk new file mode 100644 index 000000000..a98f634ea --- /dev/null +++ b/ESP32-C3_Table-Lamp/main/component.mk @@ -0,0 +1,4 @@ +# +# "main" pseudo-component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) diff --git a/ESP32-C3_Table-Lamp/partitions.csv b/ESP32-C3_Table-Lamp/partitions.csv new file mode 100644 index 000000000..5c9166b2a --- /dev/null +++ b/ESP32-C3_Table-Lamp/partitions.csv @@ -0,0 +1,10 @@ +# Name, Type, SubType, Offset, Size, Flags +# Note: Firmware partition offset needs to be 64K aligned, initial 36K (9 sectors) are reserved for bootloader and partition table +esp_secure_cert, 0x3F, , 0xD000, 0x2000, encrypted +nvs_key, data, nvs_keys, 0xF000, 0x1000, encrypted +nvs, data, nvs, 0x10000, 0x6000, +otadata, data, ota, , 0x2000 +phy_init, data, phy, , 0x1000, +ota_0, app, ota_0, 0x20000, 1600K, +ota_1, app, ota_1, , 1600K, +fctry, data, nvs, 0x340000, 0x6000 diff --git a/ESP32-C3_Table-Lamp/partitions_4mb_optimised.csv b/ESP32-C3_Table-Lamp/partitions_4mb_optimised.csv new file mode 100644 index 000000000..6c337712b --- /dev/null +++ b/ESP32-C3_Table-Lamp/partitions_4mb_optimised.csv @@ -0,0 +1,11 @@ +# Name, Type, SubType, Offset, Size, Flags +# Note: Firmware partition offset needs to be 64K aligned, initial 36K (9 sectors) are reserved for bootloader and partition table +esp_secure_cert, 0x3F, , 0xD000, 0x2000, encrypted +nvs_key, data, nvs_keys, 0xF000, 0x1000, encrypted +nvs, data, nvs, 0x10000, 0x6000, +otadata, data, ota, , 0x2000 +phy_init, data, phy, , 0x1000, +ota_0, app, ota_0, 0x20000, 0x1E0000, +ota_1, app, ota_1, 0x200000, 0x1E0000, +reserved, 0x06, , 0x3E0000, 0x1A000, +fctry, data, nvs, 0x3FA000, 0x6000 diff --git a/ESP32-C3_Table-Lamp/sdkconfig.defaults b/ESP32-C3_Table-Lamp/sdkconfig.defaults new file mode 100644 index 000000000..100a77f34 --- /dev/null +++ b/ESP32-C3_Table-Lamp/sdkconfig.defaults @@ -0,0 +1,33 @@ +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y +CONFIG_PARTITION_TABLE_SINGLE_APP= +CONFIG_PARTITION_TABLE_TWO_OTA= +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" +CONFIG_PARTITION_TABLE_FILENAME="partitions.csv" +CONFIG_PARTITION_TABLE_OFFSET=0x8000 +CONFIG_PARTITION_TABLE_MD5=y + +# mbedtls +CONFIG_MBEDTLS_DYNAMIC_BUFFER=y +CONFIG_MBEDTLS_DYNAMIC_FREE_PEER_CERT=y +CONFIG_MBEDTLS_DYNAMIC_FREE_CONFIG_DATA=y +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN=y + +# For BLE Provisioning using NimBLE stack (Not applicable for ESP32-S2) +CONFIG_BT_ENABLED=y +CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y +CONFIG_BT_NIMBLE_ENABLED=y + +# Temporary Fix for Timer Overflows +CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=3120 + +# For additional security on reset to factory +CONFIG_ESP_RMAKER_USER_ID_CHECK=y + +# Secure Local Control +CONFIG_ESP_RMAKER_LOCAL_CTRL_AUTO_ENABLE=y +#CONFIG_ESP_RMAKER_LOCAL_CTRL_ENABLE is deprecated but will continue to work +CONFIG_ESP_RMAKER_LOCAL_CTRL_SECURITY_1=y + +# Application Rollback +CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE=y diff --git a/ESP32-C3_Table-Lamp/sdkconfig.defaults.esp32 b/ESP32-C3_Table-Lamp/sdkconfig.defaults.esp32 new file mode 100644 index 000000000..c308d0703 --- /dev/null +++ b/ESP32-C3_Table-Lamp/sdkconfig.defaults.esp32 @@ -0,0 +1 @@ +CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y diff --git a/ESP32-C3_Table-Lamp/sdkconfig.defaults.esp32c6 b/ESP32-C3_Table-Lamp/sdkconfig.defaults.esp32c6 new file mode 100644 index 000000000..0caf64ced --- /dev/null +++ b/ESP32-C3_Table-Lamp/sdkconfig.defaults.esp32c6 @@ -0,0 +1,10 @@ +# +# Use partition table which makes use of flash to the fullest +# Can be used for other platforms as well. But please keep in mind that fctry partition address is +# different than default, and the new address needs to be specified to `rainmaker.py claim` +# +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_4mb_optimised.csv" + +# To accomodate security features +CONFIG_PARTITION_TABLE_OFFSET=0xc000