ESP32-Rainmaker-Matter_Switch

This commit is contained in:
Alexander 2024-07-16 20:50:57 -04:00
parent 86908a766e
commit b0c20fb8d3
21 changed files with 998 additions and 0 deletions

View File

@ -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"]

View File

@ -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"]
}

View File

@ -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
}

View File

@ -0,0 +1,15 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "gdbtarget",
"request": "attach",
"name": "Eclipse CDT GDB Adapter"
},
{
"type": "espidf",
"name": "Launch",
"request": "launch"
}
]
}

View File

@ -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": "COM29",
"idf.pythonBinPathWin": "c:\\Users\\alex\\.espressif\\tools\\python_env\\idf5.2_py3.11_env\\Scripts\\python.exe",
"idf.toolsPathWin": "c:\\Users\\alex\\.espressif\\tools"
}

View File

@ -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"
}
}
}
}
]
}

View File

@ -0,0 +1,62 @@
# 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})
if(NOT DEFINED ENV{ESP_MATTER_PATH})
message(FATAL_ERROR "Please set ESP_MATTER_PATH to the path of esp-matter repo")
endif(NOT DEFINED ENV{ESP_MATTER_PATH})
if(NOT DEFINED ENV{ESP_MATTER_DEVICE_PATH})
if("${IDF_TARGET}" STREQUAL "esp32" OR "${IDF_TARGET}" STREQUAL "")
set(ENV{ESP_MATTER_DEVICE_PATH} $ENV{ESP_MATTER_PATH}/device_hal/device/esp32_devkit_c)
elseif("${IDF_TARGET}" STREQUAL "esp32c3")
set(ENV{ESP_MATTER_DEVICE_PATH} $ENV{ESP_MATTER_PATH}/device_hal/device/esp32c3_devkit_m)
elseif("${IDF_TARGET}" STREQUAL "esp32s3")
set(ENV{ESP_MATTER_DEVICE_PATH} $ENV{ESP_MATTER_PATH}/device_hal/device/esp32s3_devkit_c)
elseif("${IDF_TARGET}" STREQUAL "esp32c6")
set(ENV{ESP_MATTER_DEVICE_PATH} $ENV{ESP_MATTER_PATH}/device_hal/device/esp32c6_devkit_c)
else()
message(FATAL_ERROR "Unsupported IDF_TARGET")
endif()
endif(NOT DEFINED ENV{ESP_MATTER_DEVICE_PATH})
set(ESP_MATTER_PATH $ENV{ESP_MATTER_PATH})
set(MATTER_SDK_PATH ${ESP_MATTER_PATH}/connectedhomeip/connectedhomeip)
# This should be done before using the IDF_TARGET variable.
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
include($ENV{ESP_MATTER_DEVICE_PATH}/esp_matter_device.cmake)
idf_build_set_property(RAINMAKER_ENABLED 1)
set(EXTRA_COMPONENT_DIRS
"${MATTER_SDK_PATH}/config/esp32/components"
"${ESP_MATTER_PATH}/components"
"${ESP_MATTER_PATH}/device_hal/device"
"${ESP_MATTER_PATH}/examples/common"
"${RMAKER_PATH}/examples/common/app_insights"
"${RMAKER_PATH}/components/esp_rainmaker"
"${RMAKER_PATH}/components/esp_schedule"
"${RMAKER_PATH}/components/json_generator"
"${RMAKER_PATH}/components/json_parser"
"${RMAKER_PATH}/components/rmaker_common"
${extra_components_dirs_append})
# Include insights only for IDF <= v4.4 as it is already included by esp-matter for >= v5.0
if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_LESS_EQUAL "4.4")
list(APPEND EXTRA_COMPONENT_DIRS "${RMAKER_PATH}/components/esp-insights/components")
endif()
project(ESP32-Rainmaker-Switch)
idf_build_set_property(CXX_COMPILE_OPTIONS "-std=gnu++17;-Os;-DCHIP_HAVE_CONFIG_H" APPEND)
idf_build_set_property(C_COMPILE_OPTIONS "-Os" APPEND)
# For RISCV chips, project_include.cmake sets -Wno-format, but does not clear various
# flags that depend on -Wformat
idf_build_set_property(COMPILE_OPTIONS "-Wno-format-nonliteral;-Wno-format-security" APPEND)

View File

@ -0,0 +1,12 @@
# Matter + Rainmaker Switch Example
## What to expect in this example?
- This demonstrates a Matter + RainMaker Switch. Matter is used for commissioning (also known as Wi-Fi provisioning) and local control, whereas RainMaker is used for remote control and OTA upgrades.
- This example uses the BOOT button and RGB LED on the ESP32-C3-DevKitC board to demonstrate a switch.
- To commission the device, scan the QR Code generated by the mfg_tool script using ESP RainMaker app.
- Pressing the BOOT button will send a toggle the power state of switch and send an on/off command to the remote device. This will also reflect on the phone app.
- Toggling the button on the phone app should toggle the LED on your board.
- To test remote control, change the network connection of the mobile.
> Please refer to the [README in the parent folder](../README.md) for instructions.

View File

@ -0,0 +1,9 @@
set(PRIV_REQUIRES_LIST device esp_matter esp_matter_console esp_matter_rainmaker app_reset
esp_rainmaker app_insights)
idf_component_register(SRCS ./app_main.cpp ./app_matter.cpp ./app_driver.cpp
PRIV_INCLUDE_DIRS "."
PRIV_REQUIRES ${PRIV_REQUIRES_LIST})
set_property(TARGET ${COMPONENT_LIB} PROPERTY CXX_STANDARD 17)
target_compile_options(${COMPONENT_LIB} PRIVATE "-DCHIP_HAVE_CONFIG_H")

View File

@ -0,0 +1,59 @@
/*
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 <esp_log.h>
#include <stdlib.h>
#include <string.h>
#include <device.h>
#include <esp_matter.h>
#include <led_driver.h>
#include <esp_rmaker_core.h>
#include <esp_rmaker_standard_params.h>
#include <app_matter.h>
#include <app_priv.h>
static const char *TAG = "app_driver";
extern uint16_t switch_endpoint_id;
static bool g_power = DEFAULT_POWER;
/* Do any conversions/remapping for the actual value here */
esp_err_t app_driver_switch_set_power(led_driver_handle_t handle, bool val)
{
g_power = val;
return led_driver_set_power(handle, val);
}
static void app_driver_button_toggle_cb(void *handle, void *usr_data)
{
ESP_LOGI(TAG, "Toggle button pressed");
app_matter_send_command_binding(!g_power);
}
esp_err_t app_driver_light_set_defaults()
{
return app_driver_switch_set_power((led_driver_handle_t)esp_matter::endpoint::get_priv_data(switch_endpoint_id),
DEFAULT_POWER);
}
app_driver_handle_t app_driver_light_init()
{
/* Initialize led */
led_driver_config_t config = led_driver_get_config();
led_driver_handle_t handle = led_driver_init(&config);
return (app_driver_handle_t)handle;
}
app_driver_handle_t app_driver_button_init(void *user_data)
{
/* Initialize button */
button_config_t config = button_driver_get_config();
button_handle_t handle = iot_button_create(&config);
iot_button_register_cb(handle, BUTTON_PRESS_DOWN, app_driver_button_toggle_cb, user_data);
return (app_driver_handle_t)handle;
}

View File

@ -0,0 +1,114 @@
/*
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 <esp_err.h>
#include <esp_log.h>
#include <nvs_flash.h>
#include <app_priv.h>
#include <app_matter.h>
#include <app_reset.h>
#include <esp_rmaker_core.h>
#include <esp_rmaker_standard_params.h>
#include <esp_rmaker_standard_devices.h>
#include <esp_rmaker_ota.h>
#include <esp_rmaker_schedule.h>
#include <esp_rmaker_scenes.h>
#include <app_insights.h>
static const char *TAG = "app_main";
static app_driver_handle_t switch_handle;
/* 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));
}
const char *param_name = esp_rmaker_param_get_name(param);
if (strcmp(param_name, ESP_RMAKER_DEF_POWER_NAME) == 0) {
app_matter_send_command_binding(val.val.b);
}
return ESP_OK;
}
extern "C" void app_main()
{
/* 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 drivers for light and button */
switch_handle = app_driver_light_init();
app_driver_switch_set_power(switch_handle, DEFAULT_POWER);
app_driver_handle_t button_handle = app_driver_button_init(switch_handle);
app_reset_button_register(button_handle);
/* Initialize matter */
app_matter_init();
app_matter_switch_create(switch_handle);
/* Matter start */
app_matter_start();
/* Initialize the ESP RainMaker Agent.
* Create Lightbulb device and its parameters.
* */
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.");
vTaskDelay(5000 / portTICK_PERIOD_MS);
abort();
}
esp_rmaker_device_t *switch_device = esp_rmaker_switch_device_create(SWITCH_DEVICE_NAME, NULL, DEFAULT_POWER);
esp_rmaker_device_add_cb(switch_device, write_cb, NULL);
esp_rmaker_node_add_device(node, switch_device);
/* Enable OTA */
esp_rmaker_ota_config_t ota_config = {
.server_cert = ESP_RMAKER_OTA_DEFAULT_SERVER_CERT,
};
esp_rmaker_ota_enable(&ota_config, OTA_USING_PARAMS);
/* 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();
/* Pre start */
ESP_ERROR_CHECK(app_matter_pre_rainmaker_start());
/* Start the ESP RainMaker Agent */
esp_rmaker_start();
/* Enable Matter diagnostics console*/
app_matter_enable_matter_console();
}

View File

@ -0,0 +1,171 @@
/*
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 <esp_log.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <nvs_flash.h>
#include <string.h>
#include <led_driver.h>
#include <esp_matter_rainmaker.h>
#include <platform/ESP32/route_hook/ESP32RouteHook.h>
#include <esp_matter_console.h>
#include <app_matter.h>
#include <esp_rmaker_standard_params.h>
#include <esp_rmaker_core.h>
#include <app_priv.h>
using namespace esp_matter;
using namespace esp_matter::attribute;
using namespace esp_matter::cluster;
using namespace esp_matter::endpoint;
using namespace chip::app::Clusters;
static const char *TAG = "app_matter";
uint16_t switch_endpoint_id;
esp_err_t app_matter_send_command_binding(bool power)
{
client::command_handle_t command;
command.cluster_id = OnOff::Id;
if (power == true) {
command.command_id = OnOff::Commands::On::Id;
} else {
command.command_id = OnOff::Commands::Off::Id;
}
lock::chip_stack_lock(portMAX_DELAY);
esp_err_t err = client::cluster_update(switch_endpoint_id, &command);
lock::chip_stack_unlock();
return err;
}
static esp_err_t app_identification_cb(identification::callback_type_t type, uint16_t endpoint_id, uint8_t effect_id,
uint8_t effect_variant, void *priv_data)
{
ESP_LOGI(TAG, "Identification callback: type: %d, effect: %d", type, effect_id);
return ESP_OK;
}
static esp_err_t app_attribute_update_cb(attribute::callback_type_t type, uint16_t endpoint_id, uint32_t cluster_id,
uint32_t attribute_id, esp_matter_attr_val_t *val, void *priv_data)
{
return ESP_OK;
}
static void app_event_cb(const ChipDeviceEvent *event, intptr_t arg)
{
switch (event->Type) {
case chip::DeviceLayer::DeviceEventType::PublicEventTypes::kCommissioningComplete:
ESP_LOGI(TAG, "Commissioning complete");
break;
default:
break;
}
}
esp_err_t app_matter_init()
{
/* Create a Matter node */
node::config_t node_config;
node_t *node = node::create(&node_config, app_attribute_update_cb, app_identification_cb);
/* The node and endpoint handles can be used to create/add other endpoints and clusters. */
if (!node) {
ESP_LOGE(TAG, "Matter node creation failed");
return ESP_FAIL;
}
/* Add custom rainmaker cluster */
return rainmaker::init();
}
static void app_matter_client_command_callback(client::peer_device_t *peer_device, client::command_handle_t *command_handle,
void *priv_data)
{
if (command_handle->cluster_id == OnOff::Id) {
/* RainMaker update */
const esp_rmaker_node_t *node = esp_rmaker_get_node();
esp_rmaker_device_t *device = esp_rmaker_node_get_device_by_name(node, SWITCH_DEVICE_NAME);
esp_rmaker_param_t *param = esp_rmaker_device_get_param_by_name(device, ESP_RMAKER_DEF_POWER_NAME);
if (command_handle->command_id == OnOff::Commands::Off::Id) {
on_off::command::send_off(peer_device, command_handle->endpoint_id);
app_driver_switch_set_power((app_driver_handle_t)priv_data, false);
esp_rmaker_param_update_and_report(param, esp_rmaker_bool(false));
} else if (command_handle->command_id == OnOff::Commands::On::Id) {
on_off::command::send_on(peer_device, command_handle->endpoint_id);
app_driver_switch_set_power((app_driver_handle_t)priv_data, true);
esp_rmaker_param_update_and_report(param, esp_rmaker_bool(true));
} else if (command_handle->command_id == OnOff::Commands::Toggle::Id) {
on_off::command::send_toggle(peer_device, command_handle->endpoint_id);
esp_rmaker_param_val_t *param_val = esp_rmaker_param_get_val(param);
app_driver_switch_set_power((app_driver_handle_t)priv_data, !param_val->val.b);
esp_rmaker_param_update_and_report(param, esp_rmaker_bool(!param_val->val.b));
}
} else if (command_handle->cluster_id == Identify::Id) {
if (((char *)command_handle->command_data)[0] != 1) {
ESP_LOGE(TAG, "Number of parameters error");
return;
}
identify::command::send_identify(peer_device, command_handle->endpoint_id,
strtoul((const char *)(command_handle->command_data) + 1, NULL, 16));
}
}
esp_err_t app_matter_switch_create(app_driver_handle_t driver_handle)
{
node_t *node = node::get();
if (!node) {
ESP_LOGE(TAG, "Matter node not found");
return ESP_FAIL;
}
on_off_switch::config_t switch_config;
endpoint_t *endpoint = on_off_switch::create(node, &switch_config, ENDPOINT_FLAG_NONE, driver_handle);
if (!endpoint) {
ESP_LOGE(TAG, "Matter endpoint creation failed");
return ESP_FAIL;
}
cluster::groups::config_t groups_config;
cluster::groups::create(endpoint, &groups_config, CLUSTER_FLAG_SERVER | CLUSTER_FLAG_CLIENT);
switch_endpoint_id = endpoint::get_id(endpoint);
ESP_LOGI(TAG, "Switch created with endpoint_id %d", switch_endpoint_id);
return ESP_OK;
}
esp_err_t app_matter_pre_rainmaker_start()
{
/* Other initializations for custom rainmaker cluster */
return rainmaker::start();
}
esp_err_t app_matter_start()
{
client::set_command_callback(app_matter_client_command_callback, NULL, NULL);
esp_err_t err = esp_matter::start(app_event_cb);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Matter start failed: %d", err);
}
app_matter_send_command_binding(DEFAULT_POWER);
return err;
}
void app_matter_enable_matter_console()
{
#if CONFIG_ENABLE_CHIP_SHELL
esp_matter::console::diagnostics_register_commands();
esp_matter::console::init();
#else
ESP_LOGI(TAG, "Set CONFIG_ENABLE_CHIP_SHELL to enable Matter Console");
#endif
}

View File

@ -0,0 +1,19 @@
/*
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 <esp_err.h>
#include <app_priv.h>
esp_err_t app_matter_init();
esp_err_t app_matter_switch_create(app_driver_handle_t driver_handle);
esp_err_t app_matter_start();
esp_err_t app_matter_pre_rainmaker_start();
esp_err_t app_matter_send_command_binding(bool power);
void app_matter_enable_matter_console();

View File

@ -0,0 +1,49 @@
/*
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 <esp_err.h>
#include <esp_matter.h>
/** Default attribute values used by Rainmaker during initialization */
#define SWITCH_DEVICE_NAME "Matter Switch"
#define DEFAULT_POWER true
typedef void *app_driver_handle_t;
/** Initialize the light driver
*
* This initializes the light driver associated with the selected board.
*
* @return Handle on success.
* @return NULL in case of failure.
*/
app_driver_handle_t app_driver_light_init();
/** Initialize the button driver
*
* This initializes the button driver associated with the selected board.
*
* @param[in] user_data Custom user data that will be used in button toggle callback.
*
* @return Handle on success.
* @return NULL in case of failure.
*/
app_driver_handle_t app_driver_button_init(void *user_data);
/** Set LED Power
*
* @param[in] handle Pointer to switch driver handle.
* @param[in] power LED power state.
*
* @return ESP_OK on success.
* @return error in case of failure.
*/
esp_err_t app_driver_switch_set_power(app_driver_handle_t handle, bool power);

View File

@ -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, data, nvs, 0x10000, 0x6000,
nvs_keys, data, nvs_keys,, 0x1000, encrypted
otadata, data, ota, , 0x2000
phy_init, data, phy, , 0x1000,
ota_0, app, ota_0, 0x20000, 0x1E0000,
ota_1, app, ota_1, 0x200000, 0x1E0000,
fctry, data, nvs, , 0x6000,
1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: Firmware partition offset needs to be 64K aligned, initial 36K (9 sectors) are reserved for bootloader and partition table
3 esp_secure_cert, 0x3F, ,0xd000, 0x2000, encrypted
4 nvs, data, nvs, 0x10000, 0x6000,
5 nvs_keys, data, nvs_keys,, 0x1000, encrypted
6 otadata, data, ota, , 0x2000
7 phy_init, data, phy, , 0x1000,
8 ota_0, app, ota_0, 0x20000, 0x1E0000,
9 ota_1, app, ota_1, 0x200000, 0x1E0000,
10 fctry, data, nvs, , 0x6000,

View File

@ -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, data, nvs, 0x10000, 0x6000,
nvs_keys, data, nvs_keys,, 0x1000, encrypted
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
1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: Firmware partition offset needs to be 64K aligned, initial 36K (9 sectors) are reserved for bootloader and partition table
3 esp_secure_cert, 0x3F, ,0xd000, 0x2000, encrypted
4 nvs, data, nvs, 0x10000, 0x6000,
5 nvs_keys, data, nvs_keys,, 0x1000, encrypted
6 otadata, data, ota, , 0x2000
7 phy_init, data, phy, , 0x1000,
8 ota_0, app, ota_0, 0x20000, 0x1E0000,
9 ota_1, app, ota_1, 0x200000, 0x1E0000,
10 reserved, 0x06, , 0x3E0000, 0x1A000,
11 fctry, data, nvs, 0x3FA000, 0x6000

View File

@ -0,0 +1,74 @@
# 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
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
# Enable BT
CONFIG_BT_ENABLED=y
CONFIG_BT_NIMBLE_ENABLED=y
# Disable BT connection re-attempts
CONFIG_BT_NIMBLE_ENABLE_CONN_REATTEMPT=n
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
# Enable lwip ipv6 autoconfig
CONFIG_LWIP_IPV6_AUTOCONFIG=y
# Use a custom partition table
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_OFFSET=0xC000
CONFIG_PARTITION_TABLE_MD5=y
# Enable chip shell
CONFIG_ENABLE_CHIP_SHELL=y
# mbedtls
CONFIG_MBEDTLS_DYNAMIC_BUFFER=y
CONFIG_MBEDTLS_DYNAMIC_FREE_PEER_CERT=y
CONFIG_MBEDTLS_DYNAMIC_FREE_CONFIG_DATA=y
# Temporary Fix for Timer Overflows
CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=3120
# Enable lwIP route hooks
CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT=y
CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT=y
# Button
CONFIG_BUTTON_PERIOD_TIME_MS=20
CONFIG_BUTTON_LONG_PRESS_TIME_MS=5000
# Disable softap by default
CONFIG_ESP_WIFI_SOFTAP_SUPPORT=n
# ESP RainMaker
CONFIG_ESP_RMAKER_USER_ID_CHECK=y
CONFIG_ESP_RMAKER_NO_CLAIM=y
CONFIG_ESP_RMAKER_USE_ESP_SECURE_CERT_MGR=y
CONFIG_ESP_RMAKER_READ_NODE_ID_FROM_CERT_CN=y
CONFIG_ESP_RMAKER_DISABLE_USER_MAPPING_PROV=y
# ESP Matter
CONFIG_CHIP_FACTORY_NAMESPACE_PARTITION_LABEL="fctry"
CONFIG_ENABLE_ESP32_FACTORY_DATA_PROVIDER=y
CONFIG_ENABLE_ESP32_DEVICE_INSTANCE_INFO_PROVIDER=y
CONFIG_ENABLE_ESP32_DEVICE_INFO_PROVIDER=y
CONFIG_SEC_CERT_DAC_PROVIDER=y
CONFIG_DEVICE_VENDOR_ID=0x131B
CONFIG_DEVICE_PRODUCT_ID=0x2
CONFIG_ESP_SECURE_CERT_DS_PERIPHERAL=n
# Enable HKDF in mbedtls
CONFIG_MBEDTLS_HKDF_C=y
# Use compact attribute storage mode
CONFIG_ESP_MATTER_NVS_USE_COMPACT_ATTR_STORAGE=y
# Increase LwIP IPv6 address number to 6 (MAX_FABRIC + 1)
# unique local addresses for fabrics(MAX_FABRIC), a link local address(1)
CONFIG_LWIP_IPV6_NUM_ADDRESSES=6

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB