diff --git a/.codespellrc b/.codespellrc index 756f7e9503b..d3b9b45cb1e 100644 --- a/.codespellrc +++ b/.codespellrc @@ -1,7 +1,7 @@ [codespell] # Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/spell-check/.codespellrc # In the event of a false positive, add the problematic word, in all lowercase, to a comma-separated list here: -ignore-words-list = ba,licence,ot,dout,als,exten +ignore-words-list = ba,licence,ot,dout,als,exten,emac skip = ./.git,./.licenses,__pycache__,.clang-format,.codespellrc,.editorconfig,.flake8,.prettierignore,.yamllint.yml,.gitignore,boards.txt,platform.txt,programmers.txt builtin = clear,informal,en-GB_to_en-US check-filenames = diff --git a/.github/ISSUE_TEMPLATE/Feature-request.yml b/.github/ISSUE_TEMPLATE/Feature-request.yml index 0788288036c..8849a407a39 100644 --- a/.github/ISSUE_TEMPLATE/Feature-request.yml +++ b/.github/ISSUE_TEMPLATE/Feature-request.yml @@ -5,6 +5,7 @@ body: - type: markdown attributes: value: | + * Please note that we can only process feature requests reported in English to ensure effective communication and support. Feature requests written in other languages will be closed, with a request to rewrite them in English. * We welcome any ideas or feature requests! It is helpful if you can explain exactly why the feature would be useful. * There are usually some outstanding feature requests in the [existing issues list](https://github.com/espressif/arduino-esp32/issues?q=is%3Aopen+is%3Aissue+label%3A%22Type%3A+Feature+request%22), feel free to add comments to them. * If you would like to contribute, please read the [contributions guide](https://docs.espressif.com/projects/arduino-esp32/en/latest/contributing.html). diff --git a/.github/ISSUE_TEMPLATE/Issue-report.yml b/.github/ISSUE_TEMPLATE/Issue-report.yml index a902184f06b..9dba5e0ca8f 100644 --- a/.github/ISSUE_TEMPLATE/Issue-report.yml +++ b/.github/ISSUE_TEMPLATE/Issue-report.yml @@ -5,6 +5,7 @@ body: - type: markdown attributes: value: | + * Please note that we can only process issues reported in English to ensure effective communication and support. Issues written in other languages will be closed, with a request to rewrite them in English. * Before reporting a new issue please check and search in [List of existing issues](https://github.com/espressif/arduino-esp32/issues?q=is%3Aissue) * Please check [Online Documentation](https://docs.espressif.com/projects/arduino-esp32/en/latest/index.html) * Take a look on [Troubleshooting guide](https://docs.espressif.com/projects/arduino-esp32/en/latest/troubleshooting.html) @@ -39,8 +40,11 @@ body: label: Version description: What version of Arduino ESP32 are you running? If possible, consider updating to the latest version. options: - - latest master (checkout manually) + - latest stable Release (if not listed below) - latest development Release Candidate (RC-X) + - latest master (checkout manually) + - v3.2.0 + - v3.1.3 - v3.1.2 - v3.1.1 - v3.1.0 diff --git a/.github/scripts/on-push-idf.sh b/.github/scripts/on-push-idf.sh new file mode 100644 index 00000000000..72e7c7f574e --- /dev/null +++ b/.github/scripts/on-push-idf.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +set -e + +CHECK_REQUIREMENTS="./components/arduino-esp32/.github/scripts/sketch_utils.sh check_requirements" + +# Export IDF environment +. ${IDF_PATH}/export.sh + +# Find all examples in ./components/arduino-esp32/idf_component_examples +idf_component_examples=$(find ./components/arduino-esp32/idf_component_examples -mindepth 1 -maxdepth 1 -type d) + +for example in $idf_component_examples; do + if [ -f "$example"/ci.json ]; then + # If the target is listed as false, skip the sketch. Otherwise, include it. + is_target=$(jq -r --arg target "$IDF_TARGET" '.targets[$target]' "$example"/ci.json) + if [[ "$is_target" == "false" ]]; then + printf "\n\033[93mSkipping %s for target %s\033[0m\n\n" "$example" "$IDF_TARGET" + continue + fi + fi + + idf.py -C "$example" set-target "$IDF_TARGET" + + has_requirements=$(${CHECK_REQUIREMENTS} "$example" "$example/sdkconfig") + if [ "$has_requirements" -eq 0 ]; then + printf "\n\033[93m%s does not meet the requirements for %s. Skipping...\033[0m\n\n" "$example" "$IDF_TARGET" + continue + fi + + printf "\n\033[95mBuilding %s\033[0m\n\n" "$example" + idf.py -C "$example" -DEXTRA_COMPONENT_DIRS="$PWD/components" build +done diff --git a/.github/scripts/on-release.sh b/.github/scripts/on-release.sh index 242cee93d0b..dafbf3d6a1c 100755 --- a/.github/scripts/on-release.sh +++ b/.github/scripts/on-release.sh @@ -35,6 +35,8 @@ PACKAGE_JSON_MERGE="$GITHUB_WORKSPACE/.github/scripts/merge_packages.py" PACKAGE_JSON_TEMPLATE="$GITHUB_WORKSPACE/package/package_esp32_index.template.json" PACKAGE_JSON_DEV="package_esp32_dev_index.json" PACKAGE_JSON_REL="package_esp32_index.json" +PACKAGE_JSON_DEV_CN="package_esp32_dev_index_cn.json" +PACKAGE_JSON_REL_CN="package_esp32_index_cn.json" echo "Event: $GITHUB_EVENT_NAME, Repo: $GITHUB_REPOSITORY, Path: $GITHUB_WORKSPACE, Ref: $GITHUB_REF" echo "Action: $action, Branch: $RELEASE_BRANCH, ID: $RELEASE_ID" @@ -339,9 +341,13 @@ jq_arg=".packages[0].platforms[0].version = \"$RELEASE_TAG\" | \ # Generate package JSONs echo "Generating $PACKAGE_JSON_DEV ..." cat "$PACKAGE_JSON_TEMPLATE" | jq "$jq_arg" > "$OUTPUT_DIR/$PACKAGE_JSON_DEV" +# On MacOS the sed command won't skip the first match. Use gsed instead. +sed '0,/github\.com\/espressif\//!s|github\.com/espressif/|dl.espressif.cn/github_assets/espressif/|g' "$OUTPUT_DIR/$PACKAGE_JSON_DEV" > "$OUTPUT_DIR/$PACKAGE_JSON_DEV_CN" if [ "$RELEASE_PRE" == "false" ]; then echo "Generating $PACKAGE_JSON_REL ..." cat "$PACKAGE_JSON_TEMPLATE" | jq "$jq_arg" > "$OUTPUT_DIR/$PACKAGE_JSON_REL" + # On MacOS the sed command won't skip the first match. Use gsed instead. + sed '0,/github\.com\/espressif\//!s|github\.com/espressif/|dl.espressif.cn/github_assets/espressif/|g' "$OUTPUT_DIR/$PACKAGE_JSON_REL" > "$OUTPUT_DIR/$PACKAGE_JSON_REL_CN" fi # Figure out the last release or pre-release @@ -373,12 +379,14 @@ echo if [ -n "$prev_any_release" ] && [ "$prev_any_release" != "null" ]; then echo "Merging with JSON from $prev_any_release ..." merge_package_json "$prev_any_release/$PACKAGE_JSON_DEV" "$OUTPUT_DIR/$PACKAGE_JSON_DEV" + merge_package_json "$prev_any_release/$PACKAGE_JSON_DEV_CN" "$OUTPUT_DIR/$PACKAGE_JSON_DEV_CN" fi if [ "$RELEASE_PRE" == "false" ]; then if [ -n "$prev_release" ] && [ "$prev_release" != "null" ]; then echo "Merging with JSON from $prev_release ..." merge_package_json "$prev_release/$PACKAGE_JSON_REL" "$OUTPUT_DIR/$PACKAGE_JSON_REL" + merge_package_json "$prev_release/$PACKAGE_JSON_REL_CN" "$OUTPUT_DIR/$PACKAGE_JSON_REL_CN" fi fi @@ -388,6 +396,8 @@ echo "Installing arduino-cli ..." export PATH="/home/runner/bin:$PATH" source "${SCRIPTS_DIR}/install-arduino-cli.sh" +# For the Chinese mirror, we can't test the package JSONs as the Chinese mirror might not be updated yet. + echo "Testing $PACKAGE_JSON_DEV install ..." echo "Installing esp32 ..." @@ -445,11 +455,15 @@ fi echo "Uploading $PACKAGE_JSON_DEV ..." echo "Download URL: $(git_safe_upload_asset "$OUTPUT_DIR/$PACKAGE_JSON_DEV")" echo "Pages URL: $(git_safe_upload_to_pages "$PACKAGE_JSON_DEV" "$OUTPUT_DIR/$PACKAGE_JSON_DEV")" +echo "Download CN URL: $(git_safe_upload_asset "$OUTPUT_DIR/$PACKAGE_JSON_DEV_CN")" +echo "Pages CN URL: $(git_safe_upload_to_pages "$PACKAGE_JSON_DEV" "$OUTPUT_DIR/$PACKAGE_JSON_DEV_CN")" echo if [ "$RELEASE_PRE" == "false" ]; then echo "Uploading $PACKAGE_JSON_REL ..." echo "Download URL: $(git_safe_upload_asset "$OUTPUT_DIR/$PACKAGE_JSON_REL")" echo "Pages URL: $(git_safe_upload_to_pages "$PACKAGE_JSON_REL" "$OUTPUT_DIR/$PACKAGE_JSON_REL")" + echo "Download CN URL: $(git_safe_upload_asset "$OUTPUT_DIR/$PACKAGE_JSON_REL_CN")" + echo "Pages CN URL: $(git_safe_upload_to_pages "$PACKAGE_JSON_REL" "$OUTPUT_DIR/$PACKAGE_JSON_REL_CN")" echo fi diff --git a/.github/scripts/sketch_utils.sh b/.github/scripts/sketch_utils.sh index 00d7d1bc232..befea255e0b 100755 --- a/.github/scripts/sketch_utils.sh +++ b/.github/scripts/sketch_utils.sh @@ -16,7 +16,7 @@ function check_requirements { # check_requirements local requirements_or if [ ! -f "$sdkconfig_path" ] || [ ! -f "$sketchdir/ci.json" ]; then - echo "ERROR: sdkconfig or ci.json not found" 1>&2 + echo "WARNING: sdkconfig or ci.json not found. Assuming requirements are met." 1>&2 # Return 1 on error to force the sketch to be built and fail. This way the # CI will fail and the user will know that the sketch has a problem. else @@ -244,7 +244,7 @@ function build_sketch { # build_sketch [ext build_dir="$ARDUINO_BUILD_DIR" elif [ "$len" -eq 1 ]; then # build_dir="$sketchdir/build" - build_dir="$HOME/.arduino/tests/$sketchname/build.tmp" + build_dir="$HOME/.arduino/tests/$target/$sketchname/build.tmp" fi output_file="$HOME/.arduino/cli_compile_output.txt" @@ -254,7 +254,7 @@ function build_sketch { # build_sketch [ext for i in $(seq 0 $((len - 1))); do if [ "$len" -ne 1 ]; then # build_dir="$sketchdir/build$i" - build_dir="$HOME/.arduino/tests/$sketchname/build$i.tmp" + build_dir="$HOME/.arduino/tests/$target/$sketchname/build$i.tmp" fi rm -rf "$build_dir" mkdir -p "$build_dir" diff --git a/.github/scripts/tests_run.sh b/.github/scripts/tests_run.sh index 274666c8a44..1c4bee79742 100755 --- a/.github/scripts/tests_run.sh +++ b/.github/scripts/tests_run.sh @@ -27,9 +27,9 @@ function run_test { fi if [ "$len" -eq 1 ]; then - sdkconfig_path="$HOME/.arduino/tests/$sketchname/build.tmp/sdkconfig" + sdkconfig_path="$HOME/.arduino/tests/$target/$sketchname/build.tmp/sdkconfig" else - sdkconfig_path="$HOME/.arduino/tests/$sketchname/build0.tmp/sdkconfig" + sdkconfig_path="$HOME/.arduino/tests/$target/$sketchname/build0.tmp/sdkconfig" fi if [ -f "$sketchdir"/ci.json ]; then @@ -45,7 +45,7 @@ function run_test { fi if [ ! -f "$sdkconfig_path" ]; then - printf "\033[93mSketch %s not built\nMight be due to missing target requirements or build failure\033[0m\n" "$sketchname" + printf "\033[93mSketch %s build not found in %s\nMight be due to missing target requirements or build failure\033[0m\n" "$(dirname "$sdkconfig_path")" "$sketchname" printf "\n\n\n" return 0 fi @@ -60,7 +60,7 @@ function run_test { if [ "$len" -eq 1 ]; then # build_dir="$sketchdir/build" - build_dir="$HOME/.arduino/tests/$sketchname/build.tmp" + build_dir="$HOME/.arduino/tests/$target/$sketchname/build.tmp" report_file="$sketchdir/$target/$sketchname.xml" fi @@ -83,7 +83,7 @@ function run_test { if [ "$len" -ne 1 ]; then # build_dir="$sketchdir/build$i" - build_dir="$HOME/.arduino/tests/$sketchname/build$i.tmp" + build_dir="$HOME/.arduino/tests/$target/$sketchname/build$i.tmp" report_file="$sketchdir/$target/$sketchname$i.xml" fi diff --git a/.github/workflows/allboards.yml b/.github/workflows/allboards.yml index 8c4dadcd03e..6910ad05d3f 100644 --- a/.github/workflows/allboards.yml +++ b/.github/workflows/allboards.yml @@ -15,7 +15,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ github.event.client_payload.branch }} @@ -32,13 +32,13 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ github.event.client_payload.branch }} - run: npm install - name: Setup jq - uses: dcarbone/install-jq-action@v1.0.1 + uses: dcarbone/install-jq-action@e397bd87438d72198f81efd21f876461183d383a # v3.0.1 - id: set-test-chunks name: Set Chunks @@ -64,7 +64,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ github.event.client_payload.branch }} @@ -74,7 +74,7 @@ jobs: FQBN: ${{ toJSON(matrix.chunk) }} - name: Compile sketch - uses: P-R-O-C-H-Y/compile-sketches@main + uses: P-R-O-C-H-Y/compile-sketches@a62f069b92dc8f5053da4ac439ea6d1950cf6379 # main with: platforms: | ${{ env.REPOSITORY }} diff --git a/.github/workflows/boards.yml b/.github/workflows/boards.yml index a51c794cfb4..287e97219c4 100644 --- a/.github/workflows/boards.yml +++ b/.github/workflows/boards.yml @@ -22,10 +22,10 @@ jobs: steps: # This step makes the contents of the repository available to the workflow - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Setup jq - uses: dcarbone/install-jq-action@v1.0.1 + uses: dcarbone/install-jq-action@e397bd87438d72198f81efd21f876461183d383a # v3.0.1 - name: Get board name run: bash .github/scripts/find_new_boards.sh ${{ github.repository }} ${{github.base_ref}} @@ -47,7 +47,7 @@ jobs: steps: # This step makes the contents of the repository available to the workflow - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Check if build.board is uppercase run: | @@ -60,7 +60,7 @@ jobs: fi - name: Get libs cache - uses: actions/cache@v4 + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: key: libs-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('package/package_esp32_index.template.json', 'tools/get.py') }} path: | @@ -73,7 +73,7 @@ jobs: ./tools/xtensa-* - name: Compile sketch - uses: P-R-O-C-H-Y/compile-sketches@main + uses: P-R-O-C-H-Y/compile-sketches@a62f069b92dc8f5053da4ac439ea6d1950cf6379 # main with: platforms: | ${{ env.REPOSITORY }} diff --git a/.github/workflows/build_py_tools.yml b/.github/workflows/build_py_tools.yml index d4dfca9c8d1..bbb36589c84 100644 --- a/.github/workflows/build_py_tools.yml +++ b/.github/workflows/build_py_tools.yml @@ -18,7 +18,7 @@ jobs: all_changed_files: ${{ steps.verify-changed-files.outputs.all_changed_files }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 2 ref: ${{ github.event.pull_request.head.ref }} @@ -30,7 +30,7 @@ jobs: echo "Make sure you are using a branch inside the repository and not a fork." - name: Verify Python Tools Changed - uses: tj-actions/changed-files@v41 + uses: tj-actions/changed-files@2f7c5bfce28377bc069a65ba478de0a74aa0ca32 # v46.0.1 id: verify-changed-files with: fetch_depth: "2" @@ -40,6 +40,7 @@ jobs: tools/espota.py tools/gen_esp32part.py tools/gen_insights_package.py + - name: List all changed files shell: bash run: | @@ -88,25 +89,30 @@ jobs: for tool in ${{ env.CHANGED_TOOLS }}; do echo "tool $tool was changed" done + - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: token: ${{ secrets.TOOLS_UPLOAD_PAT }} ref: ${{ github.event.pull_request.head.ref }} + - name: Set up Python 3.8 - uses: actions/setup-python@master + uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.0.4 with: python-version: 3.8 + - name: Install dependencies run: | python -m pip install --upgrade pip pip install pyinstaller requests + - name: Build with PyInstaller shell: bash run: | for tool in ${{ env.CHANGED_TOOLS }}; do pyinstaller --distpath ./${{ env.DISTPATH }} -F --icon=.github/pytools/espressif.ico tools/$tool.py done + - name: Sign binaries if: matrix.os == 'windows-latest' env: @@ -119,12 +125,14 @@ jobs: { ./.github/pytools/Sign-File.ps1 -Path ./${{ env.DISTPATH }}/$node.exe } + - name: Test binaries shell: bash run: | for tool in ${{ env.CHANGED_TOOLS }}; do ./${{ env.DISTPATH }}/$tool${{ matrix.EXTEN }} -h done + - name: Push binary to tools if: matrix.os == 'windows-latest' env: @@ -135,8 +143,9 @@ jobs: cp -f ./${{ env.DISTPATH }}/$tool.exe tools/$tool.exe done bash .github/scripts/upload_py_tools.sh "${{ env.CHANGED_TOOLS }}" + - name: Archive artifact - uses: actions/upload-artifact@master + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: ${{ env.DISTPATH }} path: ${{ env.DISTPATH }} diff --git a/.github/workflows/dangerjs.yml b/.github/workflows/dangerjs.yml index 8fa7b737317..13bc907566b 100644 --- a/.github/workflows/dangerjs.yml +++ b/.github/workflows/dangerjs.yml @@ -12,12 +12,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out PR head - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ github.event.pull_request.head.sha }} - name: DangerJS pull request linter - uses: espressif/shared-github-dangerjs@v1 + uses: espressif/shared-github-dangerjs@fb17367fd3e8ff7412603b8e946d9b19ffdb2d7f # v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: diff --git a/.github/workflows/docs_build.yml b/.github/workflows/docs_build.yml index d2f12e1f7b5..d9b9f160228 100644 --- a/.github/workflows/docs_build.yml +++ b/.github/workflows/docs_build.yml @@ -21,14 +21,16 @@ jobs: run: shell: bash steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: submodules: true - - uses: actions/setup-python@v5 + + - uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.0.4 with: cache-dependency-path: docs/requirements.txt cache: "pip" python-version: "3.10" + - name: Build run: | sudo apt update @@ -38,8 +40,9 @@ jobs: cd ./docs PATH=/home/runner/.local/bin:$PATH pip3 install -r requirements.txt --prefer-binary PATH=/home/runner/.local/bin:$PATH SPHINXOPTS="-W" build-docs -l en + - name: Archive Docs - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: docs path: docs diff --git a/.github/workflows/docs_deploy.yml b/.github/workflows/docs_deploy.yml index b558fd21aa5..9f45e35aef8 100644 --- a/.github/workflows/docs_deploy.yml +++ b/.github/workflows/docs_deploy.yml @@ -26,14 +26,17 @@ jobs: run: | echo "Release workflow failed. Exiting..." exit 1 - - uses: actions/checkout@v4 + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: submodules: true - - uses: actions/setup-python@v5 + + - uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.0.4 with: cache-dependency-path: docs/requirements.txt cache: "pip" python-version: "3.10" + - name: Deploy Documentation env: # Deploy to production server diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index 47480e8239a..60795229eff 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -15,7 +15,9 @@ jobs: name: Build GitHub Pages runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - name: Copy Files env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/lib.json b/.github/workflows/lib.json index 9b528e4cc43..5b93d6689ef 100644 --- a/.github/workflows/lib.json +++ b/.github/workflows/lib.json @@ -23,16 +23,44 @@ ] }, { - "source-url": "https://github.com/me-no-dev/ESPAsyncWebServer.git", + "source-url": "https://github.com/ESP32Async/ESPAsyncWebServer.git", "required-libs": [ - {"source-url": "https://github.com/me-no-dev/AsyncTCP.git"} + {"source-url": "https://github.com/ESP32Async/AsyncTCP.git"} ], "exclude_targets": [], "sketch_path": [ + "~/Arduino/libraries/ESPAsyncWebServer/examples/Auth/Auth.ino", + "~/Arduino/libraries/ESPAsyncWebServer/examples/CORS/CORS.ino", "~/Arduino/libraries/ESPAsyncWebServer/examples/CaptivePortal/CaptivePortal.ino", - "~/Arduino/libraries/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/ESP_AsyncFSBrowser.ino", - "~/Arduino/libraries/ESPAsyncWebServer/examples/regex_patterns/regex_patterns.ino", - "~/Arduino/libraries/ESPAsyncWebServer/examples/simple_server/simple_server.ino" + "~/Arduino/libraries/ESPAsyncWebServer/examples/CatchAllHandler/CatchAllHandler.ino", + "~/Arduino/libraries/ESPAsyncWebServer/examples/ChunkResponse/ChunkResponse.ino", + "~/Arduino/libraries/ESPAsyncWebServer/examples/ChunkRetryResponse/ChunkRetryResponse.ino", + "~/Arduino/libraries/ESPAsyncWebServer/examples/EndBegin/EndBegin.ino", + "~/Arduino/libraries/ESPAsyncWebServer/examples/Filters/Filters.ino", + "~/Arduino/libraries/ESPAsyncWebServer/examples/FlashResponse/FlashResponse.ino", + "~/Arduino/libraries/ESPAsyncWebServer/examples/HeaderManipulation/HeaderManipulation.ino", + "~/Arduino/libraries/ESPAsyncWebServer/examples/Headers/Headers.ino", + "~/Arduino/libraries/ESPAsyncWebServer/examples/Json/Json.ino", + "~/Arduino/libraries/ESPAsyncWebServer/examples/Logging/Logging.ino", + "~/Arduino/libraries/ESPAsyncWebServer/examples/MessagePack/MessagePack.ino", + "~/Arduino/libraries/ESPAsyncWebServer/examples/Middleware/Middleware.ino", + "~/Arduino/libraries/ESPAsyncWebServer/examples/Params/Params.ino", + "~/Arduino/libraries/ESPAsyncWebServer/examples/PartitionDownloader/PartitionDownloader.ino", + "~/Arduino/libraries/ESPAsyncWebServer/examples/PerfTests/PerfTests.ino", + "~/Arduino/libraries/ESPAsyncWebServer/examples/RateLimit/RateLimit.ino", + "~/Arduino/libraries/ESPAsyncWebServer/examples/Redirect/Redirect.ino", + "~/Arduino/libraries/ESPAsyncWebServer/examples/RequestContinuation/RequestContinuation.ino", + "~/Arduino/libraries/ESPAsyncWebServer/examples/RequestContinuationComplete/RequestContinuationComplete.ino", + "~/Arduino/libraries/ESPAsyncWebServer/examples/ResumableDownload/ResumableDownload.ino", + "~/Arduino/libraries/ESPAsyncWebServer/examples/Rewrite/Rewrite.ino", + "~/Arduino/libraries/ESPAsyncWebServer/examples/ServerSentEvents/ServerSentEvents.ino", + "~/Arduino/libraries/ESPAsyncWebServer/examples/ServerState/ServerState.ino", + "~/Arduino/libraries/ESPAsyncWebServer/examples/SkipServerMiddleware/SkipServerMiddleware.ino", + "~/Arduino/libraries/ESPAsyncWebServer/examples/SlowChunkResponse/SlowChunkResponse.ino", + "~/Arduino/libraries/ESPAsyncWebServer/examples/StaticFile/StaticFile.ino", + "~/Arduino/libraries/ESPAsyncWebServer/examples/Templates/Templates.ino", + "~/Arduino/libraries/ESPAsyncWebServer/examples/Upload/Upload.ino", + "~/Arduino/libraries/ESPAsyncWebServer/examples/WebSocket/WebSocket.ino" ] }, { diff --git a/.github/workflows/lib.yml b/.github/workflows/lib.yml index 1197308c921..0cb50842e5d 100644 --- a/.github/workflows/lib.yml +++ b/.github/workflows/lib.yml @@ -62,10 +62,10 @@ jobs: steps: # This step makes the contents of the repository available to the workflow - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Compile sketch - uses: P-R-O-C-H-Y/compile-sketches@main + uses: P-R-O-C-H-Y/compile-sketches@a62f069b92dc8f5053da4ac439ea6d1950cf6379 # main with: platforms: | ${{ env.REPOSITORY }} @@ -80,7 +80,7 @@ jobs: - --warnings="all" - name: Upload artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: ${{ env.SKETCHES_REPORTS_ARTIFACT_NAME }}-${{ matrix.target }} path: ${{ env.SKETCHES_REPORTS_PATH }} @@ -92,7 +92,7 @@ jobs: steps: # Check out repository - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: token: ${{ env.GITHUB_TOKEN }} fetch-depth: "0" @@ -102,14 +102,14 @@ jobs: # This step is needed to get the size data produced by the compile jobs - name: Download sketches reports artifact - uses: actions/download-artifact@v4 + uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1 with: pattern: ${{ env.SKETCHES_REPORTS_ARTIFACT_NAME }}-* merge-multiple: true path: ${{ env.SKETCHES_REPORTS_PATH }} - name: Report results - uses: P-R-O-C-H-Y/report-size-deltas@main + uses: P-R-O-C-H-Y/report-size-deltas@4a79caa6dcc3579024293638b97156106edc588e # main with: sketches-reports-source: ${{ env.SKETCHES_REPORTS_PATH }} destination-file: ${{ env.RESULT_LIBRARY_TEST_FILE }} @@ -136,8 +136,9 @@ jobs: env: PR_NUM: ${{ github.event.number }} run: echo $PR_NUM > pr_num.txt + - name: Upload PR number - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: pr_number path: ./pr_num.txt diff --git a/.github/workflows/pre-commit-status.yml b/.github/workflows/pre-commit-status.yml index d0060668476..c7be9f8d352 100644 --- a/.github/workflows/pre-commit-status.yml +++ b/.github/workflows/pre-commit-status.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Report success - uses: actions/github-script@v7 + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 with: script: | const owner = '${{ github.repository_owner }}'; @@ -43,7 +43,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Report pending - uses: actions/github-script@v7 + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 with: script: | const owner = '${{ github.repository_owner }}'; diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index dc009e445da..a3b858dd0fb 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -23,7 +23,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout latest commit - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 2 @@ -34,7 +34,7 @@ jobs: GH_TOKEN: ${{ github.token }} - name: Set up Python 3 - uses: actions/setup-python@v5 + uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.0.4 with: cache-dependency-path: tools/pre-commit/requirements.txt cache: "pip" @@ -46,7 +46,7 @@ jobs: echo "PY_HASH=$(python -VV | sha256sum | cut -d' ' -f1)" >> $GITHUB_ENV - name: Restore pre-commit cache - uses: actions/cache/restore@v4 + uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 id: restore-cache with: path: | @@ -58,13 +58,13 @@ jobs: - name: Get changed files id: changed-files - uses: tj-actions/changed-files@v42.0.2 + uses: tj-actions/changed-files@2f7c5bfce28377bc069a65ba478de0a74aa0ca32 # v46.0.1 - name: Run pre-commit hooks in changed files run: pre-commit run --color=always --show-diff-on-failure --files ${{ steps.changed-files.outputs.all_changed_files }} - name: Save pre-commit cache - uses: actions/cache/save@v4 + uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 if: ${{ always() && steps.restore-cache.outputs.cache-hit != 'true' }} continue-on-error: true with: @@ -73,7 +73,7 @@ jobs: key: ${{ steps.restore-cache.outputs.cache-primary-key }} - name: Push changes using pre-commit-ci-lite - uses: pre-commit-ci/lite-action@v1.1.0 + uses: pre-commit-ci/lite-action@5d6cc0eb514c891a40562a58a8e71576c5c7fb43 # v1.1.0 # Only push changes in PRs if: ${{ always() && github.event_name == 'pull_request' }} with: diff --git a/.github/workflows/publishlib.yml b/.github/workflows/publishlib.yml index 62393b80915..0e1c3f64afd 100644 --- a/.github/workflows/publishlib.yml +++ b/.github/workflows/publishlib.yml @@ -44,12 +44,12 @@ jobs: - name: Read the pr_num file id: pr_num_reader - uses: juliangruber/read-file-action@v1 + uses: juliangruber/read-file-action@b549046febe0fe86f8cb4f93c24e284433f9ab58 # v1.1.7 with: path: ./artifacts/workflows/pr_num.txt - name: Report results - uses: P-R-O-C-H-Y/report-size-deltas@libs + uses: P-R-O-C-H-Y/report-size-deltas@256d1f13e4195cd7fd436d2f959e6dc4d5e4b406 # libs with: sketches-reports-source: ${{ env.SKETCHES_REPORTS_PATH }} github-token: ${{ env.GITHUB_TOKEN }} diff --git a/.github/workflows/publishsizes-2.x.yml b/.github/workflows/publishsizes-2.x.yml index ffbd751838c..738e215bc3f 100644 --- a/.github/workflows/publishsizes-2.x.yml +++ b/.github/workflows/publishsizes-2.x.yml @@ -14,8 +14,8 @@ jobs: name: Sizes Comparison Results runs-on: ubuntu-latest steps: - - name: Checkout code - uses: actions/checkout@v4 # This step checks out the repository's code at gh-pages branch + - name: Checkout gh-pages branch + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: gh-pages @@ -34,7 +34,7 @@ jobs: mv v2.x_cli_compile/*.json artifacts/sizes-report/master/ - name: Report results - uses: P-R-O-C-H-Y/report-size-deltas@sizes_v2 + uses: P-R-O-C-H-Y/report-size-deltas@2043188c68f483a7b50527c4eacf609d05bb67a5 # sizes_v2 with: sketches-reports-source: ${{ env.SKETCHES_REPORTS_PATH }} github-token: ${{ env.GITHUB_TOKEN }} diff --git a/.github/workflows/publishsizes.yml b/.github/workflows/publishsizes.yml index 6c6d75eccce..69c18cf1835 100644 --- a/.github/workflows/publishsizes.yml +++ b/.github/workflows/publishsizes.yml @@ -21,8 +21,8 @@ jobs: github.event.workflow_run.conclusion == 'success' steps: - - name: Checkout code - uses: actions/checkout@v4 # This step checks out the repository's code at gh-pages branch + - name: Checkout gh-pages branch + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: gh-pages @@ -60,12 +60,12 @@ jobs: - name: Read the pr_num file id: pr_num_reader - uses: juliangruber/read-file-action@v1 + uses: juliangruber/read-file-action@b549046febe0fe86f8cb4f93c24e284433f9ab58 # v1.1.7 with: path: ./artifacts/sizes-report/pr_num.txt - name: Report results - uses: P-R-O-C-H-Y/report-size-deltas@sizes_v2 + uses: P-R-O-C-H-Y/report-size-deltas@2043188c68f483a7b50527c4eacf609d05bb67a5 # sizes_v2 with: sketches-reports-source: ${{ env.SKETCHES_REPORTS_PATH }} github-token: ${{ env.GITHUB_TOKEN }} diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 211ed1658f9..c8b8ddc2127 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -31,6 +31,7 @@ on: - "!libraries/**.properties" - "!libraries/**.py" - "package/**" + - "idf_component_examples/**" - "tools/**.py" - "platform.txt" - "programmers.txt" @@ -45,12 +46,12 @@ on: - "!.github/scripts/tests_*" - "!.github/scripts/upload_*" - "variants/esp32/**/*" - - "variants/esp32s2/**/*" - - "variants/esp32s3/**/*" - - "variants/esp32c2/**/*" - "variants/esp32c3/**/*" - "variants/esp32c6/**/*" - "variants/esp32h2/**/*" + - "variants/esp32p4/**/*" + - "variants/esp32s2/**/*" + - "variants/esp32s3/**/*" concurrency: group: build-${{github.event.pull_request.number || github.ref}} @@ -65,7 +66,7 @@ jobs: runs-on: ubuntu-latest if: ${{ !(github.event_name == 'pull_request' && startsWith(github.head_ref, 'release/')) }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - run: bash ./.github/scripts/check-cmakelists.sh gen-chunks: @@ -81,13 +82,13 @@ jobs: chunks: ${{ steps.set-chunks.outputs.chunks }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 2 - name: Get changed files id: changed-files - uses: tj-actions/changed-files@v44 + uses: tj-actions/changed-files@2f7c5bfce28377bc069a65ba478de0a74aa0ca32 # v46.0.1 with: files_yaml: | core: @@ -98,11 +99,12 @@ jobs: - 'platform.txt' - 'programmers.txt' - "variants/esp32/**/*" - - "variants/esp32s2/**/*" - - "variants/esp32s3/**/*" - "variants/esp32c3/**/*" - "variants/esp32c6/**/*" - "variants/esp32h2/**/*" + - "variants/esp32p4/**/*" + - "variants/esp32s2/**/*" + - "variants/esp32s3/**/*" libraries: - 'libraries/**/examples/**' - 'libraries/**/src/**' @@ -122,7 +124,7 @@ jobs: - 'idf_component.yml' - 'Kconfig.projbuild' - 'CMakeLists.txt' - - "variants/esp32c2/**/*" + - "idf_component_examples/**" - name: Set chunks id: set-chunks @@ -142,7 +144,7 @@ jobs: - name: Upload sketches found if: ${{ steps.set-chunks.outputs.build_all == 'false' && steps.set-chunks.outputs.build_libraries == 'true' }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: sketches_found path: sketches_found.txt @@ -161,13 +163,13 @@ jobs: chunk: ${{ fromJson(needs.gen-chunks.outputs.chunks) }} steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.0.4 with: python-version: "3.x" - name: Get libs cache - uses: actions/cache@v4 + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: key: libs-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('package/package_esp32_index.template.json', 'tools/get.py') }} path: | @@ -195,7 +197,7 @@ jobs: - name: Download sketches found if: ${{ needs.gen-chunks.outputs.build_all == 'false' && needs.gen-chunks.outputs.build_libraries == 'true' }} - uses: actions/download-artifact@v4 + uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1 with: name: sketches_found @@ -205,7 +207,7 @@ jobs: #Upload cli compile json as artifact - name: Upload cli compile json - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: pr_cli_compile_${{ matrix.chunk }} path: cli_compile_${{ matrix.chunk }}.json @@ -223,8 +225,8 @@ jobs: os: [windows-latest, macOS-latest] steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.0.4 with: python-version: "3.x" - name: Build Sketches @@ -260,19 +262,28 @@ jobs: container: espressif/idf:${{ matrix.idf_ver }} steps: - name: Check out arduino-esp32 as a component - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: submodules: recursive path: components/arduino-esp32 + + - name: Setup jq + uses: dcarbone/install-jq-action@e397bd87438d72198f81efd21f876461183d383a # v3.0.1 + - name: Build env: IDF_TARGET: ${{ matrix.idf_target }} shell: bash run: | - . ${IDF_PATH}/export.sh - idf.py create-project test - echo CONFIG_FREERTOS_HZ=1000 > test/sdkconfig.defaults - idf.py -C test -DEXTRA_COMPONENT_DIRS=$PWD/components build + chmod a+x ./components/arduino-esp32/.github/scripts/* + ./components/arduino-esp32/.github/scripts/on-push-idf.sh + + - name: Upload generated sdkconfig files for debugging + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + if: always() + with: + name: sdkconfig-${{ matrix.idf_target }} + path: ./components/arduino-esp32/idf_component_examples/**/sdkconfig # Save artifacts to gh-pages save-master-artifacts: @@ -283,7 +294,7 @@ jobs: steps: # Check out repository - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: token: ${{secrets.GITHUB_TOKEN}} fetch-depth: "0" @@ -292,7 +303,7 @@ jobs: run: git checkout remotes/origin/gh-pages - name: Download sketches reports artifact - uses: actions/download-artifact@v4 + uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1 with: pattern: pr_cli_compile_* merge-multiple: true @@ -322,8 +333,9 @@ jobs: env: PR_NUM: ${{ github.event.number }} run: echo $PR_NUM > pr_num.txt + - name: Upload PR number - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: pr_number path: ./pr_num.txt diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 53a512dd54f..7b23c80c49a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,14 +10,22 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 - - uses: actions/setup-python@v5 + + - name: Set up Python + uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.0.4 with: python-version: "3.x" - - run: pip install packaging - - run: pip install pyserial + + - name: Install packaging + run: pip install packaging + + - name: Install pyserial + run: pip install pyserial + - name: Build Release env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 0db3b98782b..ddc9b64aace 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -43,7 +43,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Upload - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: event_file path: ${{ github.event_path }} @@ -62,7 +62,7 @@ jobs: PERFORMANCE_ENABLED: ${{ contains(github.event.pull_request.labels.*.name, 'perf_test') }} steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: sparse-checkout: .github/scripts/tests_matrix.sh @@ -71,7 +71,7 @@ jobs: run: bash .github/scripts/tests_matrix.sh - name: Upload - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: matrix_info path: info/* diff --git a/.github/workflows/tests_build.yml b/.github/workflows/tests_build.yml index 7a5a2959657..ac1f40644ed 100644 --- a/.github/workflows/tests_build.yml +++ b/.github/workflows/tests_build.yml @@ -22,14 +22,14 @@ jobs: - name: Check if already built id: cache-build-binaries if: github.event.pull_request.number != null - uses: actions/cache/restore@v4 + uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: key: tests-${{ env.id }}-bin path: | - ~/.arduino/tests/**/build*.tmp/*.bin - ~/.arduino/tests/**/build*.tmp/*.elf - ~/.arduino/tests/**/build*.tmp/*.json - ~/.arduino/tests/**/build*.tmp/sdkconfig + ~/.arduino/tests/${{ inputs.chip }}/**/build*.tmp/*.bin + ~/.arduino/tests/${{ inputs.chip }}/**/build*.tmp/*.elf + ~/.arduino/tests/${{ inputs.chip }}/**/build*.tmp/*.json + ~/.arduino/tests/${{ inputs.chip }}/**/build*.tmp/sdkconfig - name: Evaluate if tests should be built id: check-build @@ -46,10 +46,10 @@ jobs: - name: Checkout user repository if: ${{ steps.check-build.outputs.enabled == 'true' }} - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Get libs cache - uses: actions/cache@v4 + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 if: ${{ steps.check-build.outputs.enabled == 'true' }} with: key: libs-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('package/package_esp32_index.template.json', 'tools/get.py') }} @@ -68,23 +68,23 @@ jobs: bash .github/scripts/tests_build.sh -c -type ${{ inputs.type }} -t ${{ inputs.chip }} - name: Upload ${{ inputs.chip }} ${{ inputs.type }} binaries as cache - uses: actions/cache/save@v4 + uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 if: steps.check-build.outputs.enabled == 'true' && github.event.pull_request.number != null with: key: tests-${{ env.id }}-bin path: | - ~/.arduino/tests/**/build*.tmp/*.bin - ~/.arduino/tests/**/build*.tmp/*.elf - ~/.arduino/tests/**/build*.tmp/*.json - ~/.arduino/tests/**/build*.tmp/sdkconfig + ~/.arduino/tests/${{ inputs.chip }}/**/build*.tmp/*.bin + ~/.arduino/tests/${{ inputs.chip }}/**/build*.tmp/*.elf + ~/.arduino/tests/${{ inputs.chip }}/**/build*.tmp/*.json + ~/.arduino/tests/${{ inputs.chip }}/**/build*.tmp/sdkconfig - name: Upload ${{ inputs.chip }} ${{ inputs.type }} binaries as artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: tests-bin-${{ inputs.chip }}-${{ inputs.type }} overwrite: true path: | - ~/.arduino/tests/**/build*.tmp/*.bin - ~/.arduino/tests/**/build*.tmp/*.elf - ~/.arduino/tests/**/build*.tmp/*.json - ~/.arduino/tests/**/build*.tmp/sdkconfig + ~/.arduino/tests/${{ inputs.chip }}/**/build*.tmp/*.bin + ~/.arduino/tests/${{ inputs.chip }}/**/build*.tmp/*.elf + ~/.arduino/tests/${{ inputs.chip }}/**/build*.tmp/*.json + ~/.arduino/tests/${{ inputs.chip }}/**/build*.tmp/sdkconfig diff --git a/.github/workflows/tests_hw.yml b/.github/workflows/tests_hw.yml index 76480ed7c0e..6f5fc67f7b9 100644 --- a/.github/workflows/tests_hw.yml +++ b/.github/workflows/tests_hw.yml @@ -22,17 +22,22 @@ defaults: jobs: hardware-test: name: Hardware ${{ inputs.chip }} ${{ inputs.type }} tests - runs-on: [arduino, "${{ inputs.chip }}"] + runs-on: ["arduino", "${{ inputs.chip }}"] env: id: ${{ github.event.pull_request.number || github.ref }}-${{ github.event.pull_request.head.sha || github.sha }}-${{ inputs.chip }}-${{ inputs.type }} container: image: python:3.10.1-bullseye - options: --privileged + options: --privileged --device-cgroup-rule="c 188:* rmw" --device-cgroup-rule="c 166:* rmw" steps: + - name: Clean workspace + run: | + rm -rf ./* + rm -rf ~/.arduino/tests + - name: Check if already passed id: cache-results if: github.event.pull_request.number != null - uses: actions/cache/restore@v4 + uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: key: tests-${{ env.id }}-results-hw path: | @@ -54,13 +59,13 @@ jobs: - name: Checkout user repository if: ${{ steps.check-tests.outputs.enabled == 'true' }} - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: sparse-checkout: | * # setup-python currently only works on ubuntu images - # - uses: actions/setup-python@v5 + # - uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.0.4 # if: ${{ steps.check-tests.outputs.enabled == 'true' }} # with: # cache-dependency-path: tests/requirements.txt @@ -77,11 +82,16 @@ jobs: - name: Get binaries if: ${{ steps.check-tests.outputs.enabled == 'true' }} - uses: actions/download-artifact@v4 + uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1 with: name: tests-bin-${{ inputs.chip }}-${{ inputs.type }} path: | - ~/.arduino/tests + ~/.arduino/tests/${{ inputs.chip }} + + - name: List binaries + if: ${{ steps.check-tests.outputs.enabled == 'true' }} + run: | + ls -laR ~/.arduino/tests - name: Run Tests if: ${{ steps.check-tests.outputs.enabled == 'true' }} @@ -89,7 +99,7 @@ jobs: bash .github/scripts/tests_run.sh -c -type ${{ inputs.type }} -t ${{ inputs.chip }} -i 0 -m 1 -e - name: Upload ${{ inputs.chip }} ${{ inputs.type }} hardware results as cache - uses: actions/cache/save@v4 + uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 if: steps.check-tests.outputs.enabled == 'true' && github.event.pull_request.number != null with: key: tests-${{ env.id }}-results-hw @@ -98,7 +108,7 @@ jobs: tests/**/result_*.json - name: Upload ${{ inputs.chip }} ${{ inputs.type }} hardware results as artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 if: always() with: name: tests-results-hw-${{ inputs.chip }}-${{ inputs.type }} diff --git a/.github/workflows/tests_qemu.yml b/.github/workflows/tests_qemu.yml index 6675909c9df..fa3f874cbbb 100644 --- a/.github/workflows/tests_qemu.yml +++ b/.github/workflows/tests_qemu.yml @@ -21,7 +21,7 @@ jobs: - name: Check if already passed id: get-cache-results if: github.event.pull_request.number != null - uses: actions/cache/restore@v4 + uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: key: tests-${{ env.id }}-results-qemu path: | @@ -43,7 +43,7 @@ jobs: - name: Checkout user repository if: ${{ steps.check-tests.outputs.enabled == 'true' }} - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ github.event.pull_request.head.sha || github.sha }} persist-credentials: false @@ -60,7 +60,7 @@ jobs: cd .github curl https://codeload.github.com/${{ github.repository }}/tar.gz/master | tar -xz --strip=2 arduino-esp32-master/.github - - uses: actions/setup-python@v5 + - uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.0.4 if: ${{ steps.check-tests.outputs.enabled == 'true' }} with: cache-dependency-path: tests/requirements.txt @@ -74,14 +74,14 @@ jobs: pip install -r tests/requirements.txt --extra-index-url https://dl.espressif.com/pypi - name: Install APT dependencies - uses: awalsh128/cache-apt-pkgs-action@v1.4.2 + uses: awalsh128/cache-apt-pkgs-action@5902b33ae29014e6ca012c5d8025d4346556bd40 # v1.4.3 if: ${{ steps.check-tests.outputs.enabled == 'true' }} with: packages: libpixman-1-0 libnuma1 libglib2.0-0 libslirp0 libsdl2-2.0-0 version: 1.0 - name: Get QEMU version - uses: pozetroninc/github-action-get-latest-release@v0.7.0 + uses: pozetroninc/github-action-get-latest-release@2a61c339ea7ef0a336d1daa35ef0cb1418e7676c # v0.8.0 if: ${{ steps.check-tests.outputs.enabled == 'true' }} id: get-qemu-version with: @@ -92,7 +92,7 @@ jobs: - name: Cache QEMU id: cache-qemu - uses: actions/cache@v4 + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 if: ${{ steps.check-tests.outputs.enabled == 'true' }} with: path: | @@ -113,18 +113,18 @@ jobs: - name: Get binaries if: ${{ steps.check-tests.outputs.enabled == 'true' }} - uses: actions/download-artifact@v4 + uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1 with: name: tests-bin-${{ inputs.chip }}-${{ inputs.type }} path: | - ~/.arduino/tests + ~/.arduino/tests/${{ inputs.chip }} - name: Run Tests if: ${{ steps.check-tests.outputs.enabled == 'true' }} run: QEMU_PATH="${{ env.QEMU_INSTALL_PATH }}" bash .github/scripts/tests_run.sh -c -type ${{inputs.type}} -t ${{inputs.chip}} -i 0 -m 1 -Q - name: Upload ${{ inputs.chip }} ${{ inputs.type }} QEMU results as cache - uses: actions/cache/save@v4 + uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 if: steps.check-tests.outputs.enabled == 'true' && github.event.pull_request.number != null with: key: tests-${{ env.id }}-results-qemu @@ -133,7 +133,7 @@ jobs: tests/**/result_*.json - name: Upload ${{ inputs.chip }} ${{ inputs.type }} QEMU results as artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 if: always() with: name: tests-results-qemu-${{ inputs.chip }}-${{ inputs.type }} diff --git a/.github/workflows/tests_results.yml b/.github/workflows/tests_results.yml index 9e213fad14e..ebba2a3aa08 100644 --- a/.github/workflows/tests_results.yml +++ b/.github/workflows/tests_results.yml @@ -24,12 +24,12 @@ jobs: pull-requests: write contents: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: gh-pages - name: Download and Extract Artifacts - uses: dawidd6/action-download-artifact@v6 + uses: dawidd6/action-download-artifact@07ab29fd4a977ae4d2b275087cf67563dfdf0295 # v9 with: run_id: ${{ github.event.workflow_run.id }} path: ./artifacts @@ -83,7 +83,7 @@ jobs: echo "Wokwi tests: https://github.com/${{ github.repository }}/actions/runs/${{ github.event.workflow_run.id }}" - name: Publish Unit Test Results - uses: EnricoMi/publish-unit-test-result-action@v2 + uses: EnricoMi/publish-unit-test-result-action@170bf24d20d201b842d7a52403b73ed297e6645b # v2.18.0 with: commit: ${{ env.original_sha }} event_file: ./artifacts/parent-artifacts/event_file/event.json @@ -95,7 +95,7 @@ jobs: json_suite_details: true - name: Upload JSON - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 if: ${{ always() }} with: name: unity_results @@ -109,7 +109,7 @@ jobs: - name: Clean up caches if: always() - uses: actions/github-script@v7 + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 with: script: | const ref = process.env.original_ref; @@ -139,7 +139,7 @@ jobs: }); - name: Report conclusion - uses: actions/github-script@v7 + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 if: always() with: script: | @@ -175,7 +175,7 @@ jobs: - name: Generate badge if: ${{ !cancelled() && (env.original_event == 'schedule' || env.original_event == 'workflow_dispatch') }} # codespell:ignore cancelled - uses: jaywcjlove/generated-badges@v1.0.13 + uses: jaywcjlove/generated-badges@0e078ae4d4bab3777ea4f137de496ab44688f5ad # v1.0.13 with: label: Runtime Tests status: ${{ job.status == 'success' && 'passing' || 'failing' }} diff --git a/.github/workflows/tests_wokwi.yml b/.github/workflows/tests_wokwi.yml index c254d5fa153..03dd64fc0fb 100644 --- a/.github/workflows/tests_wokwi.yml +++ b/.github/workflows/tests_wokwi.yml @@ -27,7 +27,7 @@ jobs: types: ${{ steps.set-ref.outputs.types }} steps: - name: Report pending - uses: actions/github-script@v7 + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 with: script: | const owner = '${{ github.repository_owner }}'; @@ -47,7 +47,7 @@ jobs: core.info(`${name} is ${state}`); - name: Download and extract event file - uses: actions/download-artifact@v4 + uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1 with: github-token: ${{ secrets.GITHUB_TOKEN }} run-id: ${{ github.event.workflow_run.id }} @@ -55,7 +55,7 @@ jobs: path: artifacts/event_file - name: Download and extract matrix info - uses: actions/download-artifact@v4 + uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1 with: github-token: ${{ secrets.GITHUB_TOKEN }} run-id: ${{ github.event.workflow_run.id }} @@ -130,7 +130,7 @@ jobs: echo "ref=$ref" >> $GITHUB_OUTPUT - name: Download and extract parent hardware results - uses: actions/download-artifact@v4 + uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1 continue-on-error: true with: github-token: ${{ secrets.GITHUB_TOKEN }} @@ -140,7 +140,7 @@ jobs: path: artifacts/results/hw - name: Download and extract parent QEMU results - uses: actions/download-artifact@v4 + uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1 continue-on-error: true with: github-token: ${{ secrets.GITHUB_TOKEN }} @@ -150,14 +150,14 @@ jobs: path: artifacts/results/qemu - name: Upload parent artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: parent-artifacts path: artifacts if-no-files-found: error - name: Report conclusion - uses: actions/github-script@v7 + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 if: always() with: script: | @@ -197,7 +197,7 @@ jobs: chip: ${{ fromJson(needs.get-artifacts.outputs.targets) }} steps: - name: Report pending - uses: actions/github-script@v7 + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 with: script: | const owner = '${{ github.repository_owner }}'; @@ -219,7 +219,7 @@ jobs: - name: Check if already passed id: get-cache-results if: needs.get-artifacts.outputs.pr_num - uses: actions/cache/restore@v4 + uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: key: tests-${{ env.id }}-results-wokwi path: | @@ -243,11 +243,11 @@ jobs: # DO NOT CHECKOUT THE USER'S REPOSITORY IN THIS WORKFLOW. IT HAS HIGH SECURITY RISKS. - name: Checkout repository if: ${{ steps.check-tests.outputs.enabled == 'true' }} - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ needs.get-artifacts.outputs.base || github.ref }} - - uses: actions/setup-python@v5 + - uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.0.4 if: ${{ steps.check-tests.outputs.enabled == 'true' }} with: cache-dependency-path: tests/requirements.txt @@ -266,17 +266,17 @@ jobs: - name: Wokwi CI Server if: ${{ steps.check-tests.outputs.enabled == 'true' }} - uses: wokwi/wokwi-ci-server-action@v1 + uses: wokwi/wokwi-ci-server-action@a6fabb5a49e080158c7a1d121ea5b789536a82c3 # v1 - name: Get binaries if: ${{ steps.check-tests.outputs.enabled == 'true' }} - uses: actions/download-artifact@v4 + uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1 with: github-token: ${{ secrets.GITHUB_TOKEN }} run-id: ${{ github.event.workflow_run.id }} name: tests-bin-${{ matrix.chip }}-${{ matrix.type }} path: | - ~/.arduino/tests + ~/.arduino/tests/${{ matrix.chip }} - name: Run Tests if: ${{ steps.check-tests.outputs.enabled == 'true' }} @@ -286,7 +286,7 @@ jobs: bash .github/scripts/tests_run.sh -c -type ${{ matrix.type }} -t ${{ matrix.chip }} -i 0 -m 1 -W ${{ env.WOKWI_TIMEOUT }} - name: Upload ${{ matrix.chip }} ${{ matrix.type }} Wokwi results as cache - uses: actions/cache/save@v4 + uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 if: steps.check-tests.outputs.enabled == 'true' && needs.get-artifacts.outputs.pr_num with: key: tests-${{ env.id }}-results-wokwi @@ -295,7 +295,7 @@ jobs: tests/**/result_*.json - name: Upload ${{ matrix.chip }} ${{ matrix.type }} Wokwi results as artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 if: always() with: name: tests-results-wokwi-${{ matrix.chip }}-${{ matrix.type }} @@ -305,7 +305,7 @@ jobs: tests/**/result_*.json - name: Report conclusion - uses: actions/github-script@v7 + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 if: always() with: script: | diff --git a/.github/workflows/upload-idf-component.yml b/.github/workflows/upload-idf-component.yml index 5ce4562c01a..687e721fbc2 100644 --- a/.github/workflows/upload-idf-component.yml +++ b/.github/workflows/upload-idf-component.yml @@ -45,13 +45,13 @@ jobs: echo "Tag: $tag" echo "RELEASE_TAG=$tag" >> $GITHUB_ENV - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ inputs.git_ref || env.RELEASE_TAG }} submodules: "recursive" - name: Upload components to the component registry - uses: espressif/upload-components-ci-action@v1 + uses: espressif/upload-components-ci-action@b78a19fa5424714997596d3ecffa634aef8ae20b # v1.0.5 with: name: arduino-esp32 version: ${{ env.RELEASE_TAG }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f80261422b0..0d425c46eae 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -12,7 +12,7 @@ default_language_version: repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: "v5.0.0" + rev: "cef0300fd0fc4d2a87a85fa2093c6b283ea36f4b" # v5.0.0 hooks: # Generic checks - id: check-case-conflict @@ -39,15 +39,8 @@ repos: ^package\/.*$ ) - - repo: https://github.com/codespell-project/codespell - rev: "v2.3.0" - hooks: - # Spell checking - - id: codespell - exclude: ^.*\.(svd|SVD)$ - - repo: https://github.com/pre-commit/mirrors-clang-format - rev: "v18.1.3" + rev: "f6446549e5e97ec9665b9b03e75b87b445857f9a" # v18.1.3 hooks: # C/C++ formatting - id: clang-format @@ -55,7 +48,7 @@ repos: exclude: ^.*\/build_opt\.h$ - repo: https://github.com/psf/black-pre-commit-mirror - rev: "24.10.0" + rev: "a4920527036bb9a3f3e6055d595849d67d0da066" # 25.1.0 hooks: # Python formatting - id: black @@ -63,7 +56,7 @@ repos: args: [--line-length=120] #From the arduino code style. Add as argument rather than creating a new config file. - repo: https://github.com/PyCQA/flake8 - rev: "7.1.1" + rev: "16f5f28a384f0781bebb37a08aa45e65b9526c50" # 7.2.0 hooks: # Python linting - id: flake8 @@ -74,21 +67,28 @@ repos: - flake8-simplify - repo: https://github.com/pre-commit/mirrors-prettier - rev: "v3.1.0" + rev: "ffb6a759a979008c0e6dff86e39f4745a2d9eac4" # v3.1.0 hooks: # YAML formatting - id: prettier types_or: [yaml] + - repo: https://github.com/codespell-project/codespell + rev: "63c8f8312b7559622c0d82815639671ae42132ac" # v2.4.1 + hooks: + # Spell checking + - id: codespell + exclude: ^.*\.(svd|SVD)$ + - repo: https://github.com/shellcheck-py/shellcheck-py - rev: "v0.10.0.1" + rev: "a23f6b85d0fdd5bb9d564e2579e678033debbdff" # v0.10.0.1 hooks: # Bash linting - id: shellcheck types: [shell] - repo: https://github.com/openstack/bashate - rev: "2.1.1" + rev: "fbd7c2534c2701351c603ff700ddf08202430a31" # 2.1.1 hooks: # Bash formatting - id: bashate @@ -96,15 +96,15 @@ repos: args: ["-i", "E006"] # Ignore E006: Line too long - repo: https://github.com/errata-ai/vale - rev: "v3.9.1" + rev: "dc4c47923788a413fb5677de6e3370d514aecb78" # v3.11.2 hooks: # Sync vale styles and lint markdown and reStructuredText - id: vale name: vale-sync - language_version: "1.21.6" + language_version: "1.23.2" pass_filenames: false args: [sync] types_or: [markdown, rst] - id: vale - language_version: "1.21.6" + language_version: "1.23.2" types_or: [markdown, rst] diff --git a/CMakeLists.txt b/CMakeLists.txt index d2a9162a9ba..d53d612962d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -299,6 +299,11 @@ set(ARDUINO_LIBRARY_Zigbee_SRCS libraries/Zigbee/src/ep/ZigbeeRangeExtender.cpp libraries/Zigbee/src/ep/ZigbeeGateway.cpp libraries/Zigbee/src/ep/ZigbeeWindSpeedSensor.cpp + libraries/Zigbee/src/ep/ZigbeeIlluminanceSensor.cpp + libraries/Zigbee/src/ep/ZigbeePM25Sensor.cpp + libraries/Zigbee/src/ep/ZigbeeElectricalMeasurement.cpp + libraries/Zigbee/src/ep/ZigbeeBinary.cpp + libraries/Zigbee/src/ep/ZigbeePowerOutlet.cpp ) set(ARDUINO_LIBRARY_BLE_SRCS diff --git a/README.md b/README.md index 9d300b25c54..f40315c03cc 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Arduino core for the ESP32, ESP32-P4, ESP32-S2, ESP32-S3, ESP32-C3, ESP32-C6 and ESP32-H2 +# Arduino core for the ESP32, ESP32-C3, ESP32-C6, ESP32-H2, ESP32-P4, ESP32-S2 and ESP32-S3. [![Build Status](https://img.shields.io/github/actions/workflow/status/espressif/arduino-esp32/push.yml?branch=master&event=push&label=Compilation%20Tests)](https://github.com/espressif/arduino-esp32/actions/workflows/push.yml?query=branch%3Amaster+event%3Apush) [![Verbose Build Status](https://img.shields.io/github/actions/workflow/status/espressif/arduino-esp32/push.yml?branch=master&event=schedule&label=Compilation%20Tests%20(Verbose))](https://github.com/espressif/arduino-esp32/actions/workflows/push.yml?query=branch%3Amaster+event%3Aschedule) @@ -67,16 +67,17 @@ Here are the ESP32 series supported by the Arduino-ESP32 project: | **SoC** | **Stable** | **Development** | **Datasheet** | |----------|:----------:|:---------------:|:-------------------------------------------------------------------------------------------------:| | ESP32 | Yes | Yes | [ESP32](https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf) | -| ESP32-S2 | Yes | Yes | [ESP32-S2](https://www.espressif.com/sites/default/files/documentation/esp32-s2_datasheet_en.pdf) | | ESP32-C3 | Yes | Yes | [ESP32-C3](https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf) | -| ESP32-S3 | Yes | Yes | [ESP32-S3](https://www.espressif.com/sites/default/files/documentation/esp32-s3_datasheet_en.pdf) | | ESP32-C6 | Yes | Yes | [ESP32-C6](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf) | | ESP32-H2 | Yes | Yes | [ESP32-H2](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf) | | ESP32-P4 | Yes | Yes | [ESP32-P4](https://www.espressif.com/sites/default/files/documentation/esp32-p4_datasheet_en.pdf) | +| ESP32-S2 | Yes | Yes | [ESP32-S2](https://www.espressif.com/sites/default/files/documentation/esp32-s2_datasheet_en.pdf) | +| ESP32-S3 | Yes | Yes | [ESP32-S3](https://www.espressif.com/sites/default/files/documentation/esp32-s3_datasheet_en.pdf) | > [!NOTE] -> ESP32-C2 is also supported by Arduino-ESP32 but requires rebuilding the static libraries. This is not trivial and requires a good understanding of the ESP-IDF -> build system. For more information, see the [Lib Builder documentation](https://docs.espressif.com/projects/arduino-esp32/en/latest/lib_builder.html). +> ESP32-C2 is also supported by Arduino-ESP32 but requires using Arduino as an ESP-IDF component or rebuilding the static libraries. +> For more information, see the [Arduino as an ESP-IDF component documentation](https://docs.espressif.com/projects/arduino-esp32/en/latest/esp-idf_component.html) or the +> [Lib Builder documentation](https://docs.espressif.com/projects/arduino-esp32/en/latest/lib_builder.html), respectively. For more details visit the [supported chips](https://docs.espressif.com/projects/arduino-esp32/en/latest/getting_started.html#supported-soc-s) documentation page. diff --git a/boards.txt b/boards.txt index 2afe45f50a6..d92f057a78f 100644 --- a/boards.txt +++ b/boards.txt @@ -449,7 +449,7 @@ esp32h2.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728 #esp32h2.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 #esp32h2.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB #esp32h2.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -#esp32h2.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +#esp32h2.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 esp32h2.menu.PartitionScheme.zigbee_2MB=Zigbee 2MB with spiffs esp32h2.menu.PartitionScheme.zigbee_2MB.build.partitions=zigbee_2MB esp32h2.menu.PartitionScheme.zigbee_2MB.upload.maximum_size=1310720 @@ -647,7 +647,7 @@ esp32c6.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no_ota esp32c6.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 esp32c6.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB esp32c6.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -esp32c6.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +esp32c6.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 esp32c6.menu.PartitionScheme.zigbee_2MB=Zigbee 2MB with spiffs esp32c6.menu.PartitionScheme.zigbee_2MB.build.partitions=zigbee_2MB esp32c6.menu.PartitionScheme.zigbee_2MB.upload.maximum_size=1310720 @@ -933,13 +933,16 @@ esp32s3.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no_ota esp32s3.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 esp32s3.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB esp32s3.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -esp32s3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +esp32s3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 esp32s3.menu.PartitionScheme.app5M_fat24M_32MB=32M Flash (4.8MB APP/22MB FATFS) esp32s3.menu.PartitionScheme.app5M_fat24M_32MB.build.partitions=large_fat_32MB esp32s3.menu.PartitionScheme.app5M_fat24M_32MB.upload.maximum_size=4718592 esp32s3.menu.PartitionScheme.app5M_little24M_32MB=32M Flash (4.8MB APP/22MB LittleFS) esp32s3.menu.PartitionScheme.app5M_little24M_32MB.build.partitions=large_littlefs_32MB esp32s3.menu.PartitionScheme.app5M_little24M_32MB.upload.maximum_size=4718592 +esp32s3.menu.PartitionScheme.app13M_data7M_32MB=32M Flash (13MB APP/6.75MB SPIFFS) +esp32s3.menu.PartitionScheme.app13M_data7M_32MB.build.partitions=default_32MB +esp32s3.menu.PartitionScheme.app13M_data7M_32MB.upload.maximum_size=13107200 esp32s3.menu.PartitionScheme.esp_sr_16=ESP SR 16M (3MB APP/7MB SPIFFS/2.9MB MODEL) esp32s3.menu.PartitionScheme.esp_sr_16.upload.maximum_size=3145728 esp32s3.menu.PartitionScheme.esp_sr_16.upload.extra_flags=0xD10000 {build.path}/srmodels.bin @@ -1107,7 +1110,7 @@ esp32c3.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no_ota esp32c3.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 esp32c3.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB esp32c3.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -esp32c3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +esp32c3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 esp32c3.menu.PartitionScheme.zigbee_zczr=Zigbee ZCZR 4MB with spiffs esp32c3.menu.PartitionScheme.zigbee_zczr.build.partitions=zigbee_zczr esp32c3.menu.PartitionScheme.zigbee_zczr.upload.maximum_size=1310720 @@ -1315,7 +1318,7 @@ esp32s2.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no_ota esp32s2.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 esp32s2.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB esp32s2.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -esp32s2.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +esp32s2.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 esp32s2.menu.PartitionScheme.zigbee_zczr=Zigbee ZCZR 4MB with spiffs esp32s2.menu.PartitionScheme.zigbee_zczr.build.partitions=zigbee_zczr esp32s2.menu.PartitionScheme.zigbee_zczr.upload.maximum_size=1310720 @@ -1498,7 +1501,7 @@ esp32.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no_ota esp32.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 esp32.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB esp32.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -esp32.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +esp32.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 esp32.menu.PartitionScheme.zigbee_zczr=Zigbee ZCZR 4MB with spiffs esp32.menu.PartitionScheme.zigbee_zczr.build.partitions=zigbee_zczr esp32.menu.PartitionScheme.zigbee_zczr.upload.maximum_size=1310720 @@ -1678,7 +1681,7 @@ esp32da.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no_ota esp32da.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 esp32da.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB esp32da.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -esp32da.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +esp32da.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 esp32da.menu.PartitionScheme.custom=Custom esp32da.menu.PartitionScheme.custom.build.partitions= esp32da.menu.PartitionScheme.custom.upload.maximum_size=16777216 @@ -2141,13 +2144,16 @@ esp32s3-octal.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_ esp32s3-octal.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 esp32s3-octal.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB esp32s3-octal.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -esp32s3-octal.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +esp32s3-octal.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 esp32s3-octal.menu.PartitionScheme.app5M_fat24M_32MB=32M Flash (4.8MB APP/22MB FATFS) esp32s3-octal.menu.PartitionScheme.app5M_fat24M_32MB.build.partitions=large_fat_32MB esp32s3-octal.menu.PartitionScheme.app5M_fat24M_32MB.upload.maximum_size=4718592 esp32s3-octal.menu.PartitionScheme.app5M_little24M_32MB=32M Flash (4.8MB APP/22MB LittleFS) esp32s3-octal.menu.PartitionScheme.app5M_little24M_32MB.build.partitions=large_littlefs_32MB esp32s3-octal.menu.PartitionScheme.app5M_little24M_32MB.upload.maximum_size=4718592 +esp32s3-octal.menu.PartitionScheme.app13M_data7M_32MB=32M Flash (13MB APP/6.75MB SPIFFS) +esp32s3-octal.menu.PartitionScheme.app13M_data7M_32MB.build.partitions=default_32MB +esp32s3-octal.menu.PartitionScheme.app13M_data7M_32MB.upload.maximum_size=13107200 esp32s3-octal.menu.CPUFreq.240=240MHz (WiFi) esp32s3-octal.menu.CPUFreq.240.build.f_cpu=240000000L @@ -2725,7 +2731,7 @@ esp32wroverkit.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB esp32wroverkit.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 esp32wroverkit.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB esp32wroverkit.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -esp32wroverkit.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +esp32wroverkit.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 esp32wroverkit.menu.CPUFreq.240=240MHz (WiFi/BT) esp32wroverkit.menu.CPUFreq.240.build.f_cpu=240000000L @@ -2960,7 +2966,7 @@ aventen_s3_sync.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4M aventen_s3_sync.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 aventen_s3_sync.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB aventen_s3_sync.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -aventen_s3_sync.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +aventen_s3_sync.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 aventen_s3_sync.menu.CPUFreq.240=240MHz (WiFi) aventen_s3_sync.menu.CPUFreq.240.build.f_cpu=240000000L @@ -3637,6 +3643,155 @@ um_bling.menu.EraseFlash.all.upload.erase_cmd=-e ############################################################## +um_edges3_d.name=UM EdgeS3[D] +um_edges3_d.vid.0=0x303a +um_edges3_d.pid.0=0x82DC +um_edges3_d.upload_port.0.vid=0x303a +um_edges3_d.upload_port.0.pid=0x82DC + +um_edges3_d.bootloader.tool=esptool_py +um_edges3_d.bootloader.tool.default=esptool_py + +um_edges3_d.upload.tool=esptool_py +um_edges3_d.upload.tool.default=esptool_py +um_edges3_d.upload.tool.network=esp_ota + +um_edges3_d.upload.maximum_size=1310720 +um_edges3_d.upload.maximum_data_size=327680 +um_edges3_d.upload.flags= +um_edges3_d.upload.extra_flags= +um_edges3_d.upload.use_1200bps_touch=false +um_edges3_d.upload.wait_for_upload_port=false + +um_edges3_d.serial.disableDTR=false +um_edges3_d.serial.disableRTS=false + +um_edges3_d.build.tarch=xtensa +um_edges3_d.build.bootloader_addr=0x0 +um_edges3_d.build.target=esp32s3 +um_edges3_d.build.mcu=esp32s3 +um_edges3_d.build.core=esp32 +um_edges3_d.build.variant=um_edges3_d +um_edges3_d.build.board=EDGES3D + +um_edges3_d.build.usb_mode=1 +um_edges3_d.build.cdc_on_boot=1 +um_edges3_d.build.msc_on_boot=0 +um_edges3_d.build.dfu_on_boot=0 +um_edges3_d.build.f_cpu=240000000L +um_edges3_d.build.flash_size=8MB +um_edges3_d.build.flash_freq=80m +um_edges3_d.build.flash_mode=dio +um_edges3_d.build.boot=qio +um_edges3_d.build.partitions=default +um_edges3_d.build.defines= +um_edges3_d.build.loop_core= +um_edges3_d.build.event_core= +um_edges3_d.build.flash_type=qio +um_edges3_d.build.psram_type=qspi +um_edges3_d.build.memory_type=qio_qspi + +um_edges3_d.menu.LoopCore.1=Core 1 +um_edges3_d.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 +um_edges3_d.menu.LoopCore.0=Core 0 +um_edges3_d.menu.LoopCore.0.build.loop_core=-DARDUINO_RUNNING_CORE=0 + +um_edges3_d.menu.EventsCore.1=Core 1 +um_edges3_d.menu.EventsCore.1.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1 +um_edges3_d.menu.EventsCore.0=Core 0 +um_edges3_d.menu.EventsCore.0.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=0 + +um_edges3_d.menu.USBMode.hwcdc=Hardware CDC and JTAG +um_edges3_d.menu.USBMode.hwcdc.build.usb_mode=1 +um_edges3_d.menu.USBMode.default=USB-OTG (TinyUSB) +um_edges3_d.menu.USBMode.default.build.usb_mode=0 + +um_edges3_d.menu.CDCOnBoot.cdc=Enabled +um_edges3_d.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 +um_edges3_d.menu.CDCOnBoot.default=Disabled +um_edges3_d.menu.CDCOnBoot.default.build.cdc_on_boot=0 + +um_edges3_d.menu.MSCOnBoot.default=Disabled +um_edges3_d.menu.MSCOnBoot.default.build.msc_on_boot=0 +um_edges3_d.menu.MSCOnBoot.msc=Enabled (Requires USB-OTG Mode) +um_edges3_d.menu.MSCOnBoot.msc.build.msc_on_boot=1 + +um_edges3_d.menu.DFUOnBoot.default=Disabled +um_edges3_d.menu.DFUOnBoot.default.build.dfu_on_boot=0 +um_edges3_d.menu.DFUOnBoot.dfu=Enabled (Requires USB-OTG Mode) +um_edges3_d.menu.DFUOnBoot.dfu.build.dfu_on_boot=1 + +um_edges3_d.menu.UploadMode.cdc.upload.wait_for_upload_port=true +um_edges3_d.menu.UploadMode.default=UART0 / Hardware CDC +um_edges3_d.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB) +um_edges3_d.menu.UploadMode.cdc.upload.use_1200bps_touch=true +um_edges3_d.menu.UploadMode.default.upload.use_1200bps_touch=false +um_edges3_d.menu.UploadMode.default.upload.wait_for_upload_port=false + +um_edges3_d.menu.PSRAM.enabled=Enabled +um_edges3_d.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM +um_edges3_d.menu.PSRAM.disabled=Disabled +um_edges3_d.menu.PSRAM.disabled.build.defines= + +um_edges3_d.menu.PartitionScheme.default_8MB=Default (3MB APP/1.5MB SPIFFS) +um_edges3_d.menu.PartitionScheme.default_8MB.build.partitions=default_8MB +um_edges3_d.menu.PartitionScheme.default_8MB.upload.maximum_size=3342336 + +um_edges3_d.menu.CPUFreq.240=240MHz (WiFi) +um_edges3_d.menu.CPUFreq.240.build.f_cpu=240000000L +um_edges3_d.menu.CPUFreq.160=160MHz (WiFi) +um_edges3_d.menu.CPUFreq.160.build.f_cpu=160000000L +um_edges3_d.menu.CPUFreq.80=80MHz (WiFi) +um_edges3_d.menu.CPUFreq.80.build.f_cpu=80000000L +um_edges3_d.menu.CPUFreq.40=40MHz +um_edges3_d.menu.CPUFreq.40.build.f_cpu=40000000L +um_edges3_d.menu.CPUFreq.20=20MHz +um_edges3_d.menu.CPUFreq.20.build.f_cpu=20000000L +um_edges3_d.menu.CPUFreq.10=10MHz +um_edges3_d.menu.CPUFreq.10.build.f_cpu=10000000L + +um_edges3_d.menu.FlashMode.qio=QIO +um_edges3_d.menu.FlashMode.qio.build.flash_mode=dio +um_edges3_d.menu.FlashMode.qio.build.boot=qio +um_edges3_d.menu.FlashMode.dio=DIO +um_edges3_d.menu.FlashMode.dio.build.flash_mode=dio +um_edges3_d.menu.FlashMode.dio.build.boot=dio + +um_edges3_d.menu.UploadSpeed.921600=921600 +um_edges3_d.menu.UploadSpeed.921600.upload.speed=921600 +um_edges3_d.menu.UploadSpeed.115200=115200 +um_edges3_d.menu.UploadSpeed.115200.upload.speed=115200 +um_edges3_d.menu.UploadSpeed.256000.windows=256000 +um_edges3_d.menu.UploadSpeed.256000.upload.speed=256000 +um_edges3_d.menu.UploadSpeed.230400.windows.upload.speed=256000 +um_edges3_d.menu.UploadSpeed.230400=230400 +um_edges3_d.menu.UploadSpeed.230400.upload.speed=230400 +um_edges3_d.menu.UploadSpeed.460800.linux=460800 +um_edges3_d.menu.UploadSpeed.460800.macosx=460800 +um_edges3_d.menu.UploadSpeed.460800.upload.speed=460800 +um_edges3_d.menu.UploadSpeed.512000.windows=512000 +um_edges3_d.menu.UploadSpeed.512000.upload.speed=512000 + +um_edges3_d.menu.DebugLevel.none=None +um_edges3_d.menu.DebugLevel.none.build.code_debug=0 +um_edges3_d.menu.DebugLevel.error=Error +um_edges3_d.menu.DebugLevel.error.build.code_debug=1 +um_edges3_d.menu.DebugLevel.warn=Warn +um_edges3_d.menu.DebugLevel.warn.build.code_debug=2 +um_edges3_d.menu.DebugLevel.info=Info +um_edges3_d.menu.DebugLevel.info.build.code_debug=3 +um_edges3_d.menu.DebugLevel.debug=Debug +um_edges3_d.menu.DebugLevel.debug.build.code_debug=4 +um_edges3_d.menu.DebugLevel.verbose=Verbose +um_edges3_d.menu.DebugLevel.verbose.build.code_debug=5 + +um_edges3_d.menu.EraseFlash.none=Disabled +um_edges3_d.menu.EraseFlash.none.upload.erase_cmd= +um_edges3_d.menu.EraseFlash.all=Enabled +um_edges3_d.menu.EraseFlash.all.upload.erase_cmd=-e + +############################################################## + um_feathers2.name=UM FeatherS2 um_feathers2.vid.0=0x239A um_feathers2.pid.0=0x80AB @@ -4729,6 +4884,163 @@ um_pros3.menu.EraseFlash.all.upload.erase_cmd=-e ############################################################## +um_squixl.name=UM SQUIXL +um_squixl.vid.0=0x303a +um_squixl.pid.0=0x82DF +um_squixl.upload_port.0.vid=0x303a +um_squixl.upload_port.0.pid=0x82DF + +um_squixl.bootloader.tool=esptool_py +um_squixl.bootloader.tool.default=esptool_py + +um_squixl.upload.tool=esptool_py +um_squixl.upload.tool.default=esptool_py +um_squixl.upload.tool.network=esp_ota + +um_squixl.upload.maximum_size=1310720 +um_squixl.upload.maximum_data_size=327680 +um_squixl.upload.flags= +um_squixl.upload.extra_flags= +um_squixl.upload.use_1200bps_touch=false +um_squixl.upload.wait_for_upload_port=false + +um_squixl.serial.disableDTR=false +um_squixl.serial.disableRTS=false + +um_squixl.build.tarch=xtensa +um_squixl.build.bootloader_addr=0x0 +um_squixl.build.target=esp32s3 +um_squixl.build.mcu=esp32s3 +um_squixl.build.core=esp32 +um_squixl.build.variant=um_squixl +um_squixl.build.board=SQUIXL + +um_squixl.build.usb_mode=1 +um_squixl.build.cdc_on_boot=1 +um_squixl.build.msc_on_boot=0 +um_squixl.build.dfu_on_boot=0 +um_squixl.build.f_cpu=240000000L +um_squixl.build.flash_size=16MB +um_squixl.build.flash_freq=80m +um_squixl.build.flash_mode=dio +um_squixl.build.boot=qio +um_squixl.build.partitions=default +um_squixl.build.defines= +um_squixl.build.loop_core= +um_squixl.build.event_core= +um_squixl.build.flash_type=qio +um_squixl.build.psram_type=opi +um_squixl.build.memory_type=qio_opi + +um_squixl.menu.LoopCore.1=Core 1 +um_squixl.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 +um_squixl.menu.LoopCore.0=Core 0 +um_squixl.menu.LoopCore.0.build.loop_core=-DARDUINO_RUNNING_CORE=0 + +um_squixl.menu.EventsCore.1=Core 1 +um_squixl.menu.EventsCore.1.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1 +um_squixl.menu.EventsCore.0=Core 0 +um_squixl.menu.EventsCore.0.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=0 + +um_squixl.menu.USBMode.hwcdc=Hardware CDC and JTAG +um_squixl.menu.USBMode.hwcdc.build.usb_mode=1 +um_squixl.menu.USBMode.default=USB-OTG (TinyUSB) +um_squixl.menu.USBMode.default.build.usb_mode=0 + +um_squixl.menu.CDCOnBoot.cdc=Enabled +um_squixl.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 +um_squixl.menu.CDCOnBoot.default=Disabled +um_squixl.menu.CDCOnBoot.default.build.cdc_on_boot=0 + +um_squixl.menu.MSCOnBoot.default=Disabled +um_squixl.menu.MSCOnBoot.default.build.msc_on_boot=0 +um_squixl.menu.MSCOnBoot.msc=Enabled (Requires USB-OTG Mode) +um_squixl.menu.MSCOnBoot.msc.build.msc_on_boot=1 + +um_squixl.menu.DFUOnBoot.default=Disabled +um_squixl.menu.DFUOnBoot.default.build.dfu_on_boot=0 +um_squixl.menu.DFUOnBoot.dfu=Enabled (Requires USB-OTG Mode) +um_squixl.menu.DFUOnBoot.dfu.build.dfu_on_boot=1 + +um_squixl.menu.UploadMode.cdc.upload.wait_for_upload_port=true +um_squixl.menu.UploadMode.default=UART0 / Hardware CDC +um_squixl.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB) +um_squixl.menu.UploadMode.cdc.upload.use_1200bps_touch=true +um_squixl.menu.UploadMode.default.upload.use_1200bps_touch=false +um_squixl.menu.UploadMode.default.upload.wait_for_upload_port=false + +um_squixl.menu.PSRAM.opi=OPI PSRAM +um_squixl.menu.PSRAM.opi.build.defines=-DBOARD_HAS_PSRAM +um_squixl.menu.PSRAM.opi.build.psram_type=opi + +um_squixl.menu.PartitionScheme.default_16MB=Default (6.25MB APP/3.43MB SPIFFS) +um_squixl.menu.PartitionScheme.default_16MB.build.partitions=default_16MB +um_squixl.menu.PartitionScheme.default_16MB.upload.maximum_size=6553600 +um_squixl.menu.PartitionScheme.large_spiffs=Large SPIFFS (4.5MB APP/6.93MB SPIFFS) +um_squixl.menu.PartitionScheme.large_spiffs.build.partitions=large_spiffs_16MB +um_squixl.menu.PartitionScheme.large_spiffs.upload.maximum_size=4718592 +um_squixl.menu.PartitionScheme.app3M_fat9M_16MB=FFAT (3MB APP/9MB FATFS) +um_squixl.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB +um_squixl.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728 +um_squixl.menu.PartitionScheme.fatflash=Large FFAT (2MB APP/12.5MB FATFS) +um_squixl.menu.PartitionScheme.fatflash.build.partitions=ffat +um_squixl.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 + +um_squixl.menu.CPUFreq.240=240MHz (WiFi) +um_squixl.menu.CPUFreq.240.build.f_cpu=240000000L +um_squixl.menu.CPUFreq.160=160MHz (WiFi) +um_squixl.menu.CPUFreq.160.build.f_cpu=160000000L +um_squixl.menu.CPUFreq.80=80MHz (WiFi) +um_squixl.menu.CPUFreq.80.build.f_cpu=80000000L +um_squixl.menu.CPUFreq.40=40MHz +um_squixl.menu.CPUFreq.40.build.f_cpu=40000000L +um_squixl.menu.CPUFreq.20=20MHz +um_squixl.menu.CPUFreq.20.build.f_cpu=20000000L +um_squixl.menu.CPUFreq.10=10MHz +um_squixl.menu.CPUFreq.10.build.f_cpu=10000000L + +um_squixl.menu.FlashMode.qio=QIO +um_squixl.menu.FlashMode.qio.build.flash_mode=dio +um_squixl.menu.FlashMode.qio.build.boot=qio +um_squixl.menu.FlashMode.dio=DIO +um_squixl.menu.FlashMode.dio.build.flash_mode=dio +um_squixl.menu.FlashMode.dio.build.boot=dio + +um_squixl.menu.UploadSpeed.921600=921600 +um_squixl.menu.UploadSpeed.921600.upload.speed=921600 +um_squixl.menu.UploadSpeed.115200=115200 +um_squixl.menu.UploadSpeed.115200.upload.speed=115200 +um_squixl.menu.UploadSpeed.256000.windows=256000 +um_squixl.menu.UploadSpeed.256000.upload.speed=256000 +um_squixl.menu.UploadSpeed.230400.windows.upload.speed=256000 +um_squixl.menu.UploadSpeed.230400=230400 +um_squixl.menu.UploadSpeed.230400.upload.speed=230400 +um_squixl.menu.UploadSpeed.460800.linux=460800 +um_squixl.menu.UploadSpeed.460800.macosx=460800 +um_squixl.menu.UploadSpeed.460800.upload.speed=460800 +um_squixl.menu.UploadSpeed.512000.windows=512000 +um_squixl.menu.UploadSpeed.512000.upload.speed=512000 + +um_squixl.menu.DebugLevel.none=None +um_squixl.menu.DebugLevel.none.build.code_debug=0 +um_squixl.menu.DebugLevel.error=Error +um_squixl.menu.DebugLevel.error.build.code_debug=1 +um_squixl.menu.DebugLevel.warn=Warn +um_squixl.menu.DebugLevel.warn.build.code_debug=2 +um_squixl.menu.DebugLevel.info=Info +um_squixl.menu.DebugLevel.info.build.code_debug=3 +um_squixl.menu.DebugLevel.debug=Debug +um_squixl.menu.DebugLevel.debug.build.code_debug=4 +um_squixl.menu.DebugLevel.verbose=Verbose +um_squixl.menu.DebugLevel.verbose.build.code_debug=5 + +um_squixl.menu.EraseFlash.none=Disabled +um_squixl.menu.EraseFlash.none.upload.erase_cmd= +um_squixl.menu.EraseFlash.all=Enabled +um_squixl.menu.EraseFlash.all.upload.erase_cmd=-e + +############################################################## + um_tinypico.name=UM TinyPICO um_tinypico.bootloader.tool=esptool_py @@ -4890,7 +5202,7 @@ um_tinyc6.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no_o um_tinyc6.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 um_tinyc6.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB um_tinyc6.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -um_tinyc6.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +um_tinyc6.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 um_tinyc6.menu.PartitionScheme.zigbee=Zigbee 4MB with spiffs um_tinyc6.menu.PartitionScheme.zigbee.build.partitions=zigbee um_tinyc6.menu.PartitionScheme.zigbee.upload.maximum_size=1310720 @@ -5584,7 +5896,7 @@ lilygo_t_display_s3.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmake lilygo_t_display_s3.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 lilygo_t_display_s3.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB lilygo_t_display_s3.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -lilygo_t_display_s3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +lilygo_t_display_s3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 lilygo_t_display_s3.menu.DebugLevel.none=None lilygo_t_display_s3.menu.DebugLevel.none.build.code_debug=0 @@ -5706,7 +6018,7 @@ lilygo_t_eth_lite.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_ lilygo_t_eth_lite.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 lilygo_t_eth_lite.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB lilygo_t_eth_lite.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -lilygo_t_eth_lite.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +lilygo_t_eth_lite.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 lilygo_t_eth_lite.menu.DebugLevel.none=None lilygo_t_eth_lite.menu.DebugLevel.none.build.code_debug=0 @@ -6001,12 +6313,12 @@ twatchs3.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB) twatchs3.menu.UploadMode.cdc.upload.use_1200bps_touch=true twatchs3.menu.UploadMode.cdc.upload.wait_for_upload_port=true -twatchs3.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) -twatchs3.menu.PartitionScheme.fatflash.build.partitions=ffat -twatchs3.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 twatchs3.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) twatchs3.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB twatchs3.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728 +twatchs3.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) +twatchs3.menu.PartitionScheme.fatflash.build.partitions=ffat +twatchs3.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 twatchs3.menu.PartitionScheme.rainmaker=RainMaker twatchs3.menu.PartitionScheme.rainmaker.build.partitions=rainmaker twatchs3.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 @@ -6064,10 +6376,16 @@ twatchs3.menu.EraseFlash.none.upload.erase_cmd= twatchs3.menu.EraseFlash.all=Enabled twatchs3.menu.EraseFlash.all.upload.erase_cmd=-e -twatchs3.menu.Revision.Radio_SX1280=Radio-SX1280 -twatchs3.menu.Revision.Radio_SX1280.build.board=LILYGO_LORA_SX1280 twatchs3.menu.Revision.Radio_SX1262=Radio-SX1262 twatchs3.menu.Revision.Radio_SX1262.build.board=LILYGO_LORA_SX1262 +twatchs3.menu.Revision.Radio_SX1280=Radio-SX1280 +twatchs3.menu.Revision.Radio_SX1280.build.board=LILYGO_LORA_SX1280 +twatchs3.menu.Revision.Radio_CC1101=Radio-CC1101 +twatchs3.menu.Revision.Radio_CC1101.build.board=LILYGO_LORA_CC1101 +twatchs3.menu.Revision.Radio_LR1121=Radio-LR1121 +twatchs3.menu.Revision.Radio_LR1121.build.board=LILYGO_LORA_LR1121 +twatchs3.menu.Revision.Radio_SI4432=Radio-SI4432 +twatchs3.menu.Revision.Radio_SI4432.build.board=LILYGO_LORA_SI4432 ############################################################## @@ -6160,12 +6478,12 @@ twatch_ultra.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB) twatch_ultra.menu.UploadMode.cdc.upload.use_1200bps_touch=true twatch_ultra.menu.UploadMode.cdc.upload.wait_for_upload_port=true -twatch_ultra.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) -twatch_ultra.menu.PartitionScheme.fatflash.build.partitions=ffat -twatch_ultra.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 twatch_ultra.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) twatch_ultra.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB twatch_ultra.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728 +twatch_ultra.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) +twatch_ultra.menu.PartitionScheme.fatflash.build.partitions=ffat +twatch_ultra.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 twatch_ultra.menu.PartitionScheme.rainmaker=RainMaker twatch_ultra.menu.PartitionScheme.rainmaker.build.partitions=rainmaker twatch_ultra.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 @@ -6223,11 +6541,181 @@ twatch_ultra.menu.EraseFlash.none.upload.erase_cmd= twatch_ultra.menu.EraseFlash.all=Enabled twatch_ultra.menu.EraseFlash.all.upload.erase_cmd=-e -twatch_ultra.menu.Revision.Radio_SX1280=Radio-SX1280 -twatch_ultra.menu.Revision.Radio_SX1280.build.board=LILYGO_LORA_SX1280 twatch_ultra.menu.Revision.Radio_SX1262=Radio-SX1262 twatch_ultra.menu.Revision.Radio_SX1262.build.board=LILYGO_LORA_SX1262 +twatch_ultra.menu.Revision.Radio_SX1280=Radio-SX1280 +twatch_ultra.menu.Revision.Radio_SX1280.build.board=LILYGO_LORA_SX1280 +twatch_ultra.menu.Revision.Radio_CC1101=Radio-CC1101 +twatch_ultra.menu.Revision.Radio_CC1101.build.board=LILYGO_LORA_CC1101 +twatch_ultra.menu.Revision.Radio_LR1121=Radio-LR1121 +twatch_ultra.menu.Revision.Radio_LR1121.build.board=LILYGO_LORA_LR1121 +twatch_ultra.menu.Revision.Radio_SI4432=Radio-SI4432 +twatch_ultra.menu.Revision.Radio_SI4432.build.board=LILYGO_LORA_SI4432 + +############################################################## + +tlora_pager.name=LilyGo-T-LoRa-Pager + +tlora_pager.bootloader.tool=esptool_py +tlora_pager.bootloader.tool.default=esptool_py + +tlora_pager.upload.tool=esptool_py +tlora_pager.upload.tool.default=esptool_py +tlora_pager.upload.tool.network=esp_ota + +tlora_pager.upload.maximum_size=1310720 +tlora_pager.upload.maximum_data_size=327680 +tlora_pager.upload.flags= +tlora_pager.upload.extra_flags= +tlora_pager.upload.use_1200bps_touch=false +tlora_pager.upload.wait_for_upload_port=false + +tlora_pager.serial.disableDTR=false +tlora_pager.serial.disableRTS=false + +tlora_pager.build.tarch=xtensa +tlora_pager.build.bootloader_addr=0x0 +tlora_pager.build.target=esp32s3 +tlora_pager.build.mcu=esp32s3 +tlora_pager.build.core=esp32 +tlora_pager.build.variant=lilygo_tlora_pager +tlora_pager.build.board=T_LORA_PAGER + +tlora_pager.build.usb_mode=1 +tlora_pager.build.cdc_on_boot=1 +tlora_pager.build.msc_on_boot=0 +tlora_pager.build.dfu_on_boot=0 +tlora_pager.build.f_cpu=240000000L +tlora_pager.build.flash_size=16MB +tlora_pager.build.flash_freq=80m +tlora_pager.build.flash_mode=dio +tlora_pager.build.boot=qio +tlora_pager.build.boot_freq=80m +tlora_pager.build.partitions=app3M_fat9M_16MB +tlora_pager.build.defines=-DBOARD_HAS_PSRAM -DARDUINO_T_LORA_PAGER +tlora_pager.build.loop_core= +tlora_pager.build.event_core= +tlora_pager.build.psram_type=qspi +tlora_pager.build.memory_type={build.boot}_{build.psram_type} +## IDE 2.0 Seems to not update the value +tlora_pager.menu.JTAGAdapter.default=Disabled +tlora_pager.menu.JTAGAdapter.default.build.copy_jtag_files=0 +tlora_pager.menu.JTAGAdapter.builtin=Integrated USB JTAG +tlora_pager.menu.JTAGAdapter.builtin.build.openocdscript=esp32s3-builtin.cfg +tlora_pager.menu.JTAGAdapter.builtin.build.copy_jtag_files=1 + +tlora_pager.menu.LoopCore.1=Core 1 +tlora_pager.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 +tlora_pager.menu.LoopCore.0=Core 0 +tlora_pager.menu.LoopCore.0.build.loop_core=-DARDUINO_RUNNING_CORE=0 + +tlora_pager.menu.EventsCore.1=Core 1 +tlora_pager.menu.EventsCore.1.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1 +tlora_pager.menu.EventsCore.0=Core 0 +tlora_pager.menu.EventsCore.0.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=0 + +tlora_pager.menu.USBMode.hwcdc=Hardware CDC and JTAG +tlora_pager.menu.USBMode.hwcdc.build.usb_mode=1 +tlora_pager.menu.USBMode.default=USB-OTG (TinyUSB) +tlora_pager.menu.USBMode.default.build.usb_mode=0 + +tlora_pager.menu.CDCOnBoot.default=Enabled +tlora_pager.menu.CDCOnBoot.default.build.cdc_on_boot=1 +tlora_pager.menu.CDCOnBoot.cdc=Disabled +tlora_pager.menu.CDCOnBoot.cdc.build.cdc_on_boot=0 + +tlora_pager.menu.MSCOnBoot.default=Disabled +tlora_pager.menu.MSCOnBoot.default.build.msc_on_boot=0 +tlora_pager.menu.MSCOnBoot.msc=Enabled (Requires USB-OTG Mode) +tlora_pager.menu.MSCOnBoot.msc.build.msc_on_boot=1 + +tlora_pager.menu.DFUOnBoot.default=Disabled +tlora_pager.menu.DFUOnBoot.default.build.dfu_on_boot=0 +tlora_pager.menu.DFUOnBoot.dfu=Enabled (Requires USB-OTG Mode) +tlora_pager.menu.DFUOnBoot.dfu.build.dfu_on_boot=1 + +tlora_pager.menu.UploadMode.default=UART0 / Hardware CDC +tlora_pager.menu.UploadMode.default.upload.use_1200bps_touch=false +tlora_pager.menu.UploadMode.default.upload.wait_for_upload_port=false +tlora_pager.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB) +tlora_pager.menu.UploadMode.cdc.upload.use_1200bps_touch=true +tlora_pager.menu.UploadMode.cdc.upload.wait_for_upload_port=true + +tlora_pager.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) +tlora_pager.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB +tlora_pager.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728 +tlora_pager.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) +tlora_pager.menu.PartitionScheme.fatflash.build.partitions=ffat +tlora_pager.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 +tlora_pager.menu.PartitionScheme.rainmaker=RainMaker +tlora_pager.menu.PartitionScheme.rainmaker.build.partitions=rainmaker +tlora_pager.menu.PartitionScheme.rainmaker.upload.maximum_size=3145728 +tlora_pager.menu.PartitionScheme.esp_sr_16=ESP SR 16M (3MB APP/7MB SPIFFS/2.9MB MODEL) +tlora_pager.menu.PartitionScheme.esp_sr_16.upload.maximum_size=3145728 +tlora_pager.menu.PartitionScheme.esp_sr_16.upload.extra_flags=0xD10000 {build.path}/srmodels.bin +tlora_pager.menu.PartitionScheme.esp_sr_16.build.partitions=esp_sr_16 +tlora_pager.menu.PartitionScheme.custom=Custom +tlora_pager.menu.PartitionScheme.custom.build.partitions= +tlora_pager.menu.PartitionScheme.custom.upload.maximum_size=16777216 + +tlora_pager.menu.CPUFreq.240=240MHz (WiFi) +tlora_pager.menu.CPUFreq.240.build.f_cpu=240000000L +tlora_pager.menu.CPUFreq.160=160MHz (WiFi) +tlora_pager.menu.CPUFreq.160.build.f_cpu=160000000L +tlora_pager.menu.CPUFreq.80=80MHz (WiFi) +tlora_pager.menu.CPUFreq.80.build.f_cpu=80000000L +tlora_pager.menu.CPUFreq.40=40MHz +tlora_pager.menu.CPUFreq.40.build.f_cpu=40000000L +tlora_pager.menu.CPUFreq.20=20MHz +tlora_pager.menu.CPUFreq.20.build.f_cpu=20000000L +tlora_pager.menu.CPUFreq.10=10MHz +tlora_pager.menu.CPUFreq.10.build.f_cpu=10000000L + +tlora_pager.menu.UploadSpeed.921600=921600 +tlora_pager.menu.UploadSpeed.921600.upload.speed=921600 +tlora_pager.menu.UploadSpeed.115200=115200 +tlora_pager.menu.UploadSpeed.115200.upload.speed=115200 +tlora_pager.menu.UploadSpeed.256000.windows=256000 +tlora_pager.menu.UploadSpeed.256000.upload.speed=256000 +tlora_pager.menu.UploadSpeed.230400.windows.upload.speed=256000 +tlora_pager.menu.UploadSpeed.230400=230400 +tlora_pager.menu.UploadSpeed.230400.upload.speed=230400 +tlora_pager.menu.UploadSpeed.460800.linux=460800 +tlora_pager.menu.UploadSpeed.460800.macosx=460800 +tlora_pager.menu.UploadSpeed.460800.upload.speed=460800 +tlora_pager.menu.UploadSpeed.512000.windows=512000 +tlora_pager.menu.UploadSpeed.512000.upload.speed=512000 + +tlora_pager.menu.DebugLevel.none=None +tlora_pager.menu.DebugLevel.none.build.code_debug=0 +tlora_pager.menu.DebugLevel.error=Error +tlora_pager.menu.DebugLevel.error.build.code_debug=1 +tlora_pager.menu.DebugLevel.warn=Warn +tlora_pager.menu.DebugLevel.warn.build.code_debug=2 +tlora_pager.menu.DebugLevel.info=Info +tlora_pager.menu.DebugLevel.info.build.code_debug=3 +tlora_pager.menu.DebugLevel.debug=Debug +tlora_pager.menu.DebugLevel.debug.build.code_debug=4 +tlora_pager.menu.DebugLevel.verbose=Verbose +tlora_pager.menu.DebugLevel.verbose.build.code_debug=5 + +tlora_pager.menu.EraseFlash.none=Disabled +tlora_pager.menu.EraseFlash.none.upload.erase_cmd= +tlora_pager.menu.EraseFlash.all=Enabled +tlora_pager.menu.EraseFlash.all.upload.erase_cmd=-e + + +tlora_pager.menu.Revision.Radio_SX1262=Radio-SX1262 +tlora_pager.menu.Revision.Radio_SX1262.build.board=LILYGO_LORA_SX1262 +tlora_pager.menu.Revision.Radio_SX1280=Radio-SX1280 +tlora_pager.menu.Revision.Radio_SX1280.build.board=LILYGO_LORA_SX1280 +tlora_pager.menu.Revision.Radio_CC1101=Radio-CC1101 +tlora_pager.menu.Revision.Radio_CC1101.build.board=LILYGO_LORA_CC1101 +tlora_pager.menu.Revision.Radio_LR1121=Radio-LR1121 +tlora_pager.menu.Revision.Radio_LR1121.build.board=LILYGO_LORA_LR1121 +tlora_pager.menu.Revision.Radio_SI4432=Radio-SI4432 +tlora_pager.menu.Revision.Radio_SI4432.build.board=LILYGO_LORA_SI4432 ############################################################## @@ -7886,7 +8374,7 @@ sparkfun_esp32c6_thing_plus.menu.PartitionScheme.rainmaker_4MB.build.partitions= sparkfun_esp32c6_thing_plus.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 sparkfun_esp32c6_thing_plus.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB sparkfun_esp32c6_thing_plus.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -sparkfun_esp32c6_thing_plus.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +sparkfun_esp32c6_thing_plus.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 sparkfun_esp32c6_thing_plus.menu.PartitionScheme.zigbee=Zigbee 4MB with spiffs sparkfun_esp32c6_thing_plus.menu.PartitionScheme.zigbee.build.partitions=zigbee sparkfun_esp32c6_thing_plus.menu.PartitionScheme.zigbee.upload.maximum_size=1310720 @@ -8296,7 +8784,7 @@ sparkfun_esp32_iot_redboard.menu.PartitionScheme.rainmaker_4MB.build.partitions= sparkfun_esp32_iot_redboard.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 sparkfun_esp32_iot_redboard.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB sparkfun_esp32_iot_redboard.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -sparkfun_esp32_iot_redboard.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +sparkfun_esp32_iot_redboard.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 sparkfun_esp32_iot_redboard.menu.CPUFreq.240=240MHz (WiFi/BT) sparkfun_esp32_iot_redboard.menu.CPUFreq.240.build.f_cpu=240000000L @@ -8476,7 +8964,7 @@ sparkfun_esp32c6_qwiic_pocket.menu.PartitionScheme.rainmaker_4MB.build.partition sparkfun_esp32c6_qwiic_pocket.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 sparkfun_esp32c6_qwiic_pocket.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB sparkfun_esp32c6_qwiic_pocket.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -sparkfun_esp32c6_qwiic_pocket.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +sparkfun_esp32c6_qwiic_pocket.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 sparkfun_esp32c6_qwiic_pocket.menu.PartitionScheme.zigbee=Zigbee 4MB with spiffs sparkfun_esp32c6_qwiic_pocket.menu.PartitionScheme.zigbee.build.partitions=zigbee sparkfun_esp32c6_qwiic_pocket.menu.PartitionScheme.zigbee.upload.maximum_size=1310720 @@ -8810,7 +9298,7 @@ nina_w10.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no_ot nina_w10.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 nina_w10.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB nina_w10.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -nina_w10.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +nina_w10.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 nina_w10.menu.CPUFreq.240=240MHz (WiFi/BT) nina_w10.menu.CPUFreq.240.build.f_cpu=240000000L @@ -9021,7 +9509,7 @@ nora_w10.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no_ot nora_w10.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 nora_w10.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB nora_w10.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -nora_w10.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +nora_w10.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 nora_w10.menu.CPUFreq.240=240MHz (WiFi) nora_w10.menu.CPUFreq.240.build.f_cpu=240000000L @@ -9993,7 +10481,7 @@ lolin_s3.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no_ot lolin_s3.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 lolin_s3.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB lolin_s3.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -lolin_s3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +lolin_s3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 lolin_s3.menu.CPUFreq.240=240MHz (WiFi) lolin_s3.menu.CPUFreq.240.build.f_cpu=240000000L @@ -10493,7 +10981,7 @@ lolin_s3_pro.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_n lolin_s3_pro.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 lolin_s3_pro.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB lolin_s3_pro.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -lolin_s3_pro.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +lolin_s3_pro.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 lolin_s3_pro.menu.CPUFreq.240=240MHz (WiFi) lolin_s3_pro.menu.CPUFreq.240.build.f_cpu=240000000L @@ -11873,7 +12361,7 @@ dfrobot_firebeetle2_esp32e.menu.PartitionScheme.rainmaker_4MB.build.partitions=r dfrobot_firebeetle2_esp32e.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 dfrobot_firebeetle2_esp32e.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB dfrobot_firebeetle2_esp32e.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -dfrobot_firebeetle2_esp32e.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +dfrobot_firebeetle2_esp32e.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 dfrobot_firebeetle2_esp32e.menu.CPUFreq.240=240MHz (WiFi/BT) dfrobot_firebeetle2_esp32e.menu.CPUFreq.240.build.f_cpu=240000000L @@ -12126,7 +12614,7 @@ dfrobot_firebeetle2_esp32s3.menu.PartitionScheme.rainmaker_4MB.build.partitions= dfrobot_firebeetle2_esp32s3.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 dfrobot_firebeetle2_esp32s3.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB dfrobot_firebeetle2_esp32s3.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -dfrobot_firebeetle2_esp32s3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +dfrobot_firebeetle2_esp32s3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 dfrobot_firebeetle2_esp32s3.menu.CPUFreq.240=240MHz (WiFi) dfrobot_firebeetle2_esp32s3.menu.CPUFreq.240.build.f_cpu=240000000L @@ -12487,7 +12975,7 @@ dfrobot_romeo_esp32s3.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainma dfrobot_romeo_esp32s3.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 dfrobot_romeo_esp32s3.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB dfrobot_romeo_esp32s3.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -dfrobot_romeo_esp32s3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +dfrobot_romeo_esp32s3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 dfrobot_romeo_esp32s3.menu.CPUFreq.240=240MHz (WiFi) dfrobot_romeo_esp32s3.menu.CPUFreq.240.build.f_cpu=240000000L @@ -12535,6 +13023,212 @@ dfrobot_romeo_esp32s3.menu.EraseFlash.none.upload.erase_cmd= dfrobot_romeo_esp32s3.menu.EraseFlash.all=Enabled dfrobot_romeo_esp32s3.menu.EraseFlash.all.upload.erase_cmd=-e +############################################################## +dfrobot_lorawan_esp32s3.name=DFRobot LoRaWAN ESP32-S3 +#dfrobot_lorawan_esp32s3.vid.0=0x303a +#dfrobot_lorawan_esp32s3.pid.0=0x1001 + +dfrobot_lorawan_esp32s3.bootloader.tool=esptool_py +dfrobot_lorawan_esp32s3.bootloader.tool.default=esptool_py + +dfrobot_lorawan_esp32s3.upload.tool=esptool_py +dfrobot_lorawan_esp32s3.upload.tool.default=esptool_py +dfrobot_lorawan_esp32s3.upload.tool.network=esp_ota + +dfrobot_lorawan_esp32s3.upload.speed=921600 +dfrobot_lorawan_esp32s3.upload.erase_cmd= +dfrobot_lorawan_esp32s3.upload.maximum_size=1310720 +dfrobot_lorawan_esp32s3.upload.maximum_data_size=327680 +dfrobot_lorawan_esp32s3.upload.flags= +dfrobot_lorawan_esp32s3.upload.extra_flags= +dfrobot_lorawan_esp32s3.upload.use_1200bps_touch=false +dfrobot_lorawan_esp32s3.upload.wait_for_upload_port=false + +dfrobot_lorawan_esp32s3.serial.disableDTR=false +dfrobot_lorawan_esp32s3.serial.disableRTS=false + +dfrobot_lorawan_esp32s3.build.tarch=xtensa +dfrobot_lorawan_esp32s3.build.bootloader_addr=0x0 +dfrobot_lorawan_esp32s3.build.target=esp32s3 +dfrobot_lorawan_esp32s3.build.mcu=esp32s3 +dfrobot_lorawan_esp32s3.build.core=esp32 +dfrobot_lorawan_esp32s3.build.variant=dfrobot_lorawan_esp32s3 +dfrobot_lorawan_esp32s3.build.board=DFROBOT_LORAWAN_ESP32S3 +dfrobot_lorawan_esp32s3.build.usb_mode=1 +dfrobot_lorawan_esp32s3.build.cdc_on_boot=1 +dfrobot_lorawan_esp32s3.build.msc_on_boot=0 +dfrobot_lorawan_esp32s3.build.dfu_on_boot=0 +dfrobot_lorawan_esp32s3.build.f_cpu=240000000L +dfrobot_lorawan_esp32s3.build.flash_size=4MB +dfrobot_lorawan_esp32s3.build.flash_freq=80m +dfrobot_lorawan_esp32s3.build.flash_mode=dio +dfrobot_lorawan_esp32s3.build.boot=qio +dfrobot_lorawan_esp32s3.build.boot_freq=80m +dfrobot_lorawan_esp32s3.build.partitions=default +dfrobot_lorawan_esp32s3.build.defines=-D{build.band} +dfrobot_lorawan_esp32s3.build.loop_core= +dfrobot_lorawan_esp32s3.build.event_core= +dfrobot_lorawan_esp32s3.build.psram_type=qspi +dfrobot_lorawan_esp32s3.build.memory_type={build.flash_type}_{build.psram_type} +dfrobot_lorawan_esp32s3.build.region= + +dfrobot_lorawan_esp32s3.menu.FlashMode.qio=QIO 80MHz +dfrobot_lorawan_esp32s3.menu.FlashMode.qio.build.flash_mode=dio +dfrobot_lorawan_esp32s3.menu.FlashMode.qio.build.boot=qio +dfrobot_lorawan_esp32s3.menu.FlashMode.qio.build.boot_freq=80m +dfrobot_lorawan_esp32s3.menu.FlashMode.qio.build.flash_freq=80m +dfrobot_lorawan_esp32s3.menu.FlashMode.qio.build.flash_type=qio +dfrobot_lorawan_esp32s3.menu.FlashMode.qio120=QIO 120MHz +dfrobot_lorawan_esp32s3.menu.FlashMode.qio120.build.flash_mode=dio +dfrobot_lorawan_esp32s3.menu.FlashMode.qio120.build.boot=qio +dfrobot_lorawan_esp32s3.menu.FlashMode.qio120.build.boot_freq=120m +dfrobot_lorawan_esp32s3.menu.FlashMode.qio120.build.flash_freq=80m +dfrobot_lorawan_esp32s3.menu.FlashMode.qio120.build.flash_type=qio +dfrobot_lorawan_esp32s3.menu.FlashMode.dio=DIO 80MHz +dfrobot_lorawan_esp32s3.menu.FlashMode.dio.build.flash_mode=dio +dfrobot_lorawan_esp32s3.menu.FlashMode.dio.build.boot=dio +dfrobot_lorawan_esp32s3.menu.FlashMode.dio.build.boot_freq=80m +dfrobot_lorawan_esp32s3.menu.FlashMode.dio.build.flash_freq=80m +dfrobot_lorawan_esp32s3.menu.FlashMode.dio.build.flash_type=qio + +dfrobot_lorawan_esp32s3.menu.FlashSize.4M=4MB (32Mb) +dfrobot_lorawan_esp32s3.menu.FlashSize.4M.build.flash_size=4MB + +dfrobot_lorawan_esp32s3.menu.LoopCore.1=Core 1 +dfrobot_lorawan_esp32s3.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 +dfrobot_lorawan_esp32s3.menu.LoopCore.0=Core 0 +dfrobot_lorawan_esp32s3.menu.LoopCore.0.build.loop_core=-DARDUINO_RUNNING_CORE=0 + +dfrobot_lorawan_esp32s3.menu.EventsCore.1=Core 1 +dfrobot_lorawan_esp32s3.menu.EventsCore.1.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1 +dfrobot_lorawan_esp32s3.menu.EventsCore.0=Core 0 +dfrobot_lorawan_esp32s3.menu.EventsCore.0.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=0 +dfrobot_lorawan_esp32s3.menu.USBMode.hwcdc=Hardware CDC and JTAG +dfrobot_lorawan_esp32s3.menu.USBMode.hwcdc.build.usb_mode=1 +dfrobot_lorawan_esp32s3.menu.USBMode.default=USB-OTG (TinyUSB) +dfrobot_lorawan_esp32s3.menu.USBMode.default.build.usb_mode=0 + +dfrobot_lorawan_esp32s3.menu.CDCOnBoot.default=Disabled +dfrobot_lorawan_esp32s3.menu.CDCOnBoot.default.build.cdc_on_boot=0 +dfrobot_lorawan_esp32s3.menu.CDCOnBoot.cdc=Enabled +dfrobot_lorawan_esp32s3.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 + +dfrobot_lorawan_esp32s3.menu.MSCOnBoot.default=Disabled +dfrobot_lorawan_esp32s3.menu.MSCOnBoot.default.build.msc_on_boot=0 +dfrobot_lorawan_esp32s3.menu.MSCOnBoot.msc=Enabled (Requires USB-OTG Mode) +dfrobot_lorawan_esp32s3.menu.MSCOnBoot.msc.build.msc_on_boot=1 + +dfrobot_lorawan_esp32s3.menu.DFUOnBoot.default=Disabled +dfrobot_lorawan_esp32s3.menu.DFUOnBoot.default.build.dfu_on_boot=0 +dfrobot_lorawan_esp32s3.menu.DFUOnBoot.dfu=Enabled (Requires USB-OTG Mode) +dfrobot_lorawan_esp32s3.menu.DFUOnBoot.dfu.build.dfu_on_boot=1 + +dfrobot_lorawan_esp32s3.menu.UploadMode.default=UART0 / Hardware CDC +dfrobot_lorawan_esp32s3.menu.UploadMode.default.upload.use_1200bps_touch=false +dfrobot_lorawan_esp32s3.menu.UploadMode.default.upload.wait_for_upload_port=false +dfrobot_lorawan_esp32s3.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB) +dfrobot_lorawan_esp32s3.menu.UploadMode.cdc.upload.use_1200bps_touch=true +dfrobot_lorawan_esp32s3.menu.UploadMode.cdc.upload.wait_for_upload_port=true + +dfrobot_lorawan_esp32s3.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) +dfrobot_lorawan_esp32s3.menu.PartitionScheme.default.build.partitions=default +dfrobot_lorawan_esp32s3.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) +dfrobot_lorawan_esp32s3.menu.PartitionScheme.defaultffat.build.partitions=default_ffat +dfrobot_lorawan_esp32s3.menu.PartitionScheme.minimal=Minimal (1.3MB APP/700KB SPIFFS) +dfrobot_lorawan_esp32s3.menu.PartitionScheme.minimal.build.partitions=minimal +dfrobot_lorawan_esp32s3.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS) +dfrobot_lorawan_esp32s3.menu.PartitionScheme.no_ota.build.partitions=no_ota +dfrobot_lorawan_esp32s3.menu.PartitionScheme.no_ota.upload.maximum_size=2097152 +dfrobot_lorawan_esp32s3.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS) +dfrobot_lorawan_esp32s3.menu.PartitionScheme.noota_3g.build.partitions=noota_3g +dfrobot_lorawan_esp32s3.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576 +dfrobot_lorawan_esp32s3.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS) +dfrobot_lorawan_esp32s3.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat +dfrobot_lorawan_esp32s3.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152 +dfrobot_lorawan_esp32s3.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS) +dfrobot_lorawan_esp32s3.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat +dfrobot_lorawan_esp32s3.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576 +dfrobot_lorawan_esp32s3.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS) +dfrobot_lorawan_esp32s3.menu.PartitionScheme.huge_app.build.partitions=huge_app +dfrobot_lorawan_esp32s3.menu.PartitionScheme.huge_app.upload.maximum_size=3145728 +dfrobot_lorawan_esp32s3.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS) +dfrobot_lorawan_esp32s3.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs +dfrobot_lorawan_esp32s3.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080 +dfrobot_lorawan_esp32s3.menu.PartitionScheme.rainmaker=RainMaker 4MB +dfrobot_lorawan_esp32s3.menu.PartitionScheme.rainmaker.build.partitions=rainmaker +dfrobot_lorawan_esp32s3.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 +dfrobot_lorawan_esp32s3.menu.PartitionScheme.rainmaker_4MB=RainMaker 4MB No OTA +dfrobot_lorawan_esp32s3.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no_ota +dfrobot_lorawan_esp32s3.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 + + +dfrobot_lorawan_esp32s3.menu.CPUFreq.240=240MHz (WiFi) +dfrobot_lorawan_esp32s3.menu.CPUFreq.240.build.f_cpu=240000000L +dfrobot_lorawan_esp32s3.menu.CPUFreq.160=160MHz (WiFi) +dfrobot_lorawan_esp32s3.menu.CPUFreq.160.build.f_cpu=160000000L +dfrobot_lorawan_esp32s3.menu.CPUFreq.80=80MHz (WiFi) +dfrobot_lorawan_esp32s3.menu.CPUFreq.80.build.f_cpu=80000000L +dfrobot_lorawan_esp32s3.menu.CPUFreq.40=40MHz +dfrobot_lorawan_esp32s3.menu.CPUFreq.40.build.f_cpu=40000000L +dfrobot_lorawan_esp32s3.menu.CPUFreq.20=20MHz +dfrobot_lorawan_esp32s3.menu.CPUFreq.20.build.f_cpu=20000000L +dfrobot_lorawan_esp32s3.menu.CPUFreq.10=10MHz +dfrobot_lorawan_esp32s3.menu.CPUFreq.10.build.f_cpu=10000000L + +dfrobot_lorawan_esp32s3.menu.UploadSpeed.921600=921600 +dfrobot_lorawan_esp32s3.menu.UploadSpeed.921600.upload.speed=921600 +dfrobot_lorawan_esp32s3.menu.UploadSpeed.115200=115200 +dfrobot_lorawan_esp32s3.menu.UploadSpeed.115200.upload.speed=115200 +dfrobot_lorawan_esp32s3.menu.UploadSpeed.256000.windows=256000 +dfrobot_lorawan_esp32s3.menu.UploadSpeed.256000.upload.speed=256000 +dfrobot_lorawan_esp32s3.menu.UploadSpeed.230400.windows.upload.speed=256000 +dfrobot_lorawan_esp32s3.menu.UploadSpeed.230400=230400 +dfrobot_lorawan_esp32s3.menu.UploadSpeed.230400.upload.speed=230400 +dfrobot_lorawan_esp32s3.menu.UploadSpeed.460800.linux=460800 +dfrobot_lorawan_esp32s3.menu.UploadSpeed.460800.macosx=460800 +dfrobot_lorawan_esp32s3.menu.UploadSpeed.460800.upload.speed=460800 +dfrobot_lorawan_esp32s3.menu.UploadSpeed.512000.windows=512000 +dfrobot_lorawan_esp32s3.menu.UploadSpeed.512000.upload.speed=512000 + +dfrobot_lorawan_esp32s3.menu.DebugLevel.none=None +dfrobot_lorawan_esp32s3.menu.DebugLevel.none.build.code_debug=0 +dfrobot_lorawan_esp32s3.menu.DebugLevel.error=Error +dfrobot_lorawan_esp32s3.menu.DebugLevel.error.build.code_debug=1 +dfrobot_lorawan_esp32s3.menu.DebugLevel.warn=Warn +dfrobot_lorawan_esp32s3.menu.DebugLevel.warn.build.code_debug=2 +dfrobot_lorawan_esp32s3.menu.DebugLevel.info=Info +dfrobot_lorawan_esp32s3.menu.DebugLevel.info.build.code_debug=3 +dfrobot_lorawan_esp32s3.menu.DebugLevel.debug=Debug +dfrobot_lorawan_esp32s3.menu.DebugLevel.debug.build.code_debug=4 +dfrobot_lorawan_esp32s3.menu.DebugLevel.verbose=Verbose +dfrobot_lorawan_esp32s3.menu.DebugLevel.verbose.build.code_debug=5 + +dfrobot_lorawan_esp32s3.menu.EraseFlash.none=Disabled +dfrobot_lorawan_esp32s3.menu.EraseFlash.none.upload.erase_cmd= +dfrobot_lorawan_esp32s3.menu.EraseFlash.all=Enabled +dfrobot_lorawan_esp32s3.menu.EraseFlash.all.upload.erase_cmd=-e + +dfrobot_lorawan_esp32s3.menu.LORAWAN_REGION.0=REGION_EU868 +dfrobot_lorawan_esp32s3.menu.LORAWAN_REGION.0.build.band=REGION_EU868 +dfrobot_lorawan_esp32s3.menu.LORAWAN_REGION.1=REGION_EU433 +dfrobot_lorawan_esp32s3.menu.LORAWAN_REGION.1.build.band=REGION_EU433 +dfrobot_lorawan_esp32s3.menu.LORAWAN_REGION.2=REGION_CN470 +dfrobot_lorawan_esp32s3.menu.LORAWAN_REGION.2.build.band=REGION_CN470 +dfrobot_lorawan_esp32s3.menu.LORAWAN_REGION.3=REGION_US915 +dfrobot_lorawan_esp32s3.menu.LORAWAN_REGION.3.build.band=REGION_US915 +dfrobot_lorawan_esp32s3.menu.LORAWAN_REGION.4=REGION_AU915 +dfrobot_lorawan_esp32s3.menu.LORAWAN_REGION.4.build.band=REGION_AU915 +dfrobot_lorawan_esp32s3.menu.LORAWAN_REGION.5=REGION_CN779 +dfrobot_lorawan_esp32s3.menu.LORAWAN_REGION.5.build.band=REGION_CN779 +dfrobot_lorawan_esp32s3.menu.LORAWAN_REGION.6=REGION_AS923 +dfrobot_lorawan_esp32s3.menu.LORAWAN_REGION.6.build.band=REGION_AS923 +dfrobot_lorawan_esp32s3.menu.LORAWAN_REGION.7=REGION_KR920 +dfrobot_lorawan_esp32s3.menu.LORAWAN_REGION.7.build.band=REGION_KR920 +dfrobot_lorawan_esp32s3.menu.LORAWAN_REGION.8=REGION_IN865 +dfrobot_lorawan_esp32s3.menu.LORAWAN_REGION.8.build.band=REGION_IN865 +dfrobot_lorawan_esp32s3.menu.LORAWAN_REGION.9=REGION_US915_HYBRID +dfrobot_lorawan_esp32s3.menu.LORAWAN_REGION.9.build.band=REGION_US915_HYBRID + ############################################################## firebeetle32.name=FireBeetle-ESP32 @@ -17171,6 +17865,140 @@ sparklemotionmini.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) sparklemotionmini.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR sparklemotionmini.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api.zczr -lzboss_stack.zczr -lzboss_port.remote +############################################################## +# Adafruit Sparkle Motion Stick w/ESP32 + +sparklemotionstick.name=Adafruit Sparkle Motion Stick (ESP32) + +sparklemotionstick.bootloader.tool=esptool_py +sparklemotionstick.bootloader.tool.default=esptool_py + +sparklemotionstick.upload.tool=esptool_py +sparklemotionstick.upload.tool.default=esptool_py +sparklemotionstick.upload.tool.network=esp_ota + +sparklemotionstick.upload.maximum_size=1310720 +sparklemotionstick.upload.maximum_data_size=327680 +sparklemotionstick.upload.flags= +sparklemotionstick.upload.extra_flags= + +sparklemotionstick.serial.disableDTR=true +sparklemotionstick.serial.disableRTS=true + +sparklemotionstick.build.tarch=xtensa +sparklemotionstick.build.bootloader_addr=0x1000 +sparklemotionstick.build.target=esp32 +sparklemotionstick.build.mcu=esp32 +sparklemotionstick.build.core=esp32 +sparklemotionstick.build.variant=adafruit_sparklemotionstick_esp32 +sparklemotionstick.build.board=SPARKLEMOTIONSTICK_ESP32 + +sparklemotionstick.build.f_cpu=240000000L +sparklemotionstick.build.flash_size=4MB +sparklemotionstick.build.flash_freq=80m +sparklemotionstick.build.flash_mode=dio +sparklemotionstick.build.boot=dio +sparklemotionstick.build.partitions=default +sparklemotionstick.build.defines= +sparklemotionstick.build.loop_core= +sparklemotionstick.build.event_core= + +sparklemotionstick.menu.LoopCore.1=Core 1 +sparklemotionstick.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 +sparklemotionstick.menu.LoopCore.0=Core 0 +sparklemotionstick.menu.LoopCore.0.build.loop_core=-DARDUINO_RUNNING_CORE=0 + +sparklemotionstick.menu.EventsCore.1=Core 1 +sparklemotionstick.menu.EventsCore.1.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1 +sparklemotionstick.menu.EventsCore.0=Core 0 +sparklemotionstick.menu.EventsCore.0.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=0 + +sparklemotionstick.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) +sparklemotionstick.menu.PartitionScheme.default.build.partitions=default +sparklemotionstick.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) +sparklemotionstick.menu.PartitionScheme.defaultffat.build.partitions=default_ffat +sparklemotionstick.menu.PartitionScheme.minimal=Minimal (1.3MB APP/700KB SPIFFS) +sparklemotionstick.menu.PartitionScheme.minimal.build.partitions=minimal +sparklemotionstick.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS) +sparklemotionstick.menu.PartitionScheme.no_ota.build.partitions=no_ota +sparklemotionstick.menu.PartitionScheme.no_ota.upload.maximum_size=2097152 +sparklemotionstick.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS) +sparklemotionstick.menu.PartitionScheme.noota_3g.build.partitions=noota_3g +sparklemotionstick.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576 +sparklemotionstick.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS) +sparklemotionstick.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat +sparklemotionstick.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152 +sparklemotionstick.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS) +sparklemotionstick.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat +sparklemotionstick.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576 +sparklemotionstick.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS) +sparklemotionstick.menu.PartitionScheme.huge_app.build.partitions=huge_app +sparklemotionstick.menu.PartitionScheme.huge_app.upload.maximum_size=3145728 +sparklemotionstick.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS) +sparklemotionstick.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs +sparklemotionstick.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080 + +sparklemotionstick.menu.CPUFreq.240=240MHz (WiFi/BT) +sparklemotionstick.menu.CPUFreq.240.build.f_cpu=240000000L +sparklemotionstick.menu.CPUFreq.160=160MHz (WiFi/BT) +sparklemotionstick.menu.CPUFreq.160.build.f_cpu=160000000L +sparklemotionstick.menu.CPUFreq.80=80MHz (WiFi/BT) +sparklemotionstick.menu.CPUFreq.80.build.f_cpu=80000000L +sparklemotionstick.menu.CPUFreq.40=40MHz +sparklemotionstick.menu.CPUFreq.40.build.f_cpu=40000000L +sparklemotionstick.menu.CPUFreq.20=20MHz +sparklemotionstick.menu.CPUFreq.20.build.f_cpu=20000000L +sparklemotionstick.menu.CPUFreq.10=10MHz +sparklemotionstick.menu.CPUFreq.10.build.f_cpu=10000000L + +sparklemotionstick.menu.FlashFreq.80=80MHz +sparklemotionstick.menu.FlashFreq.80.build.flash_freq=80m +sparklemotionstick.menu.FlashFreq.40=40MHz +sparklemotionstick.menu.FlashFreq.40.build.flash_freq=40m + +sparklemotionstick.menu.FlashSize.4M=4MB (32Mb) +sparklemotionstick.menu.FlashSize.4M.build.flash_size=4MB + +sparklemotionstick.menu.UploadSpeed.921600=921600 +sparklemotionstick.menu.UploadSpeed.921600.upload.speed=921600 +sparklemotionstick.menu.UploadSpeed.115200=115200 +sparklemotionstick.menu.UploadSpeed.115200.upload.speed=115200 +sparklemotionstick.menu.UploadSpeed.256000.windows=256000 +sparklemotionstick.menu.UploadSpeed.256000.upload.speed=256000 +sparklemotionstick.menu.UploadSpeed.230400.windows.upload.speed=256000 +sparklemotionstick.menu.UploadSpeed.230400=230400 +sparklemotionstick.menu.UploadSpeed.230400.upload.speed=230400 +sparklemotionstick.menu.UploadSpeed.460800.linux=460800 +sparklemotionstick.menu.UploadSpeed.460800.macosx=460800 +sparklemotionstick.menu.UploadSpeed.460800.upload.speed=460800 +sparklemotionstick.menu.UploadSpeed.512000.windows=512000 +sparklemotionstick.menu.UploadSpeed.512000.upload.speed=512000 + +sparklemotionstick.menu.DebugLevel.none=None +sparklemotionstick.menu.DebugLevel.none.build.code_debug=0 +sparklemotionstick.menu.DebugLevel.error=Error +sparklemotionstick.menu.DebugLevel.error.build.code_debug=1 +sparklemotionstick.menu.DebugLevel.warn=Warn +sparklemotionstick.menu.DebugLevel.warn.build.code_debug=2 +sparklemotionstick.menu.DebugLevel.info=Info +sparklemotionstick.menu.DebugLevel.info.build.code_debug=3 +sparklemotionstick.menu.DebugLevel.debug=Debug +sparklemotionstick.menu.DebugLevel.debug.build.code_debug=4 +sparklemotionstick.menu.DebugLevel.verbose=Verbose +sparklemotionstick.menu.DebugLevel.verbose.build.code_debug=5 + +sparklemotionstick.menu.EraseFlash.none=Disabled +sparklemotionstick.menu.EraseFlash.none.upload.erase_cmd= +sparklemotionstick.menu.EraseFlash.all=Enabled +sparklemotionstick.menu.EraseFlash.all.upload.erase_cmd=-e + +sparklemotionstick.menu.ZigbeeMode.default=Disabled +sparklemotionstick.menu.ZigbeeMode.default.build.zigbee_mode= +sparklemotionstick.menu.ZigbeeMode.default.build.zigbee_libs= +sparklemotionstick.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) +sparklemotionstick.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR +sparklemotionstick.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api.zczr -lzboss_stack.zczr -lzboss_port.remote + ############################################################## nodemcu-32s.name=NodeMCU-32S @@ -17554,7 +18382,7 @@ nologo_esp32s3_pico.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmake nologo_esp32s3_pico.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 nologo_esp32s3_pico.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB nologo_esp32s3_pico.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -nologo_esp32s3_pico.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +nologo_esp32s3_pico.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 nologo_esp32s3_pico.menu.PartitionScheme.app5M_fat24M_32MB=32M Flash (4.8MB APP/22MB FATFS) nologo_esp32s3_pico.menu.PartitionScheme.app5M_fat24M_32MB.build.partitions=large_fat_32MB nologo_esp32s3_pico.menu.PartitionScheme.app5M_fat24M_32MB.upload.maximum_size=4718592 @@ -18273,7 +19101,7 @@ esp32-poe.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no_o esp32-poe.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 esp32-poe.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB esp32-poe.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -esp32-poe.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +esp32-poe.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 esp32-poe.menu.PartitionScheme.zigbee_zczr=Zigbee ZCZR 4MB with spiffs esp32-poe.menu.PartitionScheme.zigbee_zczr.build.partitions=zigbee_zczr esp32-poe.menu.PartitionScheme.zigbee_zczr.upload.maximum_size=1310720 @@ -18416,7 +19244,7 @@ esp32-poe-iso.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_ esp32-poe-iso.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 esp32-poe-iso.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB esp32-poe-iso.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -esp32-poe-iso.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +esp32-poe-iso.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 esp32-poe-iso.menu.PartitionScheme.zigbee_zczr=Zigbee ZCZR 4MB with spiffs esp32-poe-iso.menu.PartitionScheme.zigbee_zczr.build.partitions=zigbee_zczr esp32-poe-iso.menu.PartitionScheme.zigbee_zczr.upload.maximum_size=1310720 @@ -18694,7 +19522,7 @@ esp32s2-devkitlipo.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker esp32s2-devkitlipo.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 esp32s2-devkitlipo.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB esp32s2-devkitlipo.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -esp32s2-devkitlipo.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +esp32s2-devkitlipo.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 esp32s2-devkitlipo.menu.PartitionScheme.custom=Custom esp32s2-devkitlipo.menu.PartitionScheme.custom.build.partitions= esp32s2-devkitlipo.menu.PartitionScheme.custom.upload.maximum_size=16777216 @@ -18889,7 +19717,7 @@ esp32s2-devkitlipo-usb.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainm esp32s2-devkitlipo-usb.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 esp32s2-devkitlipo-usb.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB esp32s2-devkitlipo-usb.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -esp32s2-devkitlipo-usb.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +esp32s2-devkitlipo-usb.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 esp32s2-devkitlipo-usb.menu.PartitionScheme.custom=Custom esp32s2-devkitlipo-usb.menu.PartitionScheme.custom.build.partitions= esp32s2-devkitlipo-usb.menu.PartitionScheme.custom.upload.maximum_size=16777216 @@ -19144,7 +19972,7 @@ esp32s3-devkitlipo.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker esp32s3-devkitlipo.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 esp32s3-devkitlipo.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB esp32s3-devkitlipo.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -esp32s3-devkitlipo.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +esp32s3-devkitlipo.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 esp32s3-devkitlipo.menu.PartitionScheme.app5M_fat24M_32MB=32M Flash (4.8MB APP/22MB FATFS) esp32s3-devkitlipo.menu.PartitionScheme.app5M_fat24M_32MB.build.partitions=large_fat_32MB esp32s3-devkitlipo.menu.PartitionScheme.app5M_fat24M_32MB.upload.maximum_size=4718592 @@ -19302,7 +20130,7 @@ esp32c3-devkitlipo.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker esp32c3-devkitlipo.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 esp32c3-devkitlipo.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB esp32c3-devkitlipo.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -esp32c3-devkitlipo.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +esp32c3-devkitlipo.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 esp32c3-devkitlipo.menu.PartitionScheme.custom=Custom esp32c3-devkitlipo.menu.PartitionScheme.custom.build.partitions= esp32c3-devkitlipo.menu.PartitionScheme.custom.upload.maximum_size=16777216 @@ -19475,7 +20303,7 @@ esp32c6-evb.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no esp32c6-evb.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 esp32c6-evb.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB esp32c6-evb.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -esp32c6-evb.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +esp32c6-evb.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 esp32c6-evb.menu.PartitionScheme.zigbee=Zigbee 4MB with spiffs esp32c6-evb.menu.PartitionScheme.zigbee.build.partitions=zigbee esp32c6-evb.menu.PartitionScheme.zigbee.upload.maximum_size=1310720 @@ -19658,7 +20486,7 @@ esp32h2-devkitlipo.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=314 #esp32h2-devkitlipo.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 #esp32h2-devkitlipo.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB #esp32h2-devkitlipo.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -#esp32h2-devkitlipo.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +#esp32h2-devkitlipo.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 esp32h2-devkitlipo.menu.PartitionScheme.zigbee=Zigbee 4MB with spiffs esp32h2-devkitlipo.menu.PartitionScheme.zigbee.build.partitions=zigbee esp32h2-devkitlipo.menu.PartitionScheme.zigbee.upload.maximum_size=1310720 @@ -19833,7 +20661,7 @@ esp32-sbc-fabgl.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4M esp32-sbc-fabgl.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 esp32-sbc-fabgl.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB esp32-sbc-fabgl.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -esp32-sbc-fabgl.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +esp32-sbc-fabgl.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 esp32-sbc-fabgl.menu.PartitionScheme.zigbee_zczr=Zigbee ZCZR 4MB with spiffs esp32-sbc-fabgl.menu.PartitionScheme.zigbee_zczr.build.partitions=zigbee_zczr esp32-sbc-fabgl.menu.PartitionScheme.zigbee_zczr.upload.maximum_size=1310720 @@ -20076,7 +20904,7 @@ m5stack_core.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_n m5stack_core.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 m5stack_core.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB m5stack_core.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -m5stack_core.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +m5stack_core.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 m5stack_core.menu.PartitionScheme.custom=Custom m5stack_core.menu.PartitionScheme.custom.build.partitions= m5stack_core.menu.PartitionScheme.custom.upload.maximum_size=16777216 @@ -20252,7 +21080,7 @@ m5stack_fire.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_n m5stack_fire.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 m5stack_fire.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB m5stack_fire.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -m5stack_fire.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +m5stack_fire.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 m5stack_fire.menu.PartitionScheme.custom=Custom m5stack_fire.menu.PartitionScheme.custom.build.partitions= m5stack_fire.menu.PartitionScheme.custom.upload.maximum_size=16777216 @@ -20426,7 +21254,7 @@ m5stack_core2.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_ m5stack_core2.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 m5stack_core2.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB m5stack_core2.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -m5stack_core2.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +m5stack_core2.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 m5stack_core2.menu.PartitionScheme.custom=Custom m5stack_core2.menu.PartitionScheme.custom.build.partitions= m5stack_core2.menu.PartitionScheme.custom.upload.maximum_size=16777216 @@ -20600,7 +21428,7 @@ m5stack_tough.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_ m5stack_tough.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 m5stack_tough.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB m5stack_tough.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -m5stack_tough.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +m5stack_tough.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 m5stack_tough.menu.PartitionScheme.custom=Custom m5stack_tough.menu.PartitionScheme.custom.build.partitions= m5stack_tough.menu.PartitionScheme.custom.upload.maximum_size=16777216 @@ -20767,7 +21595,7 @@ m5stack_station.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4M m5stack_station.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 m5stack_station.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB m5stack_station.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -m5stack_station.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +m5stack_station.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 m5stack_station.menu.PartitionScheme.custom=Custom m5stack_station.menu.PartitionScheme.custom.build.partitions= m5stack_station.menu.PartitionScheme.custom.upload.maximum_size=16777216 @@ -21246,7 +22074,7 @@ m5stack_stickc_plus2.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmak m5stack_stickc_plus2.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 m5stack_stickc_plus2.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB m5stack_stickc_plus2.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -m5stack_stickc_plus2.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +m5stack_stickc_plus2.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 m5stack_stickc_plus2.menu.PartitionScheme.custom=Custom m5stack_stickc_plus2.menu.PartitionScheme.custom.build.partitions= m5stack_stickc_plus2.menu.PartitionScheme.custom.upload.maximum_size=16777216 @@ -21653,7 +22481,7 @@ m5stack_atoms3.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB m5stack_atoms3.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 m5stack_atoms3.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB m5stack_atoms3.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -m5stack_atoms3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +m5stack_atoms3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 m5stack_atoms3.menu.PartitionScheme.app5M_fat24M_32MB=32M Flash (4.8MB APP/22MB FATFS) m5stack_atoms3.menu.PartitionScheme.app5M_fat24M_32MB.build.partitions=large_fat_32MB m5stack_atoms3.menu.PartitionScheme.app5M_fat24M_32MB.upload.maximum_size=4718592 @@ -21886,7 +22714,7 @@ m5stack_cores3.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB m5stack_cores3.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 m5stack_cores3.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB m5stack_cores3.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -m5stack_cores3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +m5stack_cores3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 m5stack_cores3.menu.PartitionScheme.app5M_fat24M_32MB=32M Flash (4.8MB APP/22MB FATFS) m5stack_cores3.menu.PartitionScheme.app5M_fat24M_32MB.build.partitions=large_fat_32MB m5stack_cores3.menu.PartitionScheme.app5M_fat24M_32MB.upload.maximum_size=4718592 @@ -22428,7 +23256,7 @@ m5stack_unit_cams3.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker m5stack_unit_cams3.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 m5stack_unit_cams3.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB m5stack_unit_cams3.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -m5stack_unit_cams3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +m5stack_unit_cams3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 m5stack_unit_cams3.menu.PartitionScheme.app5M_fat24M_32MB=32M Flash (4.8MB APP/22MB FATFS) m5stack_unit_cams3.menu.PartitionScheme.app5M_fat24M_32MB.build.partitions=large_fat_32MB m5stack_unit_cams3.menu.PartitionScheme.app5M_fat24M_32MB.upload.maximum_size=4718592 @@ -22725,7 +23553,7 @@ m5stack_paper.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_ m5stack_paper.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 m5stack_paper.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB m5stack_paper.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -m5stack_paper.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +m5stack_paper.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 m5stack_paper.menu.PartitionScheme.custom=Custom m5stack_paper.menu.PartitionScheme.custom.build.partitions= m5stack_paper.menu.PartitionScheme.custom.upload.maximum_size=16777216 @@ -23443,7 +24271,7 @@ m5stack_stamp_s3.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4 m5stack_stamp_s3.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 m5stack_stamp_s3.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB m5stack_stamp_s3.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -m5stack_stamp_s3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +m5stack_stamp_s3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 m5stack_stamp_s3.menu.PartitionScheme.app5M_fat24M_32MB=32M Flash (4.8MB APP/22MB FATFS) m5stack_stamp_s3.menu.PartitionScheme.app5M_fat24M_32MB.build.partitions=large_fat_32MB m5stack_stamp_s3.menu.PartitionScheme.app5M_fat24M_32MB.upload.maximum_size=4718592 @@ -23680,7 +24508,7 @@ m5stack_capsule.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4M m5stack_capsule.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 m5stack_capsule.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB m5stack_capsule.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -m5stack_capsule.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +m5stack_capsule.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 m5stack_capsule.menu.PartitionScheme.app5M_fat24M_32MB=32M Flash (4.8MB APP/22MB FATFS) m5stack_capsule.menu.PartitionScheme.app5M_fat24M_32MB.build.partitions=large_fat_32MB m5stack_capsule.menu.PartitionScheme.app5M_fat24M_32MB.upload.maximum_size=4718592 @@ -23920,7 +24748,7 @@ m5stack_cardputer.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_ m5stack_cardputer.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 m5stack_cardputer.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB m5stack_cardputer.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -m5stack_cardputer.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +m5stack_cardputer.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 m5stack_cardputer.menu.PartitionScheme.app5M_fat24M_32MB=32M Flash (4.8MB APP/22MB FATFS) m5stack_cardputer.menu.PartitionScheme.app5M_fat24M_32MB.build.partitions=large_fat_32MB m5stack_cardputer.menu.PartitionScheme.app5M_fat24M_32MB.upload.maximum_size=4718592 @@ -24157,7 +24985,7 @@ m5stack_dial.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_n m5stack_dial.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 m5stack_dial.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB m5stack_dial.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -m5stack_dial.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +m5stack_dial.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 m5stack_dial.menu.PartitionScheme.app5M_fat24M_32MB=32M Flash (4.8MB APP/22MB FATFS) m5stack_dial.menu.PartitionScheme.app5M_fat24M_32MB.build.partitions=large_fat_32MB m5stack_dial.menu.PartitionScheme.app5M_fat24M_32MB.upload.maximum_size=4718592 @@ -24394,7 +25222,7 @@ m5stack_dinmeter.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4 m5stack_dinmeter.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 m5stack_dinmeter.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB m5stack_dinmeter.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -m5stack_dinmeter.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +m5stack_dinmeter.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 m5stack_dinmeter.menu.PartitionScheme.app5M_fat24M_32MB=32M Flash (4.8MB APP/22MB FATFS) m5stack_dinmeter.menu.PartitionScheme.app5M_fat24M_32MB.build.partitions=large_fat_32MB m5stack_dinmeter.menu.PartitionScheme.app5M_fat24M_32MB.upload.maximum_size=4718592 @@ -28219,7 +29047,7 @@ bpi_leaf_s3.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no bpi_leaf_s3.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 bpi_leaf_s3.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB bpi_leaf_s3.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -bpi_leaf_s3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +bpi_leaf_s3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 bpi_leaf_s3.menu.CPUFreq.240=240MHz (WiFi) bpi_leaf_s3.menu.CPUFreq.240.build.f_cpu=240000000L @@ -28976,7 +29804,7 @@ fri3d_2024_esp32s3.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker fri3d_2024_esp32s3.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 fri3d_2024_esp32s3.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB fri3d_2024_esp32s3.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -fri3d_2024_esp32s3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +fri3d_2024_esp32s3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 fri3d_2024_esp32s3.menu.CPUFreq.240=240MHz (WiFi) fri3d_2024_esp32s3.menu.CPUFreq.240.build.f_cpu=240000000L @@ -30743,7 +31571,7 @@ wifiduino32c3.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_ wifiduino32c3.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 wifiduino32c3.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB wifiduino32c3.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -wifiduino32c3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +wifiduino32c3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 wifiduino32c3.menu.CPUFreq.160=160MHz (WiFi) wifiduino32c3.menu.CPUFreq.160.build.f_cpu=160000000L @@ -30974,7 +31802,7 @@ wifiduino32s3.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_ wifiduino32s3.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 wifiduino32s3.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB wifiduino32s3.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -wifiduino32s3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +wifiduino32s3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 wifiduino32s3.menu.CPUFreq.240=240MHz (WiFi) wifiduino32s3.menu.CPUFreq.240.build.f_cpu=240000000L @@ -32187,7 +33015,7 @@ kb32.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no_ota kb32.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 kb32.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB kb32.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -kb32.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +kb32.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 kb32.menu.CPUFreq.240=240MHz (WiFi/BT) kb32.menu.CPUFreq.240.build.f_cpu=240000000L @@ -32365,7 +33193,7 @@ deneyapkart.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no deneyapkart.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 deneyapkart.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB deneyapkart.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -deneyapkart.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +deneyapkart.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 deneyapkart.menu.CPUFreq.240=240MHz (WiFi/BT) deneyapkart.menu.CPUFreq.240.build.f_cpu=240000000L @@ -32543,7 +33371,7 @@ deneyapkart1A.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_ deneyapkart1A.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 deneyapkart1A.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB deneyapkart1A.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -deneyapkart1A.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +deneyapkart1A.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 deneyapkart1A.menu.CPUFreq.240=240MHz (WiFi/BT) deneyapkart1A.menu.CPUFreq.240.build.f_cpu=240000000L @@ -32806,7 +33634,7 @@ deneyapkart1Av2.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4M deneyapkart1Av2.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 deneyapkart1Av2.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB deneyapkart1Av2.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -deneyapkart1Av2.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +deneyapkart1Av2.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 deneyapkart1Av2.menu.CPUFreq.240=240MHz (WiFi) deneyapkart1Av2.menu.CPUFreq.240.build.f_cpu=240000000L @@ -32975,7 +33803,7 @@ deneyapmini.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no deneyapmini.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 deneyapmini.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB deneyapmini.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -deneyapmini.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +deneyapmini.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 deneyapmini.menu.CPUFreq.240=240MHz (WiFi) deneyapmini.menu.CPUFreq.240.build.f_cpu=240000000L @@ -33165,7 +33993,7 @@ deneyapminiv2.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_ deneyapminiv2.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 deneyapminiv2.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB deneyapminiv2.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -deneyapminiv2.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +deneyapminiv2.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 deneyapminiv2.menu.CPUFreq.240=240MHz (WiFi) deneyapminiv2.menu.CPUFreq.240.build.f_cpu=240000000L @@ -33334,7 +34162,7 @@ deneyapkartg.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_n deneyapkartg.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 deneyapkartg.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB deneyapkartg.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -deneyapkartg.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +deneyapkartg.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 deneyapkartg.menu.CPUFreq.160=160MHz (WiFi) deneyapkartg.menu.CPUFreq.160.build.f_cpu=160000000L @@ -34082,7 +34910,7 @@ tamc_termod_s3.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB tamc_termod_s3.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 tamc_termod_s3.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB tamc_termod_s3.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -tamc_termod_s3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +tamc_termod_s3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 tamc_termod_s3.menu.CPUFreq.240=240MHz (WiFi) tamc_termod_s3.menu.CPUFreq.240.build.f_cpu=240000000L @@ -34780,7 +35608,7 @@ XIAO_ESP32C3.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_n XIAO_ESP32C3.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 XIAO_ESP32C3.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB XIAO_ESP32C3.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -XIAO_ESP32C3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +XIAO_ESP32C3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 XIAO_ESP32C3.menu.CPUFreq.160=160MHz (WiFi) XIAO_ESP32C3.menu.CPUFreq.160.build.f_cpu=160000000L @@ -35258,6 +36086,8 @@ XIAO_ESP32S3_Plus.menu.FlashMode.dio.build.flash_freq=80m XIAO_ESP32S3_Plus.menu.FlashSize.8M=8MB (64Mb) XIAO_ESP32S3_Plus.menu.FlashSize.8M.build.flash_size=8MB +XIAO_ESP32S3_Plus.menu.FlashSize.16M=16MB (128Mb) +XIAO_ESP32S3_Plus.menu.FlashSize.16M.build.flash_size=16MB XIAO_ESP32S3_Plus.menu.LoopCore.1=Core 1 XIAO_ESP32S3_Plus.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 @@ -35296,6 +36126,12 @@ XIAO_ESP32S3_Plus.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB) XIAO_ESP32S3_Plus.menu.UploadMode.cdc.upload.use_1200bps_touch=true XIAO_ESP32S3_Plus.menu.UploadMode.cdc.upload.wait_for_upload_port=true +XIAO_ESP32S3_Plus.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) +XIAO_ESP32S3_Plus.menu.PartitionScheme.fatflash.build.partitions=ffat +XIAO_ESP32S3_Plus.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 +XIAO_ESP32S3_Plus.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) +XIAO_ESP32S3_Plus.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB +XIAO_ESP32S3_Plus.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728 XIAO_ESP32S3_Plus.menu.PartitionScheme.default_8MB=Default with spiffs (3MB APP/1.5MB SPIFFS) XIAO_ESP32S3_Plus.menu.PartitionScheme.default_8MB.build.partitions=default_8MB XIAO_ESP32S3_Plus.menu.PartitionScheme.default_8MB.upload.maximum_size=3342336 @@ -36508,7 +37344,7 @@ unphone8.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no_ot unphone8.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 unphone8.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB unphone8.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -unphone8.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +unphone8.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 unphone8.menu.PartitionScheme.max_app_8MB=Maximum APP (7.9MB APP No OTA/No FS) unphone8.menu.PartitionScheme.max_app_8MB.build.partitions=max_app_8MB @@ -36664,7 +37500,7 @@ unphone9.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no_ot unphone9.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 unphone9.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB unphone9.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -unphone9.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +unphone9.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 unphone9.menu.PartitionScheme.max_app_8MB=Maximum APP (7.9MB APP No OTA/No FS) unphone9.menu.PartitionScheme.max_app_8MB.build.partitions=max_app_8MB @@ -37393,7 +38229,7 @@ VALTRACK_V4_VTS_ESP32_C3.menu.PartitionScheme.rainmaker_4MB.build.partitions=rai VALTRACK_V4_VTS_ESP32_C3.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 VALTRACK_V4_VTS_ESP32_C3.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB VALTRACK_V4_VTS_ESP32_C3.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -VALTRACK_V4_VTS_ESP32_C3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +VALTRACK_V4_VTS_ESP32_C3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 VALTRACK_V4_VTS_ESP32_C3.menu.CPUFreq.160=160MHz (WiFi) VALTRACK_V4_VTS_ESP32_C3.menu.CPUFreq.160.build.f_cpu=160000000L @@ -37544,7 +38380,7 @@ VALTRACK_V4_MFW_ESP32_C3.menu.PartitionScheme.rainmaker_4MB.build.partitions=rai VALTRACK_V4_MFW_ESP32_C3.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 VALTRACK_V4_MFW_ESP32_C3.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB VALTRACK_V4_MFW_ESP32_C3.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -VALTRACK_V4_MFW_ESP32_C3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +VALTRACK_V4_MFW_ESP32_C3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 VALTRACK_V4_MFW_ESP32_C3.menu.CPUFreq.160=160MHz (WiFi) VALTRACK_V4_MFW_ESP32_C3.menu.CPUFreq.160.build.f_cpu=160000000L @@ -37775,7 +38611,7 @@ Edgebox-ESP-100.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4M Edgebox-ESP-100.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 Edgebox-ESP-100.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB Edgebox-ESP-100.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -Edgebox-ESP-100.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +Edgebox-ESP-100.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 Edgebox-ESP-100.menu.CPUFreq.240=240MHz (WiFi) Edgebox-ESP-100.menu.CPUFreq.240.build.f_cpu=240000000L @@ -38145,7 +38981,7 @@ nebulas3.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no_ot nebulas3.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 nebulas3.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB nebulas3.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -nebulas3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +nebulas3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 nebulas3.menu.CPUFreq.240=240MHz (WiFi) nebulas3.menu.CPUFreq.240.build.f_cpu=240000000L @@ -38371,7 +39207,7 @@ lionbits3.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no_o lionbits3.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 lionbits3.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB lionbits3.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -lionbits3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +lionbits3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 lionbits3.menu.CPUFreq.240=240MHz (WiFi) lionbits3.menu.CPUFreq.240.build.f_cpu=240000000L @@ -39669,7 +40505,7 @@ atd147_s3.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no_o atd147_s3.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 atd147_s3.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB atd147_s3.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -atd147_s3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +atd147_s3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 atd147_s3.menu.CPUFreq.240=240MHz (WiFi) atd147_s3.menu.CPUFreq.240.build.f_cpu=240000000L @@ -39852,7 +40688,7 @@ atd35s3.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no_ota atd35s3.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 atd35s3.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB atd35s3.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -atd35s3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +atd35s3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 atd35s3.menu.CPUFreq.240=240MHz (WiFi) atd35s3.menu.CPUFreq.240.build.f_cpu=240000000L @@ -40860,8 +41696,8 @@ Geekble_Nano_ESP32S3.upload.tool.default=esptool_py Geekble_Nano_ESP32S3.upload.tool.network=esp_ota Geekble_Nano_ESP32S3.upload.maximum_size=1310720 - Geekble_Nano_ESP32S3.upload.maximum_data_size=327680 +Geekble_Nano_ESP32S3.upload.speed=921600 Geekble_Nano_ESP32S3.upload.flags= Geekble_Nano_ESP32S3.upload.extra_flags= Geekble_Nano_ESP32S3.upload.use_1200bps_touch=false @@ -40887,61 +41723,18 @@ Geekble_Nano_ESP32S3.build.flash_size=4MB Geekble_Nano_ESP32S3.build.flash_freq=80m Geekble_Nano_ESP32S3.build.flash_mode=dio Geekble_Nano_ESP32S3.build.boot=qio -Geekble_Nano_ESP32S3.build.boot_freq=80m Geekble_Nano_ESP32S3.build.partitions=default Geekble_Nano_ESP32S3.build.defines= -Geekble_Nano_ESP32S3.build.loop_core= -Geekble_Nano_ESP32S3.build.event_core= -Geekble_Nano_ESP32S3.build.psram_type=qspi -Geekble_Nano_ESP32S3.build.memory_type={build.boot}_{build.psram_type} - -Geekble_Nano_ESP32S3.menu.PSRAM.disabled=Disabled -Geekble_Nano_ESP32S3.menu.PSRAM.disabled.build.defines= -Geekble_Nano_ESP32S3.menu.PSRAM.disabled.build.psram_type=qspi -Geekble_Nano_ESP32S3.menu.PSRAM.enabled=Enabled -Geekble_Nano_ESP32S3.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM -Geekble_Nano_ESP32S3.menu.PSRAM.enabled.build.psram_type=qspi - -Geekble_Nano_ESP32S3.menu.FlashMode.qio=QIO 80MHz -Geekble_Nano_ESP32S3.menu.FlashMode.qio.build.flash_mode=dio -Geekble_Nano_ESP32S3.menu.FlashMode.qio.build.boot=qio -Geekble_Nano_ESP32S3.menu.FlashMode.qio.build.boot_freq=80m -Geekble_Nano_ESP32S3.menu.FlashMode.qio.build.flash_freq=80m -Geekble_Nano_ESP32S3.menu.FlashMode.qio120=QIO 120MHz -Geekble_Nano_ESP32S3.menu.FlashMode.qio120.build.flash_mode=dio -Geekble_Nano_ESP32S3.menu.FlashMode.qio120.build.boot=qio -Geekble_Nano_ESP32S3.menu.FlashMode.qio120.build.boot_freq=120m -Geekble_Nano_ESP32S3.menu.FlashMode.qio120.build.flash_freq=80m - -Geekble_Nano_ESP32S3.menu.LoopCore.1=Core 1 -Geekble_Nano_ESP32S3.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 -Geekble_Nano_ESP32S3.menu.LoopCore.0=Core 0 -Geekble_Nano_ESP32S3.menu.LoopCore.0.build.loop_core=-DARDUINO_RUNNING_CORE=0 - -Geekble_Nano_ESP32S3.menu.EventsCore.1=Core 1 -Geekble_Nano_ESP32S3.menu.EventsCore.1.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1 -Geekble_Nano_ESP32S3.menu.EventsCore.0=Core 0 -Geekble_Nano_ESP32S3.menu.EventsCore.0.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=0 +Geekble_Nano_ESP32S3.build.memory_type=qio_qspi +Geekble_Nano_ESP32S3.build.loop_core=-DARDUINO_RUNNING_CORE=1 +Geekble_Nano_ESP32S3.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1 -Geekble_Nano_ESP32S3.menu.USBMode.hwcdc=Hardware CDC and JTAG -Geekble_Nano_ESP32S3.menu.USBMode.hwcdc.build.usb_mode=1 Geekble_Nano_ESP32S3.menu.USBMode.default=USB-OTG (TinyUSB) Geekble_Nano_ESP32S3.menu.USBMode.default.build.usb_mode=0 - -Geekble_Nano_ESP32S3.menu.CDCOnBoot.default=Disabled -Geekble_Nano_ESP32S3.menu.CDCOnBoot.default.build.cdc_on_boot=0 -Geekble_Nano_ESP32S3.menu.CDCOnBoot.cdc=Enabled -Geekble_Nano_ESP32S3.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 - -Geekble_Nano_ESP32S3.menu.MSCOnBoot.default=Disabled -Geekble_Nano_ESP32S3.menu.MSCOnBoot.default.build.msc_on_boot=0 -Geekble_Nano_ESP32S3.menu.MSCOnBoot.msc=Enabled (Requires USB-OTG Mode) -Geekble_Nano_ESP32S3.menu.MSCOnBoot.msc.build.msc_on_boot=1 - -Geekble_Nano_ESP32S3.menu.DFUOnBoot.default=Disabled -Geekble_Nano_ESP32S3.menu.DFUOnBoot.default.build.dfu_on_boot=0 -Geekble_Nano_ESP32S3.menu.DFUOnBoot.dfu=Enabled (Requires USB-OTG Mode) -Geekble_Nano_ESP32S3.menu.DFUOnBoot.dfu.build.dfu_on_boot=1 +Geekble_Nano_ESP32S3.menu.USBMode.default.build.cdc_on_boot=1 +Geekble_Nano_ESP32S3.menu.USBMode.hwcdc=Hardware CDC and JTAG +Geekble_Nano_ESP32S3.menu.USBMode.hwcdc.build.usb_mode=1 +Geekble_Nano_ESP32S3.menu.USBMode.hwcdc.build.cdc_on_boot=1 Geekble_Nano_ESP32S3.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB) Geekble_Nano_ESP32S3.menu.UploadMode.cdc.upload.use_1200bps_touch=true @@ -40975,46 +41768,16 @@ Geekble_Nano_ESP32S3.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 Geekble_Nano_ESP32S3.menu.PartitionScheme.rainmaker_4MB=RainMaker 4MB No OTA Geekble_Nano_ESP32S3.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no_ota Geekble_Nano_ESP32S3.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 - Geekble_Nano_ESP32S3.menu.PartitionScheme.otanofs=OTA no FS (2MB APP with OTA) Geekble_Nano_ESP32S3.menu.PartitionScheme.otanofs.build.custom_partitions=ota_nofs_4MB Geekble_Nano_ESP32S3.menu.PartitionScheme.otanofs.upload.maximum_size=2031616 Geekble_Nano_ESP32S3.menu.PartitionScheme.all_app=Max APP (4MB APP no OTA) Geekble_Nano_ESP32S3.menu.PartitionScheme.all_app.build.custom_partitions=max_app_4MB Geekble_Nano_ESP32S3.menu.PartitionScheme.all_app.upload.maximum_size=4063232 - Geekble_Nano_ESP32S3.menu.PartitionScheme.custom=Custom Geekble_Nano_ESP32S3.menu.PartitionScheme.custom.build.partitions= Geekble_Nano_ESP32S3.menu.PartitionScheme.custom.upload.maximum_size=16777216 -Geekble_Nano_ESP32S3.menu.CPUFreq.240=240MHz (WiFi) -Geekble_Nano_ESP32S3.menu.CPUFreq.240.build.f_cpu=240000000L -Geekble_Nano_ESP32S3.menu.CPUFreq.160=160MHz (WiFi) -Geekble_Nano_ESP32S3.menu.CPUFreq.160.build.f_cpu=160000000L -Geekble_Nano_ESP32S3.menu.CPUFreq.80=80MHz (WiFi) -Geekble_Nano_ESP32S3.menu.CPUFreq.80.build.f_cpu=80000000L -Geekble_Nano_ESP32S3.menu.CPUFreq.40=40MHz -Geekble_Nano_ESP32S3.menu.CPUFreq.40.build.f_cpu=40000000L -Geekble_Nano_ESP32S3.menu.CPUFreq.20=20MHz -Geekble_Nano_ESP32S3.menu.CPUFreq.20.build.f_cpu=20000000L -Geekble_Nano_ESP32S3.menu.CPUFreq.10=10MHz -Geekble_Nano_ESP32S3.menu.CPUFreq.10.build.f_cpu=10000000L - -Geekble_Nano_ESP32S3.menu.UploadSpeed.921600=921600 -Geekble_Nano_ESP32S3.menu.UploadSpeed.921600.upload.speed=921600 -Geekble_Nano_ESP32S3.menu.UploadSpeed.115200=115200 -Geekble_Nano_ESP32S3.menu.UploadSpeed.115200.upload.speed=115200 -Geekble_Nano_ESP32S3.menu.UploadSpeed.256000.windows=256000 -Geekble_Nano_ESP32S3.menu.UploadSpeed.256000.upload.speed=256000 -Geekble_Nano_ESP32S3.menu.UploadSpeed.230400.windows.upload.speed=256000 -Geekble_Nano_ESP32S3.menu.UploadSpeed.230400=230400 -Geekble_Nano_ESP32S3.menu.UploadSpeed.230400.upload.speed=230400 -Geekble_Nano_ESP32S3.menu.UploadSpeed.460800.linux=460800 -Geekble_Nano_ESP32S3.menu.UploadSpeed.460800.macosx=460800 -Geekble_Nano_ESP32S3.menu.UploadSpeed.460800.upload.speed=460800 -Geekble_Nano_ESP32S3.menu.UploadSpeed.512000.windows=512000 -Geekble_Nano_ESP32S3.menu.UploadSpeed.512000.upload.speed=512000 - Geekble_Nano_ESP32S3.menu.DebugLevel.none=None Geekble_Nano_ESP32S3.menu.DebugLevel.none.build.code_debug=0 Geekble_Nano_ESP32S3.menu.DebugLevel.error=Error @@ -41033,7 +41796,6 @@ Geekble_Nano_ESP32S3.menu.EraseFlash.none.upload.erase_cmd= Geekble_Nano_ESP32S3.menu.EraseFlash.all=Enabled Geekble_Nano_ESP32S3.menu.EraseFlash.all.upload.erase_cmd=-e - ############################################################## waveshare_esp32_s3_zero.name=Waveshare ESP32-S3-Zero @@ -41555,7 +42317,7 @@ waveshare_esp32_s3_touch_lcd_169.menu.PartitionScheme.rainmaker.build.partitions waveshare_esp32_s3_touch_lcd_169.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 waveshare_esp32_s3_touch_lcd_169.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB waveshare_esp32_s3_touch_lcd_169.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -waveshare_esp32_s3_touch_lcd_169.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_touch_lcd_169.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 waveshare_esp32_s3_touch_lcd_169.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) waveshare_esp32_s3_touch_lcd_169.menu.PartitionScheme.fatflash.build.partitions=ffat waveshare_esp32_s3_touch_lcd_169.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 @@ -41754,7 +42516,7 @@ waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.rainmaker.build.partitio waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.fatflash.build.partitions=ffat waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 @@ -41953,7 +42715,7 @@ waveshare_esp32_s3_lcd_169.menu.PartitionScheme.rainmaker.build.partitions=rainm waveshare_esp32_s3_lcd_169.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 waveshare_esp32_s3_lcd_169.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB waveshare_esp32_s3_lcd_169.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -waveshare_esp32_s3_lcd_169.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_lcd_169.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 waveshare_esp32_s3_lcd_169.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) waveshare_esp32_s3_lcd_169.menu.PartitionScheme.fatflash.build.partitions=ffat waveshare_esp32_s3_lcd_169.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 @@ -42466,7 +43228,7 @@ aslcanx2.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no_ot aslcanx2.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 aslcanx2.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB aslcanx2.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -aslcanx2.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +aslcanx2.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 aslcanx2.menu.CPUFreq.240=240MHz (WiFi) aslcanx2.menu.CPUFreq.240.build.f_cpu=240000000L @@ -43015,8 +43777,8 @@ alfredo-nou3.upload.maximum_size=3342336 alfredo-nou3.upload.maximum_data_size=327680 alfredo-nou3.upload.flags= alfredo-nou3.upload.extra_flags= -alfredo-nou3.upload.use_1200bps_touch=false -alfredo-nou3.upload.wait_for_upload_port=false +alfredo-nou3.upload.use_1200bps_touch=true +alfredo-nou3.upload.wait_for_upload_port=true alfredo-nou3.serial.disableDTR=false alfredo-nou3.serial.disableRTS=false @@ -43029,7 +43791,7 @@ alfredo-nou3.build.core=esp32 alfredo-nou3.build.variant=alfredo-nou3 alfredo-nou3.build.board=ALFREDO_NOU3 -alfredo-nou3.build.usb_mode=1 +alfredo-nou3.build.usb_mode=0 alfredo-nou3.build.cdc_on_boot=1 alfredo-nou3.build.msc_on_boot=0 alfredo-nou3.build.dfu_on_boot=0 @@ -43056,10 +43818,10 @@ alfredo-nou3.menu.EventsCore.1.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1 alfredo-nou3.menu.EventsCore.0=Core 0 alfredo-nou3.menu.EventsCore.0.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=0 -alfredo-nou3.menu.USBMode.default=Hardware CDC and JTAG -alfredo-nou3.menu.USBMode.default.build.usb_mode=1 -alfredo-nou3.menu.USBMode.usbotg=USB-OTG (TinyUSB) -alfredo-nou3.menu.USBMode.usbotg.build.usb_mode=0 +alfredo-nou3.menu.USBMode.default=USB-OTG (TinyUSB) +alfredo-nou3.menu.USBMode.default.build.usb_mode=0 +alfredo-nou3.menu.USBMode.hwcdc=Hardware CDC and JTAG +alfredo-nou3.menu.USBMode.hwcdc.build.usb_mode=1 alfredo-nou3.menu.CDCOnBoot.cdc=Enabled alfredo-nou3.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 @@ -43076,12 +43838,12 @@ alfredo-nou3.menu.DFUOnBoot.default.build.dfu_on_boot=0 alfredo-nou3.menu.DFUOnBoot.dfu=Enabled (Requires USB-OTG Mode) alfredo-nou3.menu.DFUOnBoot.dfu.build.dfu_on_boot=1 -alfredo-nou3.menu.UploadMode.default=UART0 / Hardware CDC -alfredo-nou3.menu.UploadMode.default.upload.use_1200bps_touch=false -alfredo-nou3.menu.UploadMode.default.upload.wait_for_upload_port=false alfredo-nou3.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB) alfredo-nou3.menu.UploadMode.cdc.upload.use_1200bps_touch=true alfredo-nou3.menu.UploadMode.cdc.upload.wait_for_upload_port=true +alfredo-nou3.menu.UploadMode.default=UART0 / Hardware CDC +alfredo-nou3.menu.UploadMode.default.upload.use_1200bps_touch=false +alfredo-nou3.menu.UploadMode.default.upload.wait_for_upload_port=false alfredo-nou3.menu.PartitionScheme.default_8MB=Default (3MB APP/1.5MB SPIFFS) alfredo-nou3.menu.PartitionScheme.default_8MB.build.partitions=default_8MB @@ -43161,20 +43923,22 @@ alfredo-nou3.menu.EraseFlash.all=Enabled alfredo-nou3.menu.EraseFlash.all.upload.erase_cmd=-e ############################################################## -codecell.name=CodeCell -codecell.vid.0=0x303a -codecell.pid.0=0x1002 -codecell.upload_port.0.vid=0x303a -codecell.upload_port.0.pid=0x1002 +codecell.name=CodeCell C3 codecell.bootloader.tool=esptool_py +codecell.bootloader.tool.default=esptool_py + codecell.upload.tool=esptool_py -codecell.upload.maximum_size=4194304 +codecell.upload.tool.default=esptool_py +codecell.upload.tool.network=esp_ota + +codecell.upload.maximum_size=1310720 codecell.upload.maximum_data_size=327680 +codecell.upload.flags= +codecell.upload.extra_flags= codecell.upload.use_1200bps_touch=false codecell.upload.wait_for_upload_port=false -codecell.upload.speed=921600 codecell.serial.disableDTR=false codecell.serial.disableRTS=false @@ -43183,8 +43947,9 @@ codecell.build.target=esp codecell.build.mcu=esp32c3 codecell.build.core=esp32 codecell.build.variant=codecell -codecell.build.board=ESP32C3_DEV +codecell.build.board=CODECELLC3 codecell.build.bootloader_addr=0x0 + codecell.build.cdc_on_boot=1 codecell.build.f_cpu=160000000L codecell.build.flash_size=4MB @@ -43192,13 +43957,118 @@ codecell.build.flash_freq=80m codecell.build.flash_mode=qio codecell.build.boot=qio codecell.build.partitions=default +codecell.build.defines= + + +codecell.menu.JTAGAdapter.default=Disabled +codecell.menu.JTAGAdapter.default.build.copy_jtag_files=0 +codecell.menu.JTAGAdapter.builtin=Integrated USB JTAG +codecell.menu.JTAGAdapter.builtin.build.openocdscript=esp32c3-builtin.cfg +codecell.menu.JTAGAdapter.builtin.build.copy_jtag_files=1 +codecell.menu.JTAGAdapter.external=FTDI Adapter +codecell.menu.JTAGAdapter.external.build.openocdscript=esp32c3-ftdi.cfg +codecell.menu.JTAGAdapter.external.build.copy_jtag_files=1 +codecell.menu.JTAGAdapter.bridge=ESP USB Bridge +codecell.menu.JTAGAdapter.bridge.build.openocdscript=esp32c3-bridge.cfg +codecell.menu.JTAGAdapter.bridge.build.copy_jtag_files=1 + +codecell.menu.CDCOnBoot.default=Enabled +codecell.menu.CDCOnBoot.default.build.cdc_on_boot=0 +codecell.menu.CDCOnBoot.cdc=Enabled +codecell.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 codecell.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) -codecell.menu.CPUFreq.160=160MHz +codecell.menu.PartitionScheme.default.build.partitions=default +codecell.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) +codecell.menu.PartitionScheme.defaultffat.build.partitions=default_ffat +codecell.menu.PartitionScheme.minimal=Minimal (1.3MB APP/700KB SPIFFS) +codecell.menu.PartitionScheme.minimal.build.partitions=minimal +codecell.menu.PartitionScheme.no_fs=No FS 4MB (2MB APP x2) +codecell.menu.PartitionScheme.no_fs.build.partitions=no_fs +codecell.menu.PartitionScheme.no_fs.upload.maximum_size=2031616 +codecell.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS) +codecell.menu.PartitionScheme.no_ota.build.partitions=no_ota +codecell.menu.PartitionScheme.no_ota.upload.maximum_size=2097152 +codecell.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS) +codecell.menu.PartitionScheme.noota_3g.build.partitions=noota_3g +codecell.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576 +codecell.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS) +codecell.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat +codecell.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152 +codecell.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS) +codecell.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat +codecell.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576 +codecell.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS) +codecell.menu.PartitionScheme.huge_app.build.partitions=huge_app +codecell.menu.PartitionScheme.huge_app.upload.maximum_size=3145728 +codecell.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS) +codecell.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs +codecell.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080 +codecell.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) +codecell.menu.PartitionScheme.fatflash.build.partitions=ffat +codecell.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 +codecell.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) +codecell.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB +codecell.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728 +codecell.menu.PartitionScheme.rainmaker=RainMaker 4MB +codecell.menu.PartitionScheme.rainmaker.build.partitions=rainmaker +codecell.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 +codecell.menu.PartitionScheme.rainmaker_4MB=RainMaker 4MB No OTA +codecell.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no_ota +codecell.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 +codecell.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB +codecell.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB +codecell.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 +codecell.menu.PartitionScheme.zigbee_zczr=Zigbee ZCZR 4MB with spiffs +codecell.menu.PartitionScheme.zigbee_zczr.build.partitions=zigbee_zczr +codecell.menu.PartitionScheme.zigbee_zczr.upload.maximum_size=1310720 +codecell.menu.PartitionScheme.zigbee_zczr_8MB=Zigbee ZCZR 8MB with spiffs +codecell.menu.PartitionScheme.zigbee_zczr_8MB.build.partitions=zigbee_zczr_8MB +codecell.menu.PartitionScheme.zigbee_zczr_8MB.upload.maximum_size=3407872 +codecell.menu.PartitionScheme.custom=Custom +codecell.menu.PartitionScheme.custom.build.partitions= +codecell.menu.PartitionScheme.custom.upload.maximum_size=16777216 + +codecell.menu.CPUFreq.160=160MHz (WiFi) +codecell.menu.CPUFreq.160.build.f_cpu=160000000L +codecell.menu.CPUFreq.80=80MHz (WiFi) +codecell.menu.CPUFreq.80.build.f_cpu=80000000L +codecell.menu.CPUFreq.40=40MHz +codecell.menu.CPUFreq.40.build.f_cpu=40000000L +codecell.menu.CPUFreq.20=20MHz +codecell.menu.CPUFreq.20.build.f_cpu=20000000L +codecell.menu.CPUFreq.10=10MHz +codecell.menu.CPUFreq.10.build.f_cpu=10000000L + codecell.menu.FlashMode.qio=QIO +codecell.menu.FlashMode.qio.build.flash_mode=dio +codecell.menu.FlashMode.qio.build.boot=qio +codecell.menu.FlashMode.dio=DIO +codecell.menu.FlashMode.dio.build.flash_mode=dio +codecell.menu.FlashMode.dio.build.boot=dio + codecell.menu.FlashFreq.80=80MHz +codecell.menu.FlashFreq.80.build.flash_freq=80m +codecell.menu.FlashFreq.40=40MHz +codecell.menu.FlashFreq.40.build.flash_freq=40m + codecell.menu.FlashSize.4M=4MB (32Mb) +codecell.menu.FlashSize.4M.build.flash_size=4MB + codecell.menu.UploadSpeed.921600=921600 +codecell.menu.UploadSpeed.921600.upload.speed=921600 +codecell.menu.UploadSpeed.115200=115200 +codecell.menu.UploadSpeed.115200.upload.speed=115200 +codecell.menu.UploadSpeed.256000.windows=256000 +codecell.menu.UploadSpeed.256000.upload.speed=256000 +codecell.menu.UploadSpeed.230400.windows.upload.speed=256000 +codecell.menu.UploadSpeed.230400=230400 +codecell.menu.UploadSpeed.230400.upload.speed=230400 +codecell.menu.UploadSpeed.460800.linux=460800 +codecell.menu.UploadSpeed.460800.macosx=460800 +codecell.menu.UploadSpeed.460800.upload.speed=460800 +codecell.menu.UploadSpeed.512000.windows=512000 +codecell.menu.UploadSpeed.512000.upload.speed=512000 codecell.menu.DebugLevel.none=None codecell.menu.DebugLevel.none.build.code_debug=0 @@ -43218,6 +44088,12 @@ codecell.menu.EraseFlash.none.upload.erase_cmd= codecell.menu.EraseFlash.all=Enabled codecell.menu.EraseFlash.all.upload.erase_cmd=-e +codecell.menu.ZigbeeMode.default=Disabled +codecell.menu.ZigbeeMode.default.build.zigbee_mode= +codecell.menu.ZigbeeMode.default.build.zigbee_libs= +codecell.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) +codecell.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR +codecell.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api.zczr -lzboss_stack.zczr -lzboss_port.remote ############################################################## jczn_2432s028r.name=ESP32-2432S028R CYD @@ -43519,7 +44395,7 @@ waveshare_esp32_s3_touch_amoled_241.menu.PartitionScheme.rainmaker.build.partiti waveshare_esp32_s3_touch_amoled_241.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 waveshare_esp32_s3_touch_amoled_241.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB waveshare_esp32_s3_touch_amoled_241.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -waveshare_esp32_s3_touch_amoled_241.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_touch_amoled_241.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 waveshare_esp32_s3_touch_amoled_241.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) waveshare_esp32_s3_touch_amoled_241.menu.PartitionScheme.fatflash.build.partitions=ffat waveshare_esp32_s3_touch_amoled_241.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 @@ -43724,7 +44600,7 @@ waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.rainmaker.build.partitions= waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.fatflash.build.partitions=ffat waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 @@ -43923,7 +44799,7 @@ waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.rainmaker.build.partitions waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.fatflash.build.partitions=ffat waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 @@ -44127,7 +45003,7 @@ waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.rainmaker.build.partitions=r waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.fatflash.build.partitions=ffat waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 @@ -44326,7 +45202,7 @@ waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.rainmaker.build.partitions=r waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.fatflash.build.partitions=ffat waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 @@ -44525,7 +45401,7 @@ waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.rainmaker.build.partitions= waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.fatflash.build.partitions=ffat waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 @@ -44724,7 +45600,7 @@ waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.rainmaker.build.partitions=r waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.fatflash.build.partitions=ffat waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 @@ -44932,7 +45808,7 @@ waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.default_8MB.build.partitio waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.default_8MB.upload.maximum_size=3342336 waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.default.build.partitions=default waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) @@ -45509,7 +46385,7 @@ waveshare_esp32_s3_lcd_185.menu.PartitionScheme.default_8MB.build.partitions=def waveshare_esp32_s3_lcd_185.menu.PartitionScheme.default_8MB.upload.maximum_size=3342336 waveshare_esp32_s3_lcd_185.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB waveshare_esp32_s3_lcd_185.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -waveshare_esp32_s3_lcd_185.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 waveshare_esp32_s3_lcd_185.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) waveshare_esp32_s3_lcd_185.menu.PartitionScheme.default.build.partitions=default waveshare_esp32_s3_lcd_185.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) @@ -45746,7 +46622,7 @@ waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.default_8MB.build.partitio waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.default_8MB.upload.maximum_size=3342336 waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.default.build.partitions=default waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) @@ -45983,7 +46859,7 @@ waveshare_esp32_s3_lcd_146.menu.PartitionScheme.default_8MB.build.partitions=def waveshare_esp32_s3_lcd_146.menu.PartitionScheme.default_8MB.upload.maximum_size=3342336 waveshare_esp32_s3_lcd_146.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB waveshare_esp32_s3_lcd_146.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -waveshare_esp32_s3_lcd_146.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 waveshare_esp32_s3_lcd_146.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) waveshare_esp32_s3_lcd_146.menu.PartitionScheme.default.build.partitions=default waveshare_esp32_s3_lcd_146.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) @@ -46220,7 +47096,7 @@ waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.default_8MB.build.part waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.default_8MB.upload.maximum_size=3342336 waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.default.build.partitions=default waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) @@ -46453,7 +47329,7 @@ waveshare_esp32_s3_lcd_147.menu.PartitionScheme.default_8MB.build.partitions=def waveshare_esp32_s3_lcd_147.menu.PartitionScheme.default_8MB.upload.maximum_size=3342336 waveshare_esp32_s3_lcd_147.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB waveshare_esp32_s3_lcd_147.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -waveshare_esp32_s3_lcd_147.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 waveshare_esp32_s3_lcd_147.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) waveshare_esp32_s3_lcd_147.menu.PartitionScheme.default.build.partitions=default waveshare_esp32_s3_lcd_147.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) @@ -46690,7 +47566,7 @@ waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.default_8MB.build.partition waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.default_8MB.upload.maximum_size=3342336 waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.default.build.partitions=default waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) @@ -46927,7 +47803,7 @@ waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.default_8MB.build.partition waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.default_8MB.upload.maximum_size=3342336 waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.default.build.partitions=default waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) @@ -47161,7 +48037,7 @@ waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.default_8MB.build.partitions=d waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.default_8MB.upload.maximum_size=3342336 waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728 @@ -47401,7 +48277,7 @@ waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.rainmaker.build.partiti waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.fatflash.build.partitions=ffat waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 @@ -47603,7 +48479,7 @@ waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.rainmaker.build.partiti waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.fatflash.build.partitions=ffat waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 @@ -47805,7 +48681,7 @@ waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.rainmaker.build.partiti waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.fatflash.build.partitions=ffat waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 @@ -48954,6 +49830,216 @@ yb_esp32s3_eth.menu.EraseFlash.none.upload.erase_cmd= yb_esp32s3_eth.menu.EraseFlash.all=Enabled yb_esp32s3_eth.menu.EraseFlash.all.upload.erase_cmd=-e +############################################################## + +yb_esp32s3_drv.name=YelloByte YB-ESP32-S3-DRV + +yb_esp32s3_drv.bootloader.tool=esptool_py +yb_esp32s3_drv.bootloader.tool.default=esptool_py + +yb_esp32s3_drv.upload.tool=esptool_py +yb_esp32s3_drv.upload.tool.default=esptool_py +yb_esp32s3_drv.upload.tool.network=esp_ota + +yb_esp32s3_drv.upload.maximum_size=1310720 +yb_esp32s3_drv.upload.maximum_data_size=327680 +yb_esp32s3_drv.upload.flags= +yb_esp32s3_drv.upload.extra_flags= +yb_esp32s3_drv.upload.use_1200bps_touch=false +yb_esp32s3_drv.upload.wait_for_upload_port=false + +yb_esp32s3_drv.serial.disableDTR=false +yb_esp32s3_drv.serial.disableRTS=false + +yb_esp32s3_drv.build.tarch=xtensa +yb_esp32s3_drv.build.bootloader_addr=0x0 +yb_esp32s3_drv.build.target=esp32s3 +yb_esp32s3_drv.build.mcu=esp32s3 +yb_esp32s3_drv.build.core=esp32 +yb_esp32s3_drv.build.variant=yb_esp32s3_drv +yb_esp32s3_drv.build.board=YB_ESP32S3_DRV + +yb_esp32s3_drv.build.usb_mode=1 +yb_esp32s3_drv.build.cdc_on_boot=1 +yb_esp32s3_drv.build.msc_on_boot=0 +yb_esp32s3_drv.build.dfu_on_boot=0 +yb_esp32s3_drv.build.f_cpu=240000000L +yb_esp32s3_drv.build.flash_size=8MB +yb_esp32s3_drv.build.flash_freq=80m +yb_esp32s3_drv.build.flash_mode=dio +yb_esp32s3_drv.build.boot=qio +yb_esp32s3_drv.build.partitions=default +yb_esp32s3_drv.build.defines= +yb_esp32s3_drv.build.loop_core= +yb_esp32s3_drv.build.event_core= +yb_esp32s3_drv.build.flash_type=qio +yb_esp32s3_drv.build.psram_type=qspi +yb_esp32s3_drv.build.memory_type={build.flash_type}_{build.psram_type} + +yb_esp32s3_drv.menu.JTAGAdapter.default=Disabled +yb_esp32s3_drv.menu.JTAGAdapter.default.build.copy_jtag_files=0 +yb_esp32s3_drv.menu.JTAGAdapter.builtin=Integrated USB JTAG +yb_esp32s3_drv.menu.JTAGAdapter.builtin.build.openocdscript=esp32s3-builtin.cfg +yb_esp32s3_drv.menu.JTAGAdapter.builtin.build.copy_jtag_files=1 +yb_esp32s3_drv.menu.JTAGAdapter.external=FTDI Adapter +yb_esp32s3_drv.menu.JTAGAdapter.external.build.openocdscript=esp32s3-ftdi.cfg +yb_esp32s3_drv.menu.JTAGAdapter.external.build.copy_jtag_files=1 +yb_esp32s3_drv.menu.JTAGAdapter.bridge=ESP USB Bridge +yb_esp32s3_drv.menu.JTAGAdapter.bridge.build.openocdscript=esp32s3-bridge.cfg +yb_esp32s3_drv.menu.JTAGAdapter.bridge.build.copy_jtag_files=1 + +yb_esp32s3_drv.menu.LoopCore.1=Core 1 +yb_esp32s3_drv.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 +yb_esp32s3_drv.menu.LoopCore.0=Core 0 +yb_esp32s3_drv.menu.LoopCore.0.build.loop_core=-DARDUINO_RUNNING_CORE=0 + +yb_esp32s3_drv.menu.EventsCore.1=Core 1 +yb_esp32s3_drv.menu.EventsCore.1.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1 +yb_esp32s3_drv.menu.EventsCore.0=Core 0 +yb_esp32s3_drv.menu.EventsCore.0.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=0 + +yb_esp32s3_drv.menu.USBMode.hwcdc=Hardware CDC and JTAG +yb_esp32s3_drv.menu.USBMode.hwcdc.build.usb_mode=1 +yb_esp32s3_drv.menu.USBMode.default=USB-OTG (TinyUSB) +yb_esp32s3_drv.menu.USBMode.default.build.usb_mode=0 + +yb_esp32s3_drv.menu.CDCOnBoot.cdc=Enabled +yb_esp32s3_drv.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 +yb_esp32s3_drv.menu.CDCOnBoot.default=Disabled +yb_esp32s3_drv.menu.CDCOnBoot.default.build.cdc_on_boot=0 + +yb_esp32s3_drv.menu.MSCOnBoot.default=Disabled +yb_esp32s3_drv.menu.MSCOnBoot.default.build.msc_on_boot=0 +yb_esp32s3_drv.menu.MSCOnBoot.msc=Enabled (Requires USB-OTG Mode) +yb_esp32s3_drv.menu.MSCOnBoot.msc.build.msc_on_boot=1 + +yb_esp32s3_drv.menu.DFUOnBoot.default=Disabled +yb_esp32s3_drv.menu.DFUOnBoot.default.build.dfu_on_boot=0 +yb_esp32s3_drv.menu.DFUOnBoot.dfu=Enabled (Requires USB-OTG Mode) +yb_esp32s3_drv.menu.DFUOnBoot.dfu.build.dfu_on_boot=1 + +yb_esp32s3_drv.menu.UploadMode.default=UART0 / Hardware CDC +yb_esp32s3_drv.menu.UploadMode.default.upload.use_1200bps_touch=false +yb_esp32s3_drv.menu.UploadMode.default.upload.wait_for_upload_port=false +yb_esp32s3_drv.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB) +yb_esp32s3_drv.menu.UploadMode.cdc.upload.use_1200bps_touch=true +yb_esp32s3_drv.menu.UploadMode.cdc.upload.wait_for_upload_port=true + +yb_esp32s3_drv.menu.PSRAM.enabled=QSPI PSRAM +yb_esp32s3_drv.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM +yb_esp32s3_drv.menu.PSRAM.enabled.build.psram_type=qspi +yb_esp32s3_drv.menu.PSRAM.disabled=Disabled +yb_esp32s3_drv.menu.PSRAM.disabled.build.defines= +yb_esp32s3_drv.menu.PSRAM.disabled.build.psram_type=qspi +yb_esp32s3_drv.menu.PSRAM.opi=OPI PSRAM +yb_esp32s3_drv.menu.PSRAM.opi.build.defines=-DBOARD_HAS_PSRAM +yb_esp32s3_drv.menu.PSRAM.opi.build.psram_type=opi + +yb_esp32s3_drv.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) +yb_esp32s3_drv.menu.PartitionScheme.default.build.partitions=default +yb_esp32s3_drv.menu.PartitionScheme.default_8MB=8M with spiffs (3MB APP/1.5MB SPIFFS) +yb_esp32s3_drv.menu.PartitionScheme.default_8MB.build.partitions=default_8MB +yb_esp32s3_drv.menu.PartitionScheme.default_8MB.upload.maximum_size=3342336 +yb_esp32s3_drv.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) +yb_esp32s3_drv.menu.PartitionScheme.defaultffat.build.partitions=default_ffat +yb_esp32s3_drv.menu.PartitionScheme.minimal=Minimal (1.3MB APP/700KB SPIFFS) +yb_esp32s3_drv.menu.PartitionScheme.minimal.build.partitions=minimal +yb_esp32s3_drv.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS) +yb_esp32s3_drv.menu.PartitionScheme.no_ota.build.partitions=no_ota +yb_esp32s3_drv.menu.PartitionScheme.no_ota.upload.maximum_size=2097152 +yb_esp32s3_drv.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS) +yb_esp32s3_drv.menu.PartitionScheme.noota_3g.build.partitions=noota_3g +yb_esp32s3_drv.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576 +yb_esp32s3_drv.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS) +yb_esp32s3_drv.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat +yb_esp32s3_drv.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152 +yb_esp32s3_drv.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS) +yb_esp32s3_drv.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat +yb_esp32s3_drv.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576 +yb_esp32s3_drv.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS) +yb_esp32s3_drv.menu.PartitionScheme.huge_app.build.partitions=huge_app +yb_esp32s3_drv.menu.PartitionScheme.huge_app.upload.maximum_size=3145728 +yb_esp32s3_drv.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS) +yb_esp32s3_drv.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs +yb_esp32s3_drv.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080 +yb_esp32s3_drv.menu.PartitionScheme.max_app_8MB=Maximum APP (7.9MB APP No OTA/No FS) +yb_esp32s3_drv.menu.PartitionScheme.max_app_8MB.build.partitions=max_app_8MB +yb_esp32s3_drv.menu.PartitionScheme.max_app_8MB.upload.maximum_size=8257536 + +yb_esp32s3_drv.menu.CPUFreq.240=240MHz (WiFi) +yb_esp32s3_drv.menu.CPUFreq.240.build.f_cpu=240000000L +yb_esp32s3_drv.menu.CPUFreq.160=160MHz (WiFi) +yb_esp32s3_drv.menu.CPUFreq.160.build.f_cpu=160000000L +yb_esp32s3_drv.menu.CPUFreq.80=80MHz (WiFi) +yb_esp32s3_drv.menu.CPUFreq.80.build.f_cpu=80000000L +yb_esp32s3_drv.menu.CPUFreq.40=40MHz +yb_esp32s3_drv.menu.CPUFreq.40.build.f_cpu=40000000L +yb_esp32s3_drv.menu.CPUFreq.20=20MHz +yb_esp32s3_drv.menu.CPUFreq.20.build.f_cpu=20000000L +yb_esp32s3_drv.menu.CPUFreq.10=10MHz +yb_esp32s3_drv.menu.CPUFreq.10.build.f_cpu=10000000L + +yb_esp32s3_drv.menu.FlashMode.qio=QIO 80MHz +yb_esp32s3_drv.menu.FlashMode.qio.build.flash_mode=dio +yb_esp32s3_drv.menu.FlashMode.qio.build.boot=qio +yb_esp32s3_drv.menu.FlashMode.qio.build.boot_freq=80m +yb_esp32s3_drv.menu.FlashMode.qio.build.flash_freq=80m +yb_esp32s3_drv.menu.FlashMode.qio120=QIO 120MHz +yb_esp32s3_drv.menu.FlashMode.qio120.build.flash_mode=dio +yb_esp32s3_drv.menu.FlashMode.qio120.build.boot=qio +yb_esp32s3_drv.menu.FlashMode.qio120.build.boot_freq=120m +yb_esp32s3_drv.menu.FlashMode.qio120.build.flash_freq=80m +yb_esp32s3_drv.menu.FlashMode.dio=DIO 80MHz +yb_esp32s3_drv.menu.FlashMode.dio.build.flash_mode=dio +yb_esp32s3_drv.menu.FlashMode.dio.build.boot=dio +yb_esp32s3_drv.menu.FlashMode.dio.build.boot_freq=80m +yb_esp32s3_drv.menu.FlashMode.dio.build.flash_freq=80m +yb_esp32s3_drv.menu.FlashMode.opi=OPI 80MHz +yb_esp32s3_drv.menu.FlashMode.opi.build.flash_mode=dout +yb_esp32s3_drv.menu.FlashMode.opi.build.boot=opi +yb_esp32s3_drv.menu.FlashMode.opi.build.boot_freq=80m +yb_esp32s3_drv.menu.FlashMode.opi.build.flash_freq=80m + +yb_esp32s3_drv.menu.FlashSize.4M=4MB (32Mb) +yb_esp32s3_drv.menu.FlashSize.4M.build.flash_size=4MB +yb_esp32s3_drv.menu.FlashSize.8M=8MB (64Mb) +yb_esp32s3_drv.menu.FlashSize.8M.build.flash_size=8MB +yb_esp32s3_drv.menu.FlashSize.16M=16MB (128Mb) +yb_esp32s3_drv.menu.FlashSize.16M.build.flash_size=16MB + +yb_esp32s3_drv.menu.UploadSpeed.921600=921600 +yb_esp32s3_drv.menu.UploadSpeed.921600.upload.speed=921600 +yb_esp32s3_drv.menu.UploadSpeed.115200=115200 +yb_esp32s3_drv.menu.UploadSpeed.115200.upload.speed=115200 +yb_esp32s3_drv.menu.UploadSpeed.256000.windows=256000 +yb_esp32s3_drv.menu.UploadSpeed.256000.upload.speed=256000 +yb_esp32s3_drv.menu.UploadSpeed.230400.windows.upload.speed=256000 +yb_esp32s3_drv.menu.UploadSpeed.230400=230400 +yb_esp32s3_drv.menu.UploadSpeed.230400.upload.speed=230400 +yb_esp32s3_drv.menu.UploadSpeed.460800.linux=460800 +yb_esp32s3_drv.menu.UploadSpeed.460800.macosx=460800 +yb_esp32s3_drv.menu.UploadSpeed.460800.upload.speed=460800 +yb_esp32s3_drv.menu.UploadSpeed.512000.windows=512000 +yb_esp32s3_drv.menu.UploadSpeed.512000.upload.speed=512000 + +yb_esp32s3_drv.menu.DebugLevel.none=None +yb_esp32s3_drv.menu.DebugLevel.none.build.code_debug=0 +yb_esp32s3_drv.menu.DebugLevel.error=Error +yb_esp32s3_drv.menu.DebugLevel.error.build.code_debug=1 +yb_esp32s3_drv.menu.DebugLevel.warn=Warn +yb_esp32s3_drv.menu.DebugLevel.warn.build.code_debug=2 +yb_esp32s3_drv.menu.DebugLevel.info=Info +yb_esp32s3_drv.menu.DebugLevel.info.build.code_debug=3 +yb_esp32s3_drv.menu.DebugLevel.debug=Debug +yb_esp32s3_drv.menu.DebugLevel.debug.build.code_debug=4 +yb_esp32s3_drv.menu.DebugLevel.verbose=Verbose +yb_esp32s3_drv.menu.DebugLevel.verbose.build.code_debug=5 + +yb_esp32s3_drv.menu.EraseFlash.none=Disabled +yb_esp32s3_drv.menu.EraseFlash.none.upload.erase_cmd= +yb_esp32s3_drv.menu.EraseFlash.all=Enabled +yb_esp32s3_drv.menu.EraseFlash.all.upload.erase_cmd=-e + ############################################################## # Huidu HD-WF2 - esp32-s3 HUB75 driver board # https://www.hdwell.com/Product/index46.html @@ -49413,7 +50499,7 @@ cyobot_v2_esp32s3.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_ cyobot_v2_esp32s3.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 cyobot_v2_esp32s3.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB cyobot_v2_esp32s3.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB -cyobot_v2_esp32s3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +cyobot_v2_esp32s3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4096000 cyobot_v2_esp32s3.menu.PartitionScheme.app5M_fat24M_32MB=32M Flash (4.8MB APP/22MB FATFS) cyobot_v2_esp32s3.menu.PartitionScheme.app5M_fat24M_32MB.build.partitions=large_fat_32MB cyobot_v2_esp32s3.menu.PartitionScheme.app5M_fat24M_32MB.upload.maximum_size=4718592 diff --git a/cores/esp32/Arduino.h b/cores/esp32/Arduino.h index d21089cc3fe..9048249a873 100644 --- a/cores/esp32/Arduino.h +++ b/cores/esp32/Arduino.h @@ -41,7 +41,6 @@ #include "extra_attr.h" #include "pins_arduino.h" -#include "io_pin_remap.h" #include "esp32-hal.h" #define PI 3.1415926535897932384626433832795 @@ -251,4 +250,8 @@ void tone(uint8_t _pin, unsigned int frequency, unsigned long duration = 0); void noTone(uint8_t _pin); #endif /* __cplusplus */ + +// must be applied last as it overrides some of the above +#include "io_pin_remap.h" + #endif /* _ESP32_CORE_ARDUINO_H_ */ diff --git a/cores/esp32/HWCDC.cpp b/cores/esp32/HWCDC.cpp index 170e323a035..062317d9f53 100644 --- a/cores/esp32/HWCDC.cpp +++ b/cores/esp32/HWCDC.cpp @@ -603,6 +603,7 @@ void HWCDC::setDebugOutput(bool en) { } else { ets_install_putc2(NULL); } + ets_install_putc1(NULL); // closes UART log output } #if ARDUINO_USB_MODE && ARDUINO_USB_CDC_ON_BOOT // Hardware JTAG CDC selected diff --git a/cores/esp32/HardwareSerial.cpp b/cores/esp32/HardwareSerial.cpp index 76135691411..6d762da21fb 100644 --- a/cores/esp32/HardwareSerial.cpp +++ b/cores/esp32/HardwareSerial.cpp @@ -607,6 +607,24 @@ bool HardwareSerial::setMode(SerialMode mode) { return uartSetMode(_uart, mode); } +// Sets the UART Clock Source based on the compatible SoC options +// This method must be called before starting UART using begin(), otherwise it won't have any effect. +// Clock Source Options are: +// UART_CLK_SRC_DEFAULT :: any SoC - it will set whatever IDF defines as the default UART Clock Source +// UART_CLK_SRC_APB :: ESP32, ESP32-S2, ESP32-C3 and ESP32-S3 +// UART_CLK_SRC_PLL :: ESP32-C2, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-H2 and ESP32-P4 +// UART_CLK_SRC_XTAL :: ESP32-C2, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-H2, ESP32-S3 and ESP32-P4 +// UART_CLK_SRC_RTC :: ESP32-C2, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-H2, ESP32-S3 and ESP32-P4 +// UART_CLK_SRC_REF_TICK :: ESP32 and ESP32-S2 +// Note: CLK_SRC_PLL Freq depends on the SoC - ESP32-C2 has 40MHz, ESP32-H2 has 48MHz and ESP32-C5, C6, C61 and P4 has 80MHz +// Note: ESP32-C6, C61, ESP32-P4 and ESP32-C5 have LP UART that will use only RTC_FAST or XTAL/2 as Clock Source +bool HardwareSerial::setClockSource(SerialClkSrc clkSrc) { + if (_uart) { + log_e("No Clock Source change was done. This function must be called before beginning UART%d.", _uart_nr); + return false; + } + return uartSetClockSource(_uart_nr, (uart_sclk_t)clkSrc); +} // minimum total RX Buffer size is the UART FIFO space (128 bytes for most SoC) + 1. IDF imposition. // LP UART has FIFO of 16 bytes size_t HardwareSerial::setRxBufferSize(size_t new_size) { diff --git a/cores/esp32/HardwareSerial.h b/cores/esp32/HardwareSerial.h index b1f6df17724..e974f112701 100644 --- a/cores/esp32/HardwareSerial.h +++ b/cores/esp32/HardwareSerial.h @@ -96,6 +96,29 @@ typedef enum { UART_PARITY_ERROR } hardwareSerial_error_t; +typedef enum { + UART_CLK_SRC_DEFAULT = UART_SCLK_DEFAULT, +#if SOC_UART_SUPPORT_APB_CLK + UART_CLK_SRC_APB = UART_SCLK_APB, +#endif +#if SOC_UART_SUPPORT_PLL_F40M_CLK + UART_CLK_SRC_PLL = UART_SCLK_PLL_F40M, +#elif SOC_UART_SUPPORT_PLL_F80M_CLK + UART_CLK_SRC_PLL = UART_SCLK_PLL_F80M, +#elif CONFIG_IDF_TARGET_ESP32H2 + UART_CLK_SRC_PLL = UART_SCLK_PLL_F48M, +#endif +#if SOC_UART_SUPPORT_XTAL_CLK + UART_CLK_SRC_XTAL = UART_SCLK_XTAL, +#endif +#if SOC_UART_SUPPORT_RTC_CLK + UART_CLK_SRC_RTC = UART_SCLK_RTC, +#endif +#if SOC_UART_SUPPORT_REF_TICK + UART_CLK_SRC_REF_TICK = UART_SCLK_REF_TICK, +#endif +} SerialClkSrc; + #ifndef ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE #ifndef CONFIG_ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE #define ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE 2048 @@ -344,6 +367,17 @@ class HardwareSerial : public Stream { // UART_MODE_RS485_COLLISION_DETECT = 0x03 mode: RS485 collision detection UART mode (used for test purposes) // UART_MODE_RS485_APP_CTRL = 0x04 mode: application control RS485 UART mode (used for test purposes) bool setMode(SerialMode mode); + // Used to set the UART clock source mode. It must be set before calling begin(), otherwise it won't have any effect. + // Not all clock source are available to every SoC. The compatible option are listed here: + // UART_CLK_SRC_DEFAULT :: any SoC - it will set whatever IDF defines as the default UART Clock Source + // UART_CLK_SRC_APB :: ESP32, ESP32-S2, ESP32-C3 and ESP32-S3 + // UART_CLK_SRC_PLL :: ESP32-C2, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-H2 and ESP32-P4 + // UART_CLK_SRC_XTAL :: ESP32-C2, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-H2, ESP32-S3 and ESP32-P4 + // UART_CLK_SRC_RTC :: ESP32-C2, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-H2, ESP32-S3 and ESP32-P4 + // UART_CLK_SRC_REF_TICK :: ESP32 and ESP32-S2 + // Note: CLK_SRC_PLL Freq depends on the SoC - ESP32-C2 has 40MHz, ESP32-H2 has 48MHz and ESP32-C5, C6, C61 and P4 has 80MHz + // Note: ESP32-C6, C61, ESP32-P4 and ESP32-C5 have LP UART that will use only RTC_FAST or XTAL/2 as Clock Source + bool setClockSource(SerialClkSrc clkSrc); size_t setRxBufferSize(size_t new_size); size_t setTxBufferSize(size_t new_size); diff --git a/cores/esp32/USB.cpp b/cores/esp32/USB.cpp index 8fdd7a3ab71..269e9a76cb3 100644 --- a/cores/esp32/USB.cpp +++ b/cores/esp32/USB.cpp @@ -100,6 +100,7 @@ static bool tinyusb_device_suspended = false; void tud_mount_cb(void) { tinyusb_device_mounted = true; arduino_usb_event_data_t p; + p.suspend.remote_wakeup_en = 0; arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_STARTED_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY); } @@ -107,6 +108,7 @@ void tud_mount_cb(void) { void tud_umount_cb(void) { tinyusb_device_mounted = false; arduino_usb_event_data_t p; + p.suspend.remote_wakeup_en = 0; arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_STOPPED_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY); } @@ -123,6 +125,7 @@ void tud_suspend_cb(bool remote_wakeup_en) { void tud_resume_cb(void) { tinyusb_device_suspended = false; arduino_usb_event_data_t p; + p.suspend.remote_wakeup_en = 0; arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_RESUME_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY); } diff --git a/cores/esp32/USBCDC.cpp b/cores/esp32/USBCDC.cpp index 945021a79e2..c7bb4582d4f 100644 --- a/cores/esp32/USBCDC.cpp +++ b/cores/esp32/USBCDC.cpp @@ -455,6 +455,7 @@ void USBCDC::setDebugOutput(bool en) { } else { ets_install_putc2(NULL); } + ets_install_putc1(NULL); // closes UART log output } USBCDC::operator bool() const { diff --git a/cores/esp32/esp32-hal-bt.c b/cores/esp32/esp32-hal-bt.c index 5f1148bd492..1e5f73e324c 100644 --- a/cores/esp32/esp32-hal-bt.c +++ b/cores/esp32/esp32-hal-bt.c @@ -15,7 +15,7 @@ #include "esp32-hal-bt.h" #if SOC_BT_SUPPORTED -#ifdef CONFIG_BT_ENABLED +#ifdef CONFIG_BT_BLUEDROID_ENABLED #if CONFIG_IDF_TARGET_ESP32 bool btInUse() { diff --git a/cores/esp32/esp32-hal-cpu.c b/cores/esp32/esp32-hal-cpu.c index 1ffde860792..b80e24c2b0f 100644 --- a/cores/esp32/esp32-hal-cpu.c +++ b/cores/esp32/esp32-hal-cpu.c @@ -26,6 +26,8 @@ #include "soc/efuse_reg.h" #include "esp32-hal.h" #include "esp32-hal-cpu.h" +#include "hal/timer_ll.h" +#include "esp_private/systimer.h" #include "esp_system.h" #ifdef ESP_IDF_VERSION_MAJOR // IDF 4+ @@ -173,7 +175,9 @@ static uint32_t calculateApb(rtc_cpu_freq_config_t *conf) { #endif } +#if defined(CONFIG_IDF_TARGET_ESP32) && !defined(LACT_MODULE) && !defined(LACT_TICKS_PER_US) void esp_timer_impl_update_apb_freq(uint32_t apb_ticks_per_us); //private in IDF +#endif bool setCpuFrequencyMhz(uint32_t cpu_freq_mhz) { rtc_cpu_freq_config_t conf, cconf; @@ -246,7 +250,13 @@ bool setCpuFrequencyMhz(uint32_t cpu_freq_mhz) { //Update APB Freq REG rtc_clk_apb_freq_update(apb); //Update esp_timer divisor +#if CONFIG_IDF_TARGET_ESP32 +#if defined(LACT_MODULE) && defined(LACT_TICKS_PER_US) + timer_ll_set_lact_clock_prescale(TIMER_LL_GET_HW(LACT_MODULE), apb / MHZ / LACT_TICKS_PER_US); +#else esp_timer_impl_update_apb_freq(apb / MHZ); +#endif +#endif } #endif //Update FreeRTOS Tick Divisor diff --git a/cores/esp32/esp32-hal-gpio.c b/cores/esp32/esp32-hal-gpio.c index c681be077b3..90ad1e7f36d 100644 --- a/cores/esp32/esp32-hal-gpio.c +++ b/cores/esp32/esp32-hal-gpio.c @@ -185,7 +185,7 @@ extern int ARDUINO_ISR_ATTR __digitalRead(uint8_t pin) { #endif // RGB_BUILTIN // This work when the pin is set as GPIO and in INPUT mode. For all other pin functions, it may return inconsistent response if (perimanGetPinBus(pin, ESP32_BUS_TYPE_GPIO) == NULL) { - log_w("IO %i is not set as GPIO. digitalRead() may return an inconsistent value."); + log_w("IO %i is not set as GPIO. digitalRead() may return an inconsistent value.", pin); } return gpio_get_level((gpio_num_t)pin); } diff --git a/cores/esp32/esp32-hal-i2c-slave.c b/cores/esp32/esp32-hal-i2c-slave.c index 46c3a4d58c2..9d39c1c783d 100644 --- a/cores/esp32/esp32-hal-i2c-slave.c +++ b/cores/esp32/esp32-hal-i2c-slave.c @@ -335,10 +335,12 @@ esp_err_t i2cSlaveInit(uint8_t num, int sda, int scl, uint16_t slaveID, uint32_t } #endif // !defined(CONFIG_IDF_TARGET_ESP32P4) - i2c_ll_slave_init(i2c->dev); #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 0) + i2c_ll_set_mode(i2c->dev, I2C_BUS_MODE_SLAVE); + i2c_ll_enable_pins_open_drain(i2c->dev, true); i2c_ll_enable_fifo_mode(i2c->dev, true); #else + i2c_ll_slave_init(i2c->dev); i2c_ll_slave_set_fifo_mode(i2c->dev, true); #endif i2c_ll_set_slave_addr(i2c->dev, slaveID, false); diff --git a/cores/esp32/esp32-hal-ledc.c b/cores/esp32/esp32-hal-ledc.c index 0a3ec5a60c7..039fa1312f1 100644 --- a/cores/esp32/esp32-hal-ledc.c +++ b/cores/esp32/esp32-hal-ledc.c @@ -126,7 +126,14 @@ bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t c return false; } } else { - ledc_timer_config_t ledc_timer = {.speed_mode = group, .timer_num = timer, .duty_resolution = resolution, .freq_hz = freq, .clk_cfg = clock_source}; + ledc_timer_config_t ledc_timer; + memset((void *)&ledc_timer, 0, sizeof(ledc_timer_config_t)); + ledc_timer.speed_mode = group; + ledc_timer.timer_num = timer; + ledc_timer.duty_resolution = resolution; + ledc_timer.freq_hz = freq; + ledc_timer.clk_cfg = clock_source; + if (ledc_timer_config(&ledc_timer) != ESP_OK) { log_e("ledc setup failed!"); return false; @@ -134,9 +141,16 @@ bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t c uint32_t duty = ledc_get_duty(group, (channel % 8)); - ledc_channel_config_t ledc_channel = { - .speed_mode = group, .channel = (channel % 8), .timer_sel = timer, .intr_type = LEDC_INTR_DISABLE, .gpio_num = pin, .duty = duty, .hpoint = 0 - }; + ledc_channel_config_t ledc_channel; + memset((void *)&ledc_channel, 0, sizeof(ledc_channel_config_t)); + ledc_channel.speed_mode = group; + ledc_channel.channel = (channel % 8); + ledc_channel.timer_sel = timer; + ledc_channel.intr_type = LEDC_INTR_DISABLE; + ledc_channel.gpio_num = pin; + ledc_channel.duty = duty; + ledc_channel.hpoint = 0; + ledc_channel_config(&ledc_channel); } @@ -256,7 +270,13 @@ uint32_t ledcWriteTone(uint8_t pin, uint32_t freq) { uint8_t group = (bus->channel / 8), timer = ((bus->channel / 2) % 4); - ledc_timer_config_t ledc_timer = {.speed_mode = group, .timer_num = timer, .duty_resolution = 10, .freq_hz = freq, .clk_cfg = clock_source}; + ledc_timer_config_t ledc_timer; + memset((void *)&ledc_timer, 0, sizeof(ledc_timer_config_t)); + ledc_timer.speed_mode = group; + ledc_timer.timer_num = timer; + ledc_timer.duty_resolution = 10; + ledc_timer.freq_hz = freq; + ledc_timer.clk_cfg = clock_source; if (ledc_timer_config(&ledc_timer) != ESP_OK) { log_e("ledcWriteTone configuration failed!"); @@ -307,7 +327,13 @@ uint32_t ledcChangeFrequency(uint8_t pin, uint32_t freq, uint8_t resolution) { } uint8_t group = (bus->channel / 8), timer = ((bus->channel / 2) % 4); - ledc_timer_config_t ledc_timer = {.speed_mode = group, .timer_num = timer, .duty_resolution = resolution, .freq_hz = freq, .clk_cfg = clock_source}; + ledc_timer_config_t ledc_timer; + memset((void *)&ledc_timer, 0, sizeof(ledc_timer_config_t)); + ledc_timer.speed_mode = group; + ledc_timer.timer_num = timer; + ledc_timer.duty_resolution = resolution; + ledc_timer.freq_hz = freq; + ledc_timer.clk_cfg = clock_source; if (ledc_timer_config(&ledc_timer) != ESP_OK) { log_e("ledcChangeFrequency failed!"); diff --git a/cores/esp32/esp32-hal-misc.c b/cores/esp32/esp32-hal-misc.c index 50e2973d27a..594acd38153 100644 --- a/cores/esp32/esp32-hal-misc.c +++ b/cores/esp32/esp32-hal-misc.c @@ -25,9 +25,9 @@ #include "esp_ota_ops.h" #endif //CONFIG_APP_ROLLBACK_ENABLE #include "esp_private/startup_internal.h" -#if defined(CONFIG_BT_ENABLED) && SOC_BT_SUPPORTED +#if defined(CONFIG_BT_BLUEDROID_ENABLED) && SOC_BT_SUPPORTED #include "esp_bt.h" -#endif //CONFIG_BT_ENABLED +#endif //CONFIG_BT_BLUEDROID_ENABLED #include #include "soc/rtc.h" #if !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32H2) && !defined(CONFIG_IDF_TARGET_ESP32P4) @@ -243,7 +243,7 @@ bool verifyRollbackLater() { } #endif -#ifdef CONFIG_BT_ENABLED +#ifdef CONFIG_BT_BLUEDROID_ENABLED #if CONFIG_IDF_TARGET_ESP32 //overwritten in esp32-hal-bt.c bool btInUse() __attribute__((weak)); @@ -305,7 +305,7 @@ void initArduino() { if (err) { log_e("Failed to initialize NVS! Error: %u", err); } -#if defined(CONFIG_BT_ENABLED) && SOC_BT_SUPPORTED +#if defined(CONFIG_BT_BLUEDROID_ENABLED) && SOC_BT_SUPPORTED if (!btInUse()) { esp_bt_controller_mem_release(ESP_BT_MODE_BTDM); } diff --git a/cores/esp32/esp32-hal-rmt.c b/cores/esp32/esp32-hal-rmt.c index e3877b5ff48..7bca1a1b529 100644 --- a/cores/esp32/esp32-hal-rmt.c +++ b/cores/esp32/esp32-hal-rmt.c @@ -206,7 +206,8 @@ bool rmtSetCarrier(int pin, bool carrier_en, bool carrier_level, uint32_t freque log_w("GPIO %d - RMT Carrier must be a float percentage from 0 to 1. Setting to 50%.", pin); duty_percent = 0.5; } - rmt_carrier_config_t carrier_cfg = {0}; + rmt_carrier_config_t carrier_cfg; + memset((void *)&carrier_cfg, 0, sizeof(rmt_carrier_config_t)); carrier_cfg.duty_cycle = duty_percent; // duty cycle carrier_cfg.frequency_hz = carrier_en ? frequency_Hz : 0; // carrier frequency in Hz carrier_cfg.flags.polarity_active_low = carrier_level; // carrier modulation polarity level @@ -313,7 +314,8 @@ static bool _rmtWrite(int pin, rmt_data_t *data, size_t num_rmt_symbols, bool bl return false; } - rmt_transmit_config_t transmit_cfg = {0}; // loop mode disabled + rmt_transmit_config_t transmit_cfg; // loop mode disabled + memset((void *)&transmit_cfg, 0, sizeof(rmt_transmit_config_t)); bool retCode = true; RMT_MUTEX_LOCK(bus); @@ -380,6 +382,7 @@ static bool _rmtRead(int pin, rmt_data_t *data, size_t *num_rmt_symbols, bool wa // request reading RMT Channel Data rmt_receive_config_t receive_config; + memset((void *)&receive_config, 0, sizeof(rmt_receive_config_t)); receive_config.signal_range_min_ns = bus->signal_range_min_ns; receive_config.signal_range_max_ns = bus->signal_range_max_ns; @@ -530,6 +533,7 @@ bool rmtInit(int pin, rmt_ch_dir_t channel_direction, rmt_reserve_memsize_t mem_ if (channel_direction == RMT_TX_MODE) { // TX Channel rmt_tx_channel_config_t tx_cfg; + memset((void *)&tx_cfg, 0, sizeof(rmt_tx_channel_config_t)); tx_cfg.gpio_num = pin; // CLK_APB for ESP32|S2|S3|C3 -- CLK_PLL_F80M for C6 -- CLK_XTAL for H2 tx_cfg.clk_src = RMT_CLK_SRC_DEFAULT; @@ -559,6 +563,7 @@ bool rmtInit(int pin, rmt_ch_dir_t channel_direction, rmt_reserve_memsize_t mem_ } else { // RX Channel rmt_rx_channel_config_t rx_cfg; + memset((void *)&rx_cfg, 0, sizeof(rmt_rx_channel_config_t)); rx_cfg.gpio_num = pin; // CLK_APB for ESP32|S2|S3|C3 -- CLK_PLL_F80M for C6 -- CLK_XTAL for H2 rx_cfg.clk_src = RMT_CLK_SRC_DEFAULT; @@ -585,7 +590,8 @@ bool rmtInit(int pin, rmt_ch_dir_t channel_direction, rmt_reserve_memsize_t mem_ } // allocate memory for the RMT Copy encoder - rmt_copy_encoder_config_t copy_encoder_config = {}; + rmt_copy_encoder_config_t copy_encoder_config; + memset((void *)©_encoder_config, 0, sizeof(rmt_copy_encoder_config_t)); if (rmt_new_copy_encoder(©_encoder_config, &bus->rmt_copy_encoder_h) != ESP_OK) { log_e("GPIO %d - RMT Encoder Memory Allocation error.", pin); goto Err; diff --git a/cores/esp32/esp32-hal-spi.c b/cores/esp32/esp32-hal-spi.c index 80928309670..6b8e3f8c013 100644 --- a/cores/esp32/esp32-hal-spi.c +++ b/cores/esp32/esp32-hal-spi.c @@ -74,6 +74,7 @@ struct spi_struct_t { int8_t miso; int8_t mosi; int8_t ss; + bool ss_invert; }; #if CONFIG_IDF_TARGET_ESP32S2 @@ -151,23 +152,23 @@ struct spi_struct_t { // clang-format off static spi_t _spi_bus_array[] = { #if CONFIG_IDF_TARGET_ESP32S2 - {(volatile spi_dev_t *)(DR_REG_SPI1_BASE), 0, -1, -1, -1, -1}, - {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 1, -1, -1, -1, -1}, - {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), 2, -1, -1, -1, -1} + {(volatile spi_dev_t *)(DR_REG_SPI1_BASE), 0, -1, -1, -1, -1, false}, + {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 1, -1, -1, -1, -1, false}, + {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), 2, -1, -1, -1, -1, false} #elif CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32P4 - {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 0, -1, -1, -1, -1}, - {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), 1, -1, -1, -1, -1} + {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 0, -1, -1, -1, -1, false}, + {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), 1, -1, -1, -1, -1, false} #elif CONFIG_IDF_TARGET_ESP32C2 - {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 0, -1, -1, -1, -1} + {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 0, -1, -1, -1, -1, false} #elif CONFIG_IDF_TARGET_ESP32C3 - {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 0, -1, -1, -1, -1} + {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 0, -1, -1, -1, -1, false} #elif CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 - {(spi_dev_t *)(DR_REG_SPI2_BASE), 0, -1, -1, -1, -1} + {(spi_dev_t *)(DR_REG_SPI2_BASE), 0, -1, -1, -1, -1, false} #else - {(volatile spi_dev_t *)(DR_REG_SPI0_BASE), 0, -1, -1, -1, -1}, - {(volatile spi_dev_t *)(DR_REG_SPI1_BASE), 1, -1, -1, -1, -1}, - {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 2, -1, -1, -1, -1}, - {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), 3, -1, -1, -1, -1} + {(volatile spi_dev_t *)(DR_REG_SPI0_BASE), 0, -1, -1, -1, -1, false}, + {(volatile spi_dev_t *)(DR_REG_SPI1_BASE), 1, -1, -1, -1, -1, false}, + {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 2, -1, -1, -1, -1, false}, + {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), 3, -1, -1, -1, -1, false} #endif }; // clang-format on @@ -179,22 +180,22 @@ static spi_t _spi_bus_array[] = { static spi_t _spi_bus_array[] = { #if CONFIG_IDF_TARGET_ESP32S2 - {(volatile spi_dev_t *)(DR_REG_SPI1_BASE), NULL, 0, -1, -1, -1, -1}, - {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 1, -1, -1, -1, -1}, - {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), NULL, 2, -1, -1, -1, -1} + {(volatile spi_dev_t *)(DR_REG_SPI1_BASE), NULL, 0, -1, -1, -1, -1, false}, + {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 1, -1, -1, -1, -1, false}, + {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), NULL, 2, -1, -1, -1, -1, false} #elif CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32P4 - {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 0, -1, -1, -1, -1}, {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), NULL, 1, -1, -1, -1, -1} + {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 0, -1, -1, -1, -1, false}, {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), NULL, 1, -1, -1, -1, -1, false} #elif CONFIG_IDF_TARGET_ESP32C2 - {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 0, -1, -1, -1, -1} + {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 0, -1, -1, -1, -1, false} #elif CONFIG_IDF_TARGET_ESP32C3 - {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 0, -1, -1, -1, -1} + {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 0, -1, -1, -1, -1, false} #elif CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 - {(spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 0, -1, -1, -1, -1} + {(spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 0, -1, -1, -1, -1, false} #else - {(volatile spi_dev_t *)(DR_REG_SPI0_BASE), NULL, 0, -1, -1, -1, -1}, - {(volatile spi_dev_t *)(DR_REG_SPI1_BASE), NULL, 1, -1, -1, -1, -1}, - {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 2, -1, -1, -1, -1}, - {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), NULL, 3, -1, -1, -1, -1} + {(volatile spi_dev_t *)(DR_REG_SPI0_BASE), NULL, 0, -1, -1, -1, -1, false}, + {(volatile spi_dev_t *)(DR_REG_SPI1_BASE), NULL, 1, -1, -1, -1, -1, false}, + {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 2, -1, -1, -1, -1, false}, + {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), NULL, 3, -1, -1, -1, -1, false} #endif }; #endif @@ -365,7 +366,7 @@ bool spiAttachSS(spi_t *spi, uint8_t ss_num, int8_t ss) { return false; } pinMode(ss, OUTPUT); - pinMatrixOutAttach(ss, SPI_SS_IDX(spi->num, ss_num), false, false); + pinMatrixOutAttach(ss, SPI_SS_IDX(spi->num, ss_num), spi->ss_invert, false); spiEnableSSPins(spi, (1 << ss_num)); spi->ss = ss; if (!perimanSetPinBus(ss, ESP32_BUS_TYPE_SPI_MASTER_SS, (void *)(spi->num + 1), spi->num, -1)) { @@ -435,6 +436,12 @@ void spiSSDisable(spi_t *spi) { SPI_MUTEX_UNLOCK(); } +void spiSSInvert(spi_t *spi, bool invert) { + if (spi) { + spi->ss_invert = invert; + } +} + void spiSSSet(spi_t *spi) { if (!spi) { return; diff --git a/cores/esp32/esp32-hal-spi.h b/cores/esp32/esp32-hal-spi.h index b77abff7854..7d56f0820d3 100644 --- a/cores/esp32/esp32-hal-spi.h +++ b/cores/esp32/esp32-hal-spi.h @@ -97,6 +97,8 @@ void spiSSSet(spi_t *spi); void spiSSClear(spi_t *spi); void spiWaitReady(spi_t *spi); +//invert hardware SS +void spiSSInvert(spi_t *spi, bool invert); uint32_t spiGetClockDiv(spi_t *spi); uint8_t spiGetDataMode(spi_t *spi); diff --git a/cores/esp32/esp32-hal-uart.c b/cores/esp32/esp32-hal-uart.c index 59a95a084f6..5311aff4f37 100644 --- a/cores/esp32/esp32-hal-uart.c +++ b/cores/esp32/esp32-hal-uart.c @@ -58,6 +58,7 @@ struct uart_struct_t { uint16_t _rx_buffer_size, _tx_buffer_size; // UART RX and TX buffer sizes bool _inverted; // UART inverted signal uint8_t _rxfifo_full_thrhd; // UART RX FIFO full threshold + int8_t _uart_clock_source; // UART Clock Source used when it is started using uartBegin() }; #if CONFIG_DISABLE_HAL_LOCKS @@ -66,21 +67,21 @@ struct uart_struct_t { #define UART_MUTEX_UNLOCK() static uart_t _uart_bus_array[] = { - {0, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, + {0, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1}, #if SOC_UART_NUM > 1 - {1, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, + {1, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1}, #endif #if SOC_UART_NUM > 2 - {2, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, + {2, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1}, #endif #if SOC_UART_NUM > 3 - {3, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, + {3, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1}, #endif #if SOC_UART_NUM > 4 - {4, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, + {4, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1}, #endif #if SOC_UART_NUM > 5 - {5, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, + {5, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1}, #endif }; @@ -95,21 +96,21 @@ static uart_t _uart_bus_array[] = { xSemaphoreGive(uart->lock) static uart_t _uart_bus_array[] = { - {NULL, 0, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, + {NULL, 0, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1}, #if SOC_UART_NUM > 1 - {NULL, 1, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, + {NULL, 1, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1}, #endif #if SOC_UART_NUM > 2 - {NULL, 2, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, + {NULL, 2, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1}, #endif #if SOC_UART_NUM > 3 - {NULL, 3, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, + {NULL, 3, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1}, #endif #if SOC_UART_NUM > 4 - {NULL, 4, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, + {NULL, 4, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1}, #endif #if SOC_UART_NUM > 5 - {NULL, 5, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, + {NULL, 5, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1}, #endif }; @@ -585,17 +586,11 @@ uart_t *uartBegin( uartEnd(uart_nr); } else { bool retCode = true; - UART_MUTEX_LOCK(); //User may just want to change some parameters, such as baudrate, data length, parity, stop bits or pins if (uart->_baudrate != baudrate) { - if (ESP_OK != uart_set_baudrate(uart_nr, baudrate)) { - log_e("UART%d changing baudrate failed.", uart_nr); - retCode = false; - } else { - log_v("UART%d changed baudrate to %d", uart_nr, baudrate); - uart->_baudrate = baudrate; - } + retCode = uartSetBaudRate(uart, baudrate); } + UART_MUTEX_LOCK(); uart_word_length_t data_bits = (config & 0xc) >> 2; uart_parity_t parity = config & 0x3; uart_stop_bits_t stop_bits = (config & 0x30) >> 4; @@ -670,30 +665,40 @@ uart_t *uartBegin( rxfifo_full_thrhd = uart_config.rx_flow_ctrl_thresh; // makes sure that it will be set correctly in the struct uart_config.baud_rate = baudrate; #if SOC_UART_LP_NUM >= 1 - if (uart_nr >= SOC_UART_HP_NUM) { // it is a LP UART NUM - uart_config.lp_source_clk = LP_UART_SCLK_DEFAULT; // use default LP clock - log_v("Setting UART%d to use LP clock", uart_nr); + if (uart_nr >= SOC_UART_HP_NUM) { // it is a LP UART NUM + if (uart->_uart_clock_source > 0) { + uart_config.lp_source_clk = (soc_periph_lp_uart_clk_src_t)uart->_uart_clock_source; // use user defined LP UART clock + log_v("Setting UART%d to user defined LP clock source (%d) ", uart_nr, uart->_uart_clock_source); + } else { + uart_config.lp_source_clk = LP_UART_SCLK_DEFAULT; // use default LP clock + log_v("Setting UART%d to Default LP clock source", uart_nr); + } } else -#endif +#endif // SOC_UART_LP_NUM >= 1 { - // there is an issue when returning from light sleep with the C6 and H2: the uart baud rate is not restored - // therefore, uart clock source will set to XTAL for all SoC that support it. This fix solves the C6|H2 issue. + if (uart->_uart_clock_source >= 0) { + uart_config.source_clk = (soc_module_clk_t)uart->_uart_clock_source; // use user defined HP UART clock + log_v("Setting UART%d to user defined HP clock source (%d) ", uart_nr, uart->_uart_clock_source); + } else { + // there is an issue when returning from light sleep with the C6 and H2: the uart baud rate is not restored + // therefore, uart clock source will set to XTAL for all SoC that support it. This fix solves the C6|H2 issue. #if SOC_UART_SUPPORT_XTAL_CLK - uart_config.source_clk = UART_SCLK_XTAL; // valid for C2, S3, C3, C6, H2 and P4 - log_v("Setting UART%d to use XTAL clock", uart_nr); + uart_config.source_clk = UART_SCLK_XTAL; // valid for C2, S3, C3, C6, H2 and P4 + log_v("Setting UART%d to use XTAL clock", uart_nr); #elif SOC_UART_SUPPORT_REF_TICK - if (baudrate <= REF_TICK_BAUDRATE_LIMIT) { - uart_config.source_clk = UART_SCLK_REF_TICK; // valid for ESP32, S2 - MAX supported baud rate is 250 Kbps - log_v("Setting UART%d to use REF_TICK clock", uart_nr); - } else { - uart_config.source_clk = UART_SCLK_APB; // baudrate may change with the APB Frequency! - log_v("Setting UART%d to use APB clock", uart_nr); - } + if (baudrate <= REF_TICK_BAUDRATE_LIMIT) { + uart_config.source_clk = UART_SCLK_REF_TICK; // valid for ESP32, S2 - MAX supported baud rate is 250 Kbps + log_v("Setting UART%d to use REF_TICK clock", uart_nr); + } else { + uart_config.source_clk = UART_SCLK_APB; // baudrate may change with the APB Frequency! + log_v("Setting UART%d to use APB clock", uart_nr); + } #else - // Default CLK Source: CLK_APB for ESP32|S2|S3|C3 -- CLK_PLL_F40M for C2 -- CLK_PLL_F48M for H2 -- CLK_PLL_F80M for C6 - uart_config.source_clk = UART_SCLK_DEFAULT; // baudrate may change with the APB Frequency! - log_v("Setting UART%d to use DEFAULT clock", uart_nr); -#endif + // Default CLK Source: CLK_APB for ESP32|S2|S3|C3 -- CLK_PLL_F40M for C2 -- CLK_PLL_F48M for H2 -- CLK_PLL_F80M for C6|P4 + uart_config.source_clk = UART_SCLK_DEFAULT; // baudrate may change with the APB Frequency! + log_v("Setting UART%d to use DEFAULT clock", uart_nr); +#endif // SOC_UART_SUPPORT_XTAL_CLK + } } UART_MUTEX_LOCK(); @@ -722,6 +727,14 @@ uart_t *uartBegin( uart->_tx_buffer_size = tx_buffer_size; uart->has_peek = false; uart->peek_byte = 0; +#if SOC_UART_LP_NUM >= 1 + if (uart_nr >= SOC_UART_HP_NUM) { + uart->_uart_clock_source = uart_config.lp_source_clk; + } else +#endif + { + uart->_uart_clock_source = uart_config.source_clk; + } } UART_MUTEX_UNLOCK(); @@ -763,7 +776,11 @@ bool uartSetRxTimeout(uart_t *uart, uint8_t numSymbTimeout) { if (uart == NULL) { return false; } - + uint16_t maxRXTimeout = uart_get_max_rx_timeout(uart->num); + if (numSymbTimeout > maxRXTimeout) { + log_e("Invalid RX Timeout value, its limit is %d", maxRXTimeout); + return false; + } UART_MUTEX_LOCK(); bool retCode = (ESP_OK == uart_set_rx_timeout(uart->num, numSymbTimeout)); UART_MUTEX_UNLOCK(); @@ -972,33 +989,66 @@ void uartFlushTxOnly(uart_t *uart, bool txOnly) { UART_MUTEX_UNLOCK(); } -void uartSetBaudRate(uart_t *uart, uint32_t baud_rate) { +bool uartSetBaudRate(uart_t *uart, uint32_t baud_rate) { if (uart == NULL) { - return; + return false; } - UART_MUTEX_LOCK(); -#if SOC_UART_SUPPORT_XTAL_CLK // ESP32-S3, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-H2 and ESP32-P4 - soc_module_clk_t newClkSrc = UART_SCLK_XTAL; + bool retCode = true; + soc_module_clk_t newClkSrc = UART_SCLK_DEFAULT; + int8_t previousClkSrc = uart->_uart_clock_source; #if SOC_UART_LP_NUM >= 1 if (uart->num >= SOC_UART_HP_NUM) { // it is a LP UART NUM - newClkSrc = LP_UART_SCLK_DEFAULT; // use default LP clock + if (uart->_uart_clock_source > 0) { + newClkSrc = (soc_periph_lp_uart_clk_src_t)uart->_uart_clock_source; // use user defined LP UART clock + log_v("Setting UART%d to user defined LP clock source (%d) ", uart->num, newClkSrc); + } else { + newClkSrc = LP_UART_SCLK_DEFAULT; // use default LP clock + log_v("Setting UART%d to Default LP clock source", uart->num); + } + } else +#endif // SOC_UART_LP_NUM >= 1 + { + if (uart->_uart_clock_source >= 0) { + newClkSrc = (soc_module_clk_t)uart->_uart_clock_source; // use user defined HP UART clock + log_v("Setting UART%d to use HP clock source (%d) ", uart->num, newClkSrc); + } else { + // there is an issue when returning from light sleep with the C6 and H2: the uart baud rate is not restored + // therefore, uart clock source will set to XTAL for all SoC that support it. This fix solves the C6|H2 issue. +#if SOC_UART_SUPPORT_XTAL_CLK + newClkSrc = UART_SCLK_XTAL; // valid for C2, S3, C3, C6, H2 and P4 + log_v("Setting UART%d to use XTAL clock", uart->num); +#elif SOC_UART_SUPPORT_REF_TICK + if (baud_rate <= REF_TICK_BAUDRATE_LIMIT) { + newClkSrc = UART_SCLK_REF_TICK; // valid for ESP32, S2 - MAX supported baud rate is 250 Kbps + log_v("Setting UART%d to use REF_TICK clock", uart->num); + } else { + newClkSrc = UART_SCLK_APB; // baudrate may change with the APB Frequency! + log_v("Setting UART%d to use APB clock", uart->num); + } +#else + // Default CLK Source: CLK_APB for ESP32|S2|S3|C3 -- CLK_PLL_F40M for C2 -- CLK_PLL_F48M for H2 -- CLK_PLL_F80M for C6|P4 + // using newClkSrc = UART_SCLK_DEFAULT as defined in the variable declaration + log_v("Setting UART%d to use DEFAULT clock", uart->num); +#endif // SOC_UART_SUPPORT_XTAL_CLK + } } -#endif - // ESP32-P4 demands an atomic operation for setting the clock source - HP_UART_SRC_CLK_ATOMIC() { - uart_ll_set_sclk(UART_LL_GET_HW(uart->num), newClkSrc); + UART_MUTEX_LOCK(); + // if necessary, set the correct UART Clock Source before changing the baudrate + if (previousClkSrc < 0 || previousClkSrc != newClkSrc) { + HP_UART_SRC_CLK_ATOMIC() { + uart_ll_set_sclk(UART_LL_GET_HW(uart->num), newClkSrc); + } + uart->_uart_clock_source = newClkSrc; } -#else // ESP32, ESP32-S2 - soc_module_clk_t newClkSrc = baud_rate <= REF_TICK_BAUDRATE_LIMIT ? SOC_MOD_CLK_REF_TICK : SOC_MOD_CLK_APB; - uart_ll_set_sclk(UART_LL_GET_HW(uart->num), newClkSrc); -#endif if (uart_set_baudrate(uart->num, baud_rate) == ESP_OK) { - log_v("Setting UART%d baud rate to %d.", uart->num, baud_rate); + log_v("Setting UART%d baud rate to %ld.", uart->num, baud_rate); uart->_baudrate = baud_rate; } else { - log_e("Setting UART%d baud rate to %d has failed.", uart->num, baud_rate); + retCode = false; + log_e("Setting UART%d baud rate to %ld has failed.", uart->num, baud_rate); } UART_MUTEX_UNLOCK(); + return retCode; } uint32_t uartGetBaudRate(uart_t *uart) { @@ -1083,6 +1133,31 @@ bool uartSetMode(uart_t *uart, uart_mode_t mode) { return retCode; } +// this function will set the uart clock source +// it must be called before uartBegin(), otherwise it won't change any thing. +bool uartSetClockSource(uint8_t uartNum, uart_sclk_t clkSrc) { + if (uartNum >= SOC_UART_NUM) { + log_e("UART%d is invalid. This device has %d UARTs, from 0 to %d.", uartNum, SOC_UART_NUM, SOC_UART_NUM - 1); + return false; + } + uart_t *uart = &_uart_bus_array[uartNum]; +#if SOC_UART_LP_NUM >= 1 + if (uart->num >= SOC_UART_HP_NUM) { + switch (clkSrc) { + case UART_SCLK_XTAL: uart->_uart_clock_source = LP_UART_SCLK_XTAL_D2; break; + case UART_SCLK_RTC: uart->_uart_clock_source = LP_UART_SCLK_LP_FAST; break; + case UART_SCLK_DEFAULT: + default: uart->_uart_clock_source = LP_UART_SCLK_DEFAULT; + } + } else +#endif + { + uart->_uart_clock_source = clkSrc; + } + //log_i("UART%d set clock source to %d", uart->num, uart->_uart_clock_source); + return true; +} + void uartSetDebug(uart_t *uart) { // LP UART is not supported for debug if (uart == NULL || uart->num >= SOC_UART_HP_NUM) { @@ -1111,7 +1186,7 @@ int log_printfv(const char *format, va_list arg) { return 0; } } -/* + /* // This causes dead locks with logging in specific cases and also with C++ constructors that may send logs #if !CONFIG_DISABLE_HAL_LOCKS if(s_uart_debug_nr != -1 && _uart_bus_array[s_uart_debug_nr].lock){ @@ -1119,16 +1194,8 @@ int log_printfv(const char *format, va_list arg) { } #endif */ -#if (ARDUINO_USB_CDC_ON_BOOT == 1 && ARDUINO_USB_MODE == 0) || CONFIG_IDF_TARGET_ESP32C3 \ - || ((CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32P4) && ARDUINO_USB_CDC_ON_BOOT == 1) vsnprintf(temp, len + 1, format, arg); ets_printf("%s", temp); -#else - int wlen = vsnprintf(temp, len + 1, format, arg); - for (int i = 0; i < wlen; i++) { - ets_write_char_uart(temp[i]); - } -#endif /* // This causes dead locks with logging and also with constructors that may send logs #if !CONFIG_DISABLE_HAL_LOCKS @@ -1385,4 +1452,24 @@ int uart_send_msg_with_break(uint8_t uartNum, uint8_t *msg, size_t msgSize) { return uart_write_bytes_with_break(uartNum, (const void *)msg, msgSize, 12); } +// returns the maximum valid uart RX Timeout based on the UART Source Clock and Baudrate +uint16_t uart_get_max_rx_timeout(uint8_t uartNum) { + if (uartNum >= SOC_UART_NUM) { + log_e("UART%d is invalid. This device has %d UARTs, from 0 to %d.", uartNum, SOC_UART_NUM, SOC_UART_NUM - 1); + return (uint16_t)-1; + } + uint16_t tout_max_thresh = uart_ll_max_tout_thrd(UART_LL_GET_HW(uartNum)); + uint8_t symbol_len = 1; // number of bits per symbol including start + uart_parity_t parity_mode; + uart_stop_bits_t stop_bit; + uart_word_length_t data_bit; + uart_ll_get_data_bit_num(UART_LL_GET_HW(uartNum), &data_bit); + uart_ll_get_stop_bits(UART_LL_GET_HW(uartNum), &stop_bit); + uart_ll_get_parity(UART_LL_GET_HW(uartNum), &parity_mode); + symbol_len += (data_bit < UART_DATA_BITS_MAX) ? (uint8_t)data_bit + 5 : 8; + symbol_len += (stop_bit > UART_STOP_BITS_1) ? 2 : 1; + symbol_len += (parity_mode > UART_PARITY_DISABLE) ? 1 : 0; + return (uint16_t)(tout_max_thresh / symbol_len); +} + #endif /* SOC_UART_SUPPORTED */ diff --git a/cores/esp32/esp32-hal-uart.h b/cores/esp32/esp32-hal-uart.h index 74249194da3..41b005aa151 100644 --- a/cores/esp32/esp32-hal-uart.h +++ b/cores/esp32/esp32-hal-uart.h @@ -58,7 +58,7 @@ void uartWriteBuf(uart_t *uart, const uint8_t *data, size_t len); void uartFlush(uart_t *uart); void uartFlushTxOnly(uart_t *uart, bool txOnly); -void uartSetBaudRate(uart_t *uart, uint32_t baud_rate); +bool uartSetBaudRate(uart_t *uart, uint32_t baud_rate); uint32_t uartGetBaudRate(uart_t *uart); void uartSetRxInvert(uart_t *uart, bool invert); @@ -97,6 +97,19 @@ bool uartSetHwFlowCtrlMode(uart_t *uart, uart_hw_flowcontrol_t mode, uint8_t thr // UART_MODE_RS485_APP_CTRL = 0x04 mode: application control RS485 UART mode (used for test purposes) bool uartSetMode(uart_t *uart, uart_mode_t mode); +// Used to set the UART clock source mode. It must be set before calling uartBegin(), otherwise it won't have any effect. +// Not all clock source are available to every SoC. The compatible option are listed here: +// UART_SCLK_DEFAULT :: any SoC - it will set whatever IDF defines as the default UART Clock Source +// UART_SCLK_APB :: ESP32, ESP32-S2, ESP32-C3 and ESP32-S3 +// UART_SCLK_PLL_F80M :: ESP32-C5, ESP32-C6, ESP32-C61 and ESP32-P4 +// UART_SCLK_PLL_F40M :: ESP32-C2 +// UART_SCLK_PLL_F48M :: ESP32-H2 +// UART_SCLK_XTAL :: ESP32-C2, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-H2, ESP32-S3 and ESP32-P4 +// UART_SCLK_RTC :: ESP32-C2, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-H2, ESP32-S3 and ESP32-P4 +// UART_SCLK_REF_TICK :: ESP32 and ESP32-S2 +// Note: ESP32-C6, C61, ESP32-P4 and ESP32-C5 have LP UART that will use only LP_UART_SCLK_LP_FAST (RTC_FAST) or LP_UART_SCLK_XTAL_D2 (XTAL/2) as Clock Source +bool uartSetClockSource(uint8_t uartNum, uart_sclk_t clkSrc); + void uartStartDetectBaudrate(uart_t *uart); unsigned long uartDetectBaudrate(uart_t *uart); @@ -116,6 +129,10 @@ void uart_send_break(uint8_t uartNum); // Sends a buffer and at the end of the stream, it generates BREAK in the line int uart_send_msg_with_break(uint8_t uartNum, uint8_t *msg, size_t msgSize); +// UART RX Timeout (in UART Symbols) depends on the UART Clock Source and the SoC that is used +// This is a helper function that calculates what is the maximum RX Timeout that a running UART IDF driver allows. +uint16_t uart_get_max_rx_timeout(uint8_t uartNum); + #ifdef __cplusplus } #endif diff --git a/cores/esp32/freertos_stats.cpp b/cores/esp32/freertos_stats.cpp index 50a98bf502b..b37a5205e11 100644 --- a/cores/esp32/freertos_stats.cpp +++ b/cores/esp32/freertos_stats.cpp @@ -31,7 +31,8 @@ void printRunningTasks(Print &printer) { #endif configRUN_TIME_COUNTER_TYPE ulTotalRunTime = 0; TaskStatus_t *pxTaskStatusArray = NULL; - volatile UBaseType_t uxArraySize = 0, x = 0; + volatile UBaseType_t uxArraySize = 0; + uint32_t x = 0; const char *taskStates[] = {"Running", "Ready", "Blocked", "Suspended", "Deleted", "Invalid"}; // Take a snapshot of the number of tasks in case it changes while this function is executing. diff --git a/docs/en/boards/boards.rst b/docs/en/boards/boards.rst index 05df917c8b1..407b019a78b 100644 --- a/docs/en/boards/boards.rst +++ b/docs/en/boards/boards.rst @@ -18,16 +18,18 @@ The ESP32 is divided by family: * ESP32 * Wi-Fi, BT and BLE 4 -* ESP32-S2 - * Wi-Fi only -* ESP32-S3 - * Wi-Fi and BLE 5 * ESP32-C3 * Wi-Fi and BLE 5 * ESP32-C6 * Wi-Fi, BLE 5 and IEEE 802.15.4 * ESP32-H2 * BLE 5 and IEEE 802.15.4 +* ESP32-P4 + * 400 MHz Dual Core RISC-V CPU, 40 MHz ULP Co-processor, single-precision FPU and AI extensions. +* ESP32-S2 + * Wi-Fi only +* ESP32-S3 + * Wi-Fi and BLE 5 For each family, we have SoC variants with some differentiation. The differences are more about the embedded flash and its size and the number of the cores (dual or single). diff --git a/docs/en/common/datasheet.inc b/docs/en/common/datasheet.inc index 193359fb73a..7086a12d1a8 100644 --- a/docs/en/common/datasheet.inc +++ b/docs/en/common/datasheet.inc @@ -2,16 +2,20 @@ Datasheet --------- * `ESP32`_ (Datasheet) -* `ESP32-S2`_ (Datasheet) +* `ESP32-C2`_ (Datasheet) * `ESP32-C3`_ (Datasheet) -* `ESP32-S3`_ (Datasheet) * `ESP32-C6`_ (Datasheet) * `ESP32-H2`_ (Datasheet) +* `ESP32-P4`_ (Datasheet) +* `ESP32-S2`_ (Datasheet) +* `ESP32-S3`_ (Datasheet) .. _Espressif Product Selector: https://products.espressif.com/ .. _ESP32: https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf -.. _ESP32-S2: https://www.espressif.com/sites/default/files/documentation/esp32-s2_datasheet_en.pdf +.. _ESP32-C2: https://www.espressif.com/sites/default/files/documentation/esp8684_datasheet_en.pdf .. _ESP32-C3: https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf -.. _ESP32-S3: https://www.espressif.com/sites/default/files/documentation/esp32-s3_datasheet_en.pdf .. _ESP32-C6: https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf .. _ESP32-H2: https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf +.. _ESP32-P4: https://www.espressif.com/sites/default/files/documentation/esp32-p4_datasheet_en.pdf +.. _ESP32-S2: https://www.espressif.com/sites/default/files/documentation/esp32-s2_datasheet_en.pdf +.. _ESP32-S3: https://www.espressif.com/sites/default/files/documentation/esp32-s3_datasheet_en.pdf diff --git a/docs/en/contributing.rst b/docs/en/contributing.rst index fb7843f1fb6..4ebe01cbf5b 100644 --- a/docs/en/contributing.rst +++ b/docs/en/contributing.rst @@ -15,6 +15,9 @@ Before Contributing Before sending us a Pull Request, please consider this: +* All contributions must be written in English to ensure effective communication and support. + Pull Requests written in other languages will be closed, with a request to rewrite them in English. + * Is the contribution entirely your own work, or is it already licensed under an LGPL 2.1 compatible Open Source License? If not, cannot accept it. @@ -318,7 +321,7 @@ ESP32-C3 target, you would run: ./.github/scripts/tests_build.sh -s uart -t esp32c3 -You should see the output of the build process and the test binary should be generated in the ``~/.arduino/tests//build.tmp`` folder. +You should see the output of the build process and the test binary should be generated in the ``~/.arduino/tests///build.tmp`` folder. Now that the test is built, you can run it in the target board. Connect the target board to your computer and run: @@ -339,7 +342,7 @@ The test will run on the target board and you should see the output of the test lucassvaz@Lucas--MacBook-Pro esp32 % ./.github/scripts/tests_run.sh -s uart -t esp32c3 Sketch uart test type: validation Running test: uart -- Config: Default - pytest tests --build-dir /Users/lucassvaz/.arduino/tests/uart/build.tmp -k test_uart --junit-xml=/Users/lucassvaz/Espressif/Arduino/hardware/espressif/esp32/tests/validation/uart/esp32c3/uart.xml --embedded-services esp,arduino + pytest tests --build-dir /Users/lucassvaz/.arduino/tests/esp32c3/uart/build.tmp -k test_uart --junit-xml=/Users/lucassvaz/Espressif/Arduino/hardware/espressif/esp32/tests/validation/uart/esp32c3/uart.xml --embedded-services esp,arduino =============================================================================================== test session starts ================================================================================================ platform darwin -- Python 3.12.3, pytest-8.2.2, pluggy-1.5.0 rootdir: /Users/lucassvaz/Espressif/Arduino/hardware/espressif/esp32/tests diff --git a/docs/en/getting_started.rst b/docs/en/getting_started.rst index cabb2ddc805..1b0f1bba87a 100644 --- a/docs/en/getting_started.rst +++ b/docs/en/getting_started.rst @@ -38,17 +38,18 @@ Here are the ESP32 series supported by the Arduino-ESP32 project: SoC Stable Development Datasheet ========== ====== =========== ================================= ESP32 Yes Yes `ESP32`_ -ESP32-S2 Yes Yes `ESP32-S2`_ ESP32-C3 Yes Yes `ESP32-C3`_ -ESP32-S3 Yes Yes `ESP32-S3`_ ESP32-C6 Yes Yes `ESP32-C6`_ ESP32-H2 Yes Yes `ESP32-H2`_ +ESP32-P4 Yes Yes `ESP32-P4`_ +ESP32-S2 Yes Yes `ESP32-S2`_ +ESP32-S3 Yes Yes `ESP32-S3`_ ========== ====== =========== ================================= .. note:: - ESP32-C2 is also supported by Arduino-ESP32 but requires rebuilding the static libraries. - This is not trivial and requires a good understanding of the ESP-IDF build system. - For more information, see the `Lib Builder documentation `_. + ESP32-C2 is also supported by Arduino-ESP32 but requires using Arduino as an ESP-IDF component or rebuilding the static libraries. + For more information, see the `Arduino as an ESP-IDF component documentation `_ or the + `Lib Builder documentation `_, respectively. See `Boards `_ for more details about ESP32 development boards. diff --git a/docs/en/installing.rst b/docs/en/installing.rst index d5392d4b5ec..35342020864 100644 --- a/docs/en/installing.rst +++ b/docs/en/installing.rst @@ -10,6 +10,11 @@ Before Installing We recommend you install the support using your favorite IDE, but other options are available depending on your operating system. To install Arduino-ESP32 support, you can use one of the following options. +.. note:: + Users in China might have troubles with connection and download speeds using GitHub. Please use our Jihulab mirror as the repository source: + + ``https://jihulab.com/esp-mirror/espressif/arduino-esp32.git`` + Installing using Arduino IDE ---------------------------- @@ -32,6 +37,16 @@ This is the way to install Arduino-ESP32 directly from the Arduino IDE. https://espressif.github.io/arduino-esp32/package_esp32_dev_index.json +Users in China might have troubles with connection and download speeds using the links above. Please use our Jihulab mirror: + +- Stable release link:: + + https://jihulab.com/esp-mirror/espressif/arduino-esp32/-/raw/gh-pages/package_esp32_index_cn.json + +- Development release link:: + + https://jihulab.com/esp-mirror/espressif/arduino-esp32/-/raw/gh-pages/package_esp32_dev_index_cn.json + .. note:: Starting with the Arduino IDE version 1.6.4, Arduino allows installation of third-party platform packages using Boards Manager. We have packages available for Windows, macOS, and Linux. diff --git a/docs/en/lib_builder.rst b/docs/en/lib_builder.rst index 478becc3350..e7edb331fd3 100644 --- a/docs/en/lib_builder.rst +++ b/docs/en/lib_builder.rst @@ -151,13 +151,13 @@ Set the build target(chip). ex. 'esp32s3' This build command will build for the ESP32-S3 target. You can specify other targets. * esp32 -* esp32s2 -* esp32s3 * esp32c2 * esp32c3 * esp32c6 * esp32h2 * esp32p4 +* esp32s2 +* esp32s3 Set Build Type ^^^^^^^^^^^^^^ diff --git a/docs/en/libraries.rst b/docs/en/libraries.rst index 0e3499f7783..525a5c4ba26 100644 --- a/docs/en/libraries.rst +++ b/docs/en/libraries.rst @@ -9,60 +9,68 @@ Supported Peripherals Currently, the Arduino ESP32 supports the following peripherals with Arduino APIs. -+---------------+-------+-------+-------+-------+-------+-------+-------+ -| Peripheral | ESP32 | S2 | C3 | S3 | C6 | H2 | Notes | -+===============+=======+=======+=======+=======+=======+=======+=======+ -| ADC | Yes | Yes | Yes | Yes | Yes | Yes | | -+---------------+-------+-------+-------+-------+-------+-------+-------+ -| BT Classic | Yes | N/A | N/A | N/A | N/A | N/A | | -+---------------+-------+-------+-------+-------+-------+-------+-------+ -| BLE | Yes | N/A | Yes | Yes | Yes | Yes | | -+---------------+-------+-------+-------+-------+-------+-------+-------+ -| DAC | Yes | Yes | N/A | N/A | N/A | N/A | | -+---------------+-------+-------+-------+-------+-------+-------+-------+ -| Ethernet | Yes | N/A | N/A | N/A | N/A | N/A | (*) | -+---------------+-------+-------+-------+-------+-------+-------+-------+ -| GPIO | Yes | Yes | Yes | Yes | Yes | Yes | | -+---------------+-------+-------+-------+-------+-------+-------+-------+ -| Hall Sensor | N/A | N/A | N/A | N/A | N/A | N/A | | -+---------------+-------+-------+-------+-------+-------+-------+-------+ -| I2C | Yes | Yes | Yes | Yes | Yes | Yes | | -+---------------+-------+-------+-------+-------+-------+-------+-------+ -| I2S | Yes | Yes | Yes | Yes | Yes | Yes | | -+---------------+-------+-------+-------+-------+-------+-------+-------+ -| LEDC | Yes | Yes | Yes | Yes | Yes | Yes | | -+---------------+-------+-------+-------+-------+-------+-------+-------+ -| Motor PWM | No | N/A | N/A | N/A | N/A | N/A | | -+---------------+-------+-------+-------+-------+-------+-------+-------+ -| Pulse Counter | No | No | No | No | No | No | | -+---------------+-------+-------+-------+-------+-------+-------+-------+ -| RMT | Yes | Yes | Yes | Yes | Yes | Yes | | -+---------------+-------+-------+-------+-------+-------+-------+-------+ -| SDIO | No | No | No | No | No | No | | -+---------------+-------+-------+-------+-------+-------+-------+-------+ -| SDMMC | Yes | N/A | N/A | Yes | N/A | N/A | | -+---------------+-------+-------+-------+-------+-------+-------+-------+ -| Timer | Yes | Yes | Yes | Yes | Yes | Yes | | -+---------------+-------+-------+-------+-------+-------+-------+-------+ -| Temp. Sensor | N/A | Yes | Yes | Yes | Yes | Yes | | -+---------------+-------+-------+-------+-------+-------+-------+-------+ -| Touch | Yes | Yes | N/A | Yes | N/A | N/A | | -+---------------+-------+-------+-------+-------+-------+-------+-------+ -| TWAI | No | No | No | No | No | No | | -+---------------+-------+-------+-------+-------+-------+-------+-------+ -| UART | Yes | Yes | Yes | Yes | Yes | Yes | | -+---------------+-------+-------+-------+-------+-------+-------+-------+ -| USB | N/A | Yes | Yes | Yes | Yes | Yes | (**) | -+---------------+-------+-------+-------+-------+-------+-------+-------+ -| Wi-Fi | Yes | Yes | Yes | Yes | Yes | N/A | | -+---------------+-------+-------+-------+-------+-------+-------+-------+ ++---------------+-------+-------+-------+-------+-------+-------+-------+-------+ +| Peripheral | ESP32 | C3 | C6 | H2 | P4 | S2 | S3 | Notes | ++===============+=======+=======+=======+=======+=======+=======+=======+=======+ +| ADC | Yes | Yes | Yes | Yes | Yes | Yes | Yes | (1) | ++---------------+-------+-------+-------+-------+-------+-------+-------+-------+ +| BT Classic | Yes | N/A | N/A | N/A | N/A | N/A | N/A | | ++---------------+-------+-------+-------+-------+-------+-------+-------+-------+ +| BLE | Yes | Yes | Yes | Yes | No | N/A | Yes | | ++---------------+-------+-------+-------+-------+-------+-------+-------+-------+ +| DAC | Yes | N/A | N/A | N/A | Yes | Yes | N/A | | ++---------------+-------+-------+-------+-------+-------+-------+-------+-------+ +| Ethernet | Yes | N/A | N/A | N/A | Yes | N/A | N/A | (2) | ++---------------+-------+-------+-------+-------+-------+-------+-------+-------+ +| GPIO | Yes | Yes | Yes | Yes | Yes | Yes | Yes | | ++---------------+-------+-------+-------+-------+-------+-------+-------+-------+ +| Hall Sensor | N/A | N/A | N/A | N/A | N/A | N/A | N/A | | ++---------------+-------+-------+-------+-------+-------+-------+-------+-------+ +| I2C | Yes | Yes | Yes | Yes | Yes | Yes | Yes | | ++---------------+-------+-------+-------+-------+-------+-------+-------+-------+ +| I2S | Yes | Yes | Yes | Yes | Yes | Yes | Yes | | ++---------------+-------+-------+-------+-------+-------+-------+-------+-------+ +| LEDC | Yes | Yes | Yes | Yes | Yes | Yes | Yes | | ++---------------+-------+-------+-------+-------+-------+-------+-------+-------+ +| MIPI | N/A | N/A | N/A | N/A | No | N/A | N/A | | ++---------------+-------+-------+-------+-------+-------+-------+-------+-------+ +| Motor PWM | No | N/A | N/A | N/A | N/A | N/A | N/A | | ++---------------+-------+-------+-------+-------+-------+-------+-------+-------+ +| MSPI | N/A | N/A | N/A | N/A | No | N/A | N/A | | ++---------------+-------+-------+-------+-------+-------+-------+-------+-------+ +| Pulse Counter | No | No | No | No | No | No | No | | ++---------------+-------+-------+-------+-------+-------+-------+-------+-------+ +| RMT | Yes | Yes | Yes | Yes | Yes | Yes | Yes | | ++---------------+-------+-------+-------+-------+-------+-------+-------+-------+ +| SDIO | No | No | No | No | No | No | No | | ++---------------+-------+-------+-------+-------+-------+-------+-------+-------+ +| SDMMC | Yes | N/A | N/A | N/A | N/A | N/A | Yes | | ++---------------+-------+-------+-------+-------+-------+-------+-------+-------+ +| Timer | Yes | Yes | Yes | Yes | Yes | Yes | Yes | | ++---------------+-------+-------+-------+-------+-------+-------+-------+-------+ +| Temp. Sensor | N/A | Yes | Yes | Yes | Yes | Yes | Yes | | ++---------------+-------+-------+-------+-------+-------+-------+-------+-------+ +| Touch | Yes | N/A | N/A | N/A | Yes | Yes | Yes | | ++---------------+-------+-------+-------+-------+-------+-------+-------+-------+ +| TWAI | No | No | No | No | No | No | No | | ++---------------+-------+-------+-------+-------+-------+-------+-------+-------+ +| UART | Yes | Yes | Yes | Yes | Yes | Yes | Yes | | ++---------------+-------+-------+-------+-------+-------+-------+-------+-------+ +| USB | N/A | Yes | Yes | Yes | Yes | Yes | Yes | (3) | ++---------------+-------+-------+-------+-------+-------+-------+-------+-------+ +| Wi-Fi | Yes | Yes | Yes | N/A | Yes | Yes | Yes | (4) | ++---------------+-------+-------+-------+-------+-------+-------+-------+-------+ Notes ^^^^^ -(*) SPI Ethernet is supported by all ESP32 families and RMII only for ESP32. +(1) ESP32-P4 calibration schemes not supported yet in IDF and ADC Continuous also lacks IDF support. -(**) ESP32-C3, C6, H2 only support USB CDC/JTAG +(2) SPI Ethernet is supported by all ESP32 families and RMII only for ESP32 and ESP32-P4. + +(3) ESP32-C3, C6, H2 only support USB CDC/JTAG + +(4) ESP32-P4 only supports Wi-Fi through another SoC by using ``esp_hosted``. .. note:: Some peripherals are not available for all ESP32 families. To see more details about it, see the corresponding SoC at `Product Selector `_ page. diff --git a/docs/en/troubleshooting.rst b/docs/en/troubleshooting.rst index f6a241729f5..ea9a6db94d6 100644 --- a/docs/en/troubleshooting.rst +++ b/docs/en/troubleshooting.rst @@ -14,6 +14,23 @@ Installing Here are the common issues during the installation. +Slow or unstable downloads +************************** + +Users in China might have troubles with connection and download speeds using GitHub. Please use our Jihulab mirror as the repository source: + +`https://jihulab.com/esp-mirror/espressif/arduino-esp32.git `_ + +JSON files for the boards manager are available here: + +- Stable release:: + + https://jihulab.com/esp-mirror/espressif/arduino-esp32/-/raw/gh-pages/package_esp32_index_cn.json + +- Development release:: + + https://jihulab.com/esp-mirror/espressif/arduino-esp32/-/raw/gh-pages/package_esp32_dev_index_cn.json + Building -------- diff --git a/idf_component_examples/.gitignore b/idf_component_examples/.gitignore new file mode 100644 index 00000000000..6052fd4e70b --- /dev/null +++ b/idf_component_examples/.gitignore @@ -0,0 +1,4 @@ +build/ +managed_components/ +dependencies.lock +sdkconfig diff --git a/idf_component_examples/esp_matter_light/CMakeLists.txt b/idf_component_examples/esp_matter_light/CMakeLists.txt index 16a7533f2a5..1430df8ff78 100644 --- a/idf_component_examples/esp_matter_light/CMakeLists.txt +++ b/idf_component_examples/esp_matter_light/CMakeLists.txt @@ -8,6 +8,7 @@ set(PROJECT_VER_NUMBER 1) # This should be done before using the IDF_TARGET variable. include($ENV{IDF_PATH}/tools/cmake/project.cmake) +idf_build_set_property(MINIMAL_BUILD ON) project(arduino_managed_component_light) # WARNING: This is just an example for using key for decrypting the encrypted OTA image @@ -20,7 +21,7 @@ if(CONFIG_IDF_TARGET_ESP32C2) include(relinker) endif() -idf_build_set_property(CXX_COMPILE_OPTIONS "-std=gnu++17;-Os;-DCHIP_HAVE_CONFIG_H" APPEND) +idf_build_set_property(CXX_COMPILE_OPTIONS "-std=gnu++2a;-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 diff --git a/idf_component_examples/esp_matter_light/README.md b/idf_component_examples/esp_matter_light/README.md index 06a22cdceac..b0173f6a437 100644 --- a/idf_component_examples/esp_matter_light/README.md +++ b/idf_component_examples/esp_matter_light/README.md @@ -59,15 +59,22 @@ Use ESP-IDF 5.1.4 from https://github.com/espressif/esp-idf/tree/release/v5.1 This example has been tested with Arduino Core 3.0.4 The project will download all necessary components, including the Arduino Core. -Run `idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults..idf" -p flash monitor` +Execute this sequence: + ` using linux rm command or Windows rmdir command` + `idf.py set-target ` + `idf.py -D SDKCONFIG_DEFAULTS="sdkconfig_file1;sdkconfig_file2;sdkconfig_fileX" -p flash monitor` Example for ESP32-S3/Linux | macOS: ``` -idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults.esp32s3" -p /dev/ttyACM0 flash monitor +rm -rf build +idf.py set-target esp32s3 +idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults" -p /dev/ttyACM0 flash monitor ``` Example for ESP32-C3/Windows: ``` -idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults.esp32c3" -p com3 flash monitor +rmdir /s/q build +idf.py set-target esp32c3 +idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults" -p com3 flash monitor ``` It may be necessary to delete some folders and files before running `idf.py` @@ -95,11 +102,15 @@ In order to build the application that will use Thread Networking instead of Wi- Example for ESP32-C6/Linux | macOS: ``` -idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults.c6_thread" -p /dev/ttyACM0 flash monitor +rm -rf build +idf.py set-target esp32c6 +idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.defaults.c6_thread" -p /dev/ttyACM0 flash monitor ``` Example for ESP32-C6/Windows: ``` -idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults.c6_thread" -p com3 flash monitor +rmdir /s/q build +idf.py set-targt esp32c6 +idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.defaults.c6_thread" -p com3 flash monitor ``` It may be necessary to delete some folders and files before running `idf.py` diff --git a/idf_component_examples/esp_matter_light/ci.json b/idf_component_examples/esp_matter_light/ci.json new file mode 100644 index 00000000000..f23a085285d --- /dev/null +++ b/idf_component_examples/esp_matter_light/ci.json @@ -0,0 +1,11 @@ +{ + "targets": { + "esp32c2": false, + "esp32s2": false + }, + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y", + "CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y", + "CONFIG_MBEDTLS_HKDF_C=y" + ] +} diff --git a/idf_component_examples/esp_matter_light/main/Kconfig.projbuild b/idf_component_examples/esp_matter_light/main/Kconfig.projbuild index 6e6abcb7fcf..3e0a35c5e15 100644 --- a/idf_component_examples/esp_matter_light/main/Kconfig.projbuild +++ b/idf_component_examples/esp_matter_light/main/Kconfig.projbuild @@ -3,100 +3,40 @@ menu "Light Matter Accessory" config BUTTON_PIN int prompt "Button 1 GPIO" - default ENV_GPIO_BOOT_BUTTON + default 9 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C6 + default 0 range -1 ENV_GPIO_IN_RANGE_MAX help The GPIO pin for button that will be used to turn on/off the Matter Light. It shall be connected to a push button. It can use the BOOT button of the development board. endmenu - menu "LEDs" config WS2812_PIN int prompt "WS2812 RGB LED GPIO" - default ENV_GPIO_RGB_LED + default 8 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C6 + default 48 range -1 ENV_GPIO_OUT_RANGE_MAX help The GPIO pin for the Matter Light that will be driven by RMT. It shall be connected to one single WS2812 RGB LED. endmenu - # TARGET CONFIGURATION - if IDF_TARGET_ESP32C3 - config ENV_GPIO_RANGE_MIN - int - default 0 - - config ENV_GPIO_RANGE_MAX - int - default 19 - # GPIOs 20/21 are always used by UART in examples - - config ENV_GPIO_IN_RANGE_MAX - int - default ENV_GPIO_RANGE_MAX - - config ENV_GPIO_OUT_RANGE_MAX - int - default ENV_GPIO_RANGE_MAX - - config ENV_GPIO_BOOT_BUTTON - int - default 9 - - config ENV_GPIO_RGB_LED - int - default 8 - endif - if IDF_TARGET_ESP32C6 - config ENV_GPIO_RANGE_MIN - int - default 0 + config ENV_GPIO_RANGE_MIN + int + default 0 - config ENV_GPIO_RANGE_MAX - int - default 30 - # GPIOs 16/17 are always used by UART in examples + config ENV_GPIO_RANGE_MAX + int + default 19 if IDF_TARGET_ESP32C3 + default 30 if IDF_TARGET_ESP32C6 + default 48 - config ENV_GPIO_IN_RANGE_MAX - int - default ENV_GPIO_RANGE_MAX + config ENV_GPIO_IN_RANGE_MAX + int + default ENV_GPIO_RANGE_MAX - config ENV_GPIO_OUT_RANGE_MAX - int - default ENV_GPIO_RANGE_MAX - - config ENV_GPIO_BOOT_BUTTON - int - default 9 - - config ENV_GPIO_RGB_LED - int - default 8 - endif - if IDF_TARGET_ESP32S3 - config ENV_GPIO_RANGE_MIN - int - default 0 - - config ENV_GPIO_RANGE_MAX - int - default 48 - - config ENV_GPIO_IN_RANGE_MAX - int - default ENV_GPIO_RANGE_MAX - - config ENV_GPIO_OUT_RANGE_MAX - int - default ENV_GPIO_RANGE_MAX - - config ENV_GPIO_BOOT_BUTTON - int - default 0 - - config ENV_GPIO_RGB_LED - int - default 48 - endif + config ENV_GPIO_OUT_RANGE_MAX + int + default ENV_GPIO_RANGE_MAX endmenu diff --git a/idf_component_examples/esp_matter_light/main/idf_component.yml b/idf_component_examples/esp_matter_light/main/idf_component.yml index 2b4ae4b34a4..e0286324591 100644 --- a/idf_component_examples/esp_matter_light/main/idf_component.yml +++ b/idf_component_examples/esp_matter_light/main/idf_component.yml @@ -1,9 +1,9 @@ dependencies: espressif/esp_matter: - version: "^1.3.0" + version: ">=1.3.0" # Adds Arduino Core from GitHub repository using main branch espressif/arduino-esp32: - version: "^3.0.5" + version: ">=3.0.5" override_path: "../../../" pre_release: true diff --git a/idf_component_examples/esp_matter_light/sdkconfig.defaults.esp32c3 b/idf_component_examples/esp_matter_light/sdkconfig.defaults similarity index 98% rename from idf_component_examples/esp_matter_light/sdkconfig.defaults.esp32c3 rename to idf_component_examples/esp_matter_light/sdkconfig.defaults index df6d6b0d585..43871661856 100644 --- a/idf_component_examples/esp_matter_light/sdkconfig.defaults.esp32c3 +++ b/idf_component_examples/esp_matter_light/sdkconfig.defaults @@ -1,5 +1,3 @@ -CONFIG_IDF_TARGET="esp32c3" - # Arduino Settings CONFIG_FREERTOS_HZ=1000 CONFIG_AUTOSTART_ARDUINO=y diff --git a/idf_component_examples/esp_matter_light/sdkconfig.defaults.esp32c6 b/idf_component_examples/esp_matter_light/sdkconfig.defaults.esp32c6 index f228f3158c8..9fe589613ef 100644 --- a/idf_component_examples/esp_matter_light/sdkconfig.defaults.esp32c6 +++ b/idf_component_examples/esp_matter_light/sdkconfig.defaults.esp32c6 @@ -1,68 +1,5 @@ CONFIG_IDF_TARGET="esp32c6" -# Arduino Settings -CONFIG_FREERTOS_HZ=1000 -CONFIG_AUTOSTART_ARDUINO=y - -# Log Levels -# Boot Messages - Log level -CONFIG_BOOTLOADER_LOG_LEVEL_ERROR=y -# Arduino Log Level -CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL_INFO=y -# IDF Log Level -CONFIG_LOG_DEFAULT_LEVEL_ERROR=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 -CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y - -#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 - -# Use a custom partition table -CONFIG_PARTITION_TABLE_CUSTOM=y -CONFIG_PARTITION_TABLE_FILENAME="partitions.csv" -CONFIG_PARTITION_TABLE_OFFSET=0xC000 - -# Disable chip shell -CONFIG_ENABLE_CHIP_SHELL=n - -# Enable OTA Requester -CONFIG_ENABLE_OTA_REQUESTOR=n - -#enable lwIP route hooks -CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT=y -CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT=y - -# disable softap by default -CONFIG_ESP_WIFI_SOFTAP_SUPPORT=n -CONFIG_ENABLE_WIFI_STATION=y -CONFIG_ENABLE_WIFI_AP=n - -# Disable DS Peripheral -CONFIG_ESP_SECURE_CERT_DS_PERIPHERAL=n - -# Use compact attribute storage mode -CONFIG_ESP_MATTER_NVS_USE_COMPACT_ATTR_STORAGE=y - -# Enable HKDF in mbedtls -CONFIG_MBEDTLS_HKDF_C=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 - # libsodium CONFIG_LIBSODIUM_USE_MBEDTLS_SHA=y diff --git a/idf_component_examples/esp_matter_light/sdkconfig.defaults.esp32s3 b/idf_component_examples/esp_matter_light/sdkconfig.defaults.esp32s3 deleted file mode 100644 index 9c1aa36b6c9..00000000000 --- a/idf_component_examples/esp_matter_light/sdkconfig.defaults.esp32s3 +++ /dev/null @@ -1,64 +0,0 @@ -CONFIG_IDF_TARGET="esp32s3" - -# Arduino Settings -CONFIG_FREERTOS_HZ=1000 -CONFIG_AUTOSTART_ARDUINO=y - -# Log Levels -# Boot Messages - Log level -CONFIG_BOOTLOADER_LOG_LEVEL_ERROR=y -# Arduino Log Level -CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL_INFO=y -# IDF Log Level -CONFIG_LOG_DEFAULT_LEVEL_ERROR=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 -CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y - -#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 - -# Use a custom partition table -CONFIG_PARTITION_TABLE_CUSTOM=y -CONFIG_PARTITION_TABLE_FILENAME="partitions.csv" -CONFIG_PARTITION_TABLE_OFFSET=0xC000 - -# Disable chip shell -CONFIG_ENABLE_CHIP_SHELL=n - -# Enable OTA Requester -CONFIG_ENABLE_OTA_REQUESTOR=n - -#enable lwIP route hooks -CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT=y -CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT=y - -# disable softap by default -CONFIG_ESP_WIFI_SOFTAP_SUPPORT=n -CONFIG_ENABLE_WIFI_STATION=y -CONFIG_ENABLE_WIFI_AP=n - -# Disable DS Peripheral -CONFIG_ESP_SECURE_CERT_DS_PERIPHERAL=n - -# Use compact attribute storage mode -CONFIG_ESP_MATTER_NVS_USE_COMPACT_ATTR_STORAGE=y - -# Enable HKDF in mbedtls -CONFIG_MBEDTLS_HKDF_C=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 diff --git a/idf_component_examples/hello_world/CMakeLists.txt b/idf_component_examples/hello_world/CMakeLists.txt index 664d45871d0..af087cf42b6 100644 --- a/idf_component_examples/hello_world/CMakeLists.txt +++ b/idf_component_examples/hello_world/CMakeLists.txt @@ -5,4 +5,6 @@ cmake_minimum_required(VERSION 3.16) include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +idf_build_set_property(MINIMAL_BUILD ON) project(main) diff --git a/idf_component_examples/hw_cdc_hello_world/CMakeLists.txt b/idf_component_examples/hw_cdc_hello_world/CMakeLists.txt index 16bb1063af3..1c3971f4dbf 100644 --- a/idf_component_examples/hw_cdc_hello_world/CMakeLists.txt +++ b/idf_component_examples/hw_cdc_hello_world/CMakeLists.txt @@ -9,4 +9,5 @@ include($ENV{IDF_PATH}/tools/cmake/project.cmake) list(APPEND compile_definitions "ARDUINO_USB_CDC_ON_BOOT=1") list(APPEND compile_definitions "ARDUINO_USB_MODE=1") +idf_build_set_property(MINIMAL_BUILD ON) project(hw_cdc_hello_world) diff --git a/idf_component_examples/hw_cdc_hello_world/ci.json b/idf_component_examples/hw_cdc_hello_world/ci.json new file mode 100644 index 00000000000..80669afc2cc --- /dev/null +++ b/idf_component_examples/hw_cdc_hello_world/ci.json @@ -0,0 +1,5 @@ +{ + "requires": [ + "CONFIG_SOC_USB_SERIAL_JTAG_SUPPORTED=y" + ] +} diff --git a/libraries/BLE/src/BLEAdvertising.cpp b/libraries/BLE/src/BLEAdvertising.cpp index 2d71c4d7478..fe39a69c206 100644 --- a/libraries/BLE/src/BLEAdvertising.cpp +++ b/libraries/BLE/src/BLEAdvertising.cpp @@ -183,7 +183,7 @@ void BLEAdvertising::setScanFilter(bool scanRequestWhitelistOnly, bool connectWh * @brief Set the advertisement data that is to be published in a regular advertisement. * @param [in] advertisementData The data to be advertised. */ -void BLEAdvertising::setAdvertisementData(BLEAdvertisementData &advertisementData) { +bool BLEAdvertising::setAdvertisementData(BLEAdvertisementData &advertisementData) { log_v(">> setAdvertisementData"); esp_err_t errRc = ::esp_ble_gap_config_adv_data_raw((uint8_t *)advertisementData.getPayload().c_str(), advertisementData.getPayload().length()); if (errRc != ESP_OK) { @@ -191,13 +191,14 @@ void BLEAdvertising::setAdvertisementData(BLEAdvertisementData &advertisementDat } m_customAdvData = true; // Set the flag that indicates we are using custom advertising data. log_v("<< setAdvertisementData"); + return ESP_OK == errRc; } // setAdvertisementData /** * @brief Set the advertisement data that is to be published in a scan response. * @param [in] advertisementData The data to be advertised. */ -void BLEAdvertising::setScanResponseData(BLEAdvertisementData &advertisementData) { +bool BLEAdvertising::setScanResponseData(BLEAdvertisementData &advertisementData) { log_v(">> setScanResponseData"); esp_err_t errRc = ::esp_ble_gap_config_scan_rsp_data_raw((uint8_t *)advertisementData.getPayload().c_str(), advertisementData.getPayload().length()); if (errRc != ESP_OK) { @@ -205,6 +206,7 @@ void BLEAdvertising::setScanResponseData(BLEAdvertisementData &advertisementData } m_customScanResponseData = true; // Set the flag that indicates we are using custom scan response data. log_v("<< setScanResponseData"); + return ESP_OK == errRc; } // setScanResponseData /** @@ -212,7 +214,7 @@ void BLEAdvertising::setScanResponseData(BLEAdvertisementData &advertisementData * Start advertising. * @return N/A. */ -void BLEAdvertising::start() { +bool BLEAdvertising::start() { log_v(">> start: customAdvData: %d, customScanResponseData: %d", m_customAdvData, m_customScanResponseData); // We have a vector of service UUIDs that we wish to advertise. In order to use the @@ -225,7 +227,7 @@ void BLEAdvertising::start() { m_advData.p_service_uuid = (uint8_t *)malloc(m_advData.service_uuid_len); if (!m_advData.p_service_uuid) { log_e(">> start failed: out of memory"); - return; + return false; } uint8_t *p = m_advData.p_service_uuid; @@ -250,7 +252,7 @@ void BLEAdvertising::start() { errRc = ::esp_ble_gap_config_adv_data(&m_advData); if (errRc != ESP_OK) { log_e("<< esp_ble_gap_config_adv_data: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return; + return false; } } @@ -266,7 +268,7 @@ void BLEAdvertising::start() { errRc = ::esp_ble_gap_config_adv_data(&m_scanRespData); if (errRc != ESP_OK) { log_e("<< esp_ble_gap_config_adv_data (Scan response): rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return; + return false; } } @@ -279,9 +281,10 @@ void BLEAdvertising::start() { errRc = ::esp_ble_gap_start_advertising(&m_advParams); if (errRc != ESP_OK) { log_e("<< esp_ble_gap_start_advertising: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return; + } else { + log_v("<< start"); } - log_v("<< start"); + return ESP_OK == errRc; } // start /** @@ -289,14 +292,15 @@ void BLEAdvertising::start() { * Stop advertising. * @return N/A. */ -void BLEAdvertising::stop() { +bool BLEAdvertising::stop() { log_v(">> stop"); esp_err_t errRc = ::esp_ble_gap_stop_advertising(); if (errRc != ESP_OK) { log_e("esp_ble_gap_stop_advertising: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return; + } else { + log_v("<< stop"); } - log_v("<< stop"); + return ESP_OK == errRc; } // stop /** @@ -305,17 +309,17 @@ void BLEAdvertising::stop() { * @param [in] Bluetooth address type. * Set BLE address. */ - -void BLEAdvertising::setDeviceAddress(esp_bd_addr_t addr, esp_ble_addr_type_t type) { +bool BLEAdvertising::setDeviceAddress(esp_bd_addr_t addr, esp_ble_addr_type_t type) { log_v(">> setPrivateAddress"); m_advParams.own_addr_type = type; esp_err_t errRc = esp_ble_gap_set_rand_addr((uint8_t *)addr); if (errRc != ESP_OK) { log_e("esp_ble_gap_set_rand_addr: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return; + } else { + log_v("<< setPrivateAddress"); } - log_v("<< setPrivateAddress"); + return ESP_OK == errRc; } // setPrivateAddress /** diff --git a/libraries/BLE/src/BLEAdvertising.h b/libraries/BLE/src/BLEAdvertising.h index 9da70a3d9ca..1e573ac814f 100644 --- a/libraries/BLE/src/BLEAdvertising.h +++ b/libraries/BLE/src/BLEAdvertising.h @@ -54,18 +54,18 @@ class BLEAdvertising { bool removeServiceUUID(int index); bool removeServiceUUID(BLEUUID serviceUUID); bool removeServiceUUID(const char *serviceUUID); - void start(); - void stop(); + bool start(); + bool stop(); void setAppearance(uint16_t appearance); void setAdvertisementType(esp_ble_adv_type_t adv_type); void setAdvertisementChannelMap(esp_ble_adv_channel_t channel_map); void setMaxInterval(uint16_t maxinterval); void setMinInterval(uint16_t mininterval); - void setAdvertisementData(BLEAdvertisementData &advertisementData); + bool setAdvertisementData(BLEAdvertisementData &advertisementData); void setScanFilter(bool scanRequestWhitelistOnly, bool connectWhitelistOnly); - void setScanResponseData(BLEAdvertisementData &advertisementData); + bool setScanResponseData(BLEAdvertisementData &advertisementData); void setPrivateAddress(esp_ble_addr_type_t type = BLE_ADDR_TYPE_RANDOM); - void setDeviceAddress(esp_bd_addr_t addr, esp_ble_addr_type_t type = BLE_ADDR_TYPE_RANDOM); + bool setDeviceAddress(esp_bd_addr_t addr, esp_ble_addr_type_t type = BLE_ADDR_TYPE_RANDOM); void handleGAPEvent(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param); void setMinPreferred(uint16_t); diff --git a/libraries/ESP32/examples/Camera/CameraWebServer/app_httpd.cpp b/libraries/ESP32/examples/Camera/CameraWebServer/app_httpd.cpp index 81d643e37ac..cc924bd5b3b 100644 --- a/libraries/ESP32/examples/Camera/CameraWebServer/app_httpd.cpp +++ b/libraries/ESP32/examples/Camera/CameraWebServer/app_httpd.cpp @@ -478,6 +478,7 @@ static esp_err_t status_handler(httpd_req_t *req) { p += sprintf(p, "\"raw_gma\":%u,", s->status.raw_gma); p += sprintf(p, "\"lenc\":%u,", s->status.lenc); p += sprintf(p, "\"hmirror\":%u,", s->status.hmirror); + p += sprintf(p, "\"vflip\":%u,", s->status.vflip); p += sprintf(p, "\"dcw\":%u,", s->status.dcw); p += sprintf(p, "\"colorbar\":%u", s->status.colorbar); #if CONFIG_LED_ILLUMINATOR_ENABLED diff --git a/libraries/ESP32/examples/Camera/CameraWebServer/camera_index.h b/libraries/ESP32/examples/Camera/CameraWebServer/camera_index.h index 07e2d661821..b38e2773af3 100644 --- a/libraries/ESP32/examples/Camera/CameraWebServer/camera_index.h +++ b/libraries/ESP32/examples/Camera/CameraWebServer/camera_index.h @@ -1,260 +1,265 @@ -//File: index_ov2640.html.gz, Size: 6578 -#define index_ov2640_html_gz_len 6578 +//File: index_ov2640.html.gz, Size: 6687 +#define index_ov2640_html_gz_len 6687 const unsigned char index_ov2640_html_gz[] = { - 0x1F, 0x8B, 0x08, 0x08, 0x99, 0xA8, 0x7B, 0x67, 0x00, 0x03, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x5F, 0x6F, 0x76, 0x32, 0x36, 0x34, 0x30, 0x2E, 0x68, 0x74, 0x6D, - 0x6C, 0x00, 0xED, 0x3D, 0x6B, 0x73, 0xDB, 0x46, 0x92, 0xDF, 0xFD, 0x2B, 0x60, 0x24, 0x6B, 0x92, 0x65, 0x92, 0x22, 0x29, 0x4A, 0x96, 0x15, 0x89, 0x3E, 0x5B, - 0x56, 0x6C, 0xD7, 0xDA, 0x89, 0xD7, 0x4A, 0x1C, 0x6F, 0xA5, 0xB6, 0x6C, 0x10, 0x18, 0x92, 0x88, 0x41, 0x80, 0x0B, 0x80, 0xA2, 0x98, 0x94, 0x7E, 0xC7, 0xFD, - 0xA0, 0xFB, 0x63, 0xD7, 0x3D, 0x0F, 0x60, 0x00, 0x0C, 0x5E, 0xA4, 0x4C, 0x7A, 0x7D, 0x47, 0xA7, 0x22, 0x3C, 0x7A, 0x7A, 0xFA, 0xDD, 0x3D, 0x33, 0x18, 0xE0, - 0xEC, 0xBE, 0xE5, 0x99, 0xE1, 0x7A, 0x41, 0xB4, 0x59, 0x38, 0x77, 0x46, 0xF7, 0xCE, 0xD8, 0x1F, 0x0D, 0x7E, 0x67, 0x33, 0x62, 0x58, 0xEC, 0x90, 0x9E, 0xCE, - 0x49, 0x68, 0x68, 0xE6, 0xCC, 0xF0, 0x03, 0x12, 0x9E, 0xEB, 0xCB, 0x70, 0xD2, 0x39, 0xD1, 0xD3, 0xB7, 0x5D, 0x63, 0x4E, 0xCE, 0xF5, 0x6B, 0x9B, 0xAC, 0x16, - 0x9E, 0x1F, 0xEA, 0x9A, 0xE9, 0xB9, 0x21, 0x71, 0x01, 0x7C, 0x65, 0x5B, 0xE1, 0xEC, 0xDC, 0x22, 0xD7, 0xB6, 0x49, 0x3A, 0xF4, 0xA4, 0x6D, 0xBB, 0x76, 0x68, - 0x1B, 0x4E, 0x27, 0x30, 0x0D, 0x87, 0x9C, 0xF7, 0x65, 0x5C, 0xA1, 0x1D, 0x3A, 0x64, 0x74, 0x79, 0xF5, 0xF6, 0x70, 0xA0, 0xFD, 0xFC, 0x7E, 0x30, 0x3C, 0xEE, - 0x9D, 0x1D, 0xB0, 0x6B, 0x31, 0x4C, 0x10, 0xAE, 0xE5, 0x73, 0xFC, 0x8D, 0x3D, 0x6B, 0xAD, 0xFD, 0x95, 0xB8, 0x84, 0xBF, 0x09, 0x10, 0xD1, 0x99, 0x18, 0x73, - 0xDB, 0x59, 0x9F, 0x6A, 0x4F, 0x7D, 0xE8, 0xB3, 0xFD, 0x92, 0x38, 0xD7, 0x24, 0xB4, 0x4D, 0xA3, 0x1D, 0x18, 0x6E, 0xD0, 0x09, 0x88, 0x6F, 0x4F, 0x7E, 0xC8, - 0x34, 0x1C, 0x1B, 0xE6, 0xE7, 0xA9, 0xEF, 0x2D, 0x5D, 0xEB, 0x54, 0xFB, 0xAE, 0x7F, 0x82, 0xFF, 0xB2, 0x40, 0xA6, 0xE7, 0x78, 0x3E, 0xDC, 0xBF, 0xFC, 0x11, - 0xFF, 0x65, 0xEF, 0xD3, 0xDE, 0x03, 0xFB, 0x4F, 0x72, 0xAA, 0xF5, 0x8F, 0x17, 0x37, 0x89, 0xFB, 0xB7, 0xF7, 0x12, 0xA7, 0xB3, 0x41, 0x1E, 0xF5, 0xBC, 0xFD, - 0x49, 0x71, 0xFB, 0x80, 0x98, 0xA1, 0xED, 0xB9, 0xDD, 0xB9, 0x61, 0xBB, 0x0A, 0x4C, 0x96, 0x1D, 0x2C, 0x1C, 0x03, 0x64, 0x30, 0x71, 0x48, 0x21, 0x9E, 0xEF, - 0xE6, 0xC4, 0x5D, 0xB6, 0x4B, 0xB0, 0x21, 0x92, 0x8E, 0x65, 0xFB, 0x0C, 0xEA, 0x14, 0xE5, 0xB0, 0x9C, 0xBB, 0xA5, 0x68, 0x8B, 0xE8, 0x72, 0x3D, 0x97, 0x28, - 0x04, 0x88, 0x1D, 0xAD, 0x7C, 0x63, 0x81, 0x00, 0xF8, 0x37, 0x0B, 0x32, 0xB7, 0x5D, 0x66, 0x54, 0xA7, 0xDA, 0xE1, 0xB0, 0xB7, 0xB8, 0x29, 0x51, 0xE5, 0xE1, - 0x31, 0xFE, 0xCB, 0x02, 0x2D, 0x0C, 0xCB, 0xB2, 0xDD, 0xE9, 0xA9, 0x76, 0xA2, 0x44, 0xE1, 0xF9, 0x16, 0xF1, 0x3B, 0xBE, 0x61, 0xD9, 0xCB, 0xE0, 0x54, 0x1B, - 0xAA, 0x60, 0xE6, 0x86, 0x3F, 0x05, 0x5A, 0x42, 0x0F, 0x88, 0xED, 0xF4, 0x95, 0x94, 0x70, 0x10, 0xDF, 0x9E, 0xCE, 0x42, 0x50, 0x69, 0x06, 0x26, 0x2D, 0x34, - 0xEE, 0x42, 0x65, 0xFA, 0x2C, 0x94, 0x9B, 0x5A, 0x6A, 0x86, 0x63, 0x4F, 0xDD, 0x8E, 0x1D, 0x92, 0x39, 0xB0, 0x13, 0x84, 0x3E, 0x09, 0xCD, 0x59, 0x11, 0x29, - 0x13, 0x7B, 0xBA, 0xF4, 0x89, 0x82, 0x90, 0x48, 0x6E, 0x05, 0x0C, 0xC3, 0xCD, 0xEC, 0xAD, 0xCE, 0x8A, 0x8C, 0x3F, 0xDB, 0x61, 0x87, 0xCB, 0x64, 0x4C, 0x26, - 0x9E, 0x4F, 0x94, 0x90, 0x02, 0xC2, 0xF1, 0xCC, 0xCF, 0x9D, 0x20, 0x34, 0xFC, 0xB0, 0x0A, 0x42, 0x63, 0x12, 0x12, 0xBF, 0x1C, 0x1F, 0x41, 0xAB, 0x28, 0xC7, - 0x96, 0xDF, 0x2D, 0x07, 0xB0, 0x5D, 0xC7, 0x76, 0x49, 0x75, 0xF2, 0xF2, 0xFA, 0x4D, 0xA2, 0x63, 0x50, 0x15, 0x14, 0x63, 0xCF, 0xA7, 0x45, 0x56, 0x42, 0x79, - 0xCD, 0x76, 0xC6, 0xFD, 0xA6, 0xDF, 0xEB, 0xFD, 0x2D, 0x7B, 0x73, 0x46, 0x98, 0x99, 0x1A, 0xCB, 0xD0, 0xDB, 0xDE, 0x23, 0x32, 0x6E, 0x95, 0xE2, 0xE3, 0xBF, - 0xE6, 0xC4, 0xB2, 0x0D, 0xAD, 0x29, 0xB9, 0xF3, 0x49, 0x0F, 0x6C, 0xAA, 0xA5, 0x19, 0xAE, 0xA5, 0x35, 0x3D, 0xDF, 0x06, 0x47, 0x30, 0x68, 0xB8, 0x71, 0xE0, - 0x0A, 0x24, 0x8E, 0x05, 0x69, 0x29, 0x58, 0x2E, 0xF0, 0x19, 0x59, 0x22, 0x6A, 0xB7, 0xC1, 0x5F, 0x85, 0x90, 0x83, 0xBF, 0x52, 0x07, 0x52, 0xF0, 0x48, 0xD1, - 0x17, 0xE9, 0x4B, 0xA6, 0x30, 0x4F, 0x67, 0xF8, 0x9B, 0x1B, 0x37, 0x9D, 0x42, 0xDD, 0x09, 0x20, 0xA1, 0x43, 0x48, 0xB3, 0x66, 0x13, 0x40, 0xAF, 0x67, 0x5A, - 0x47, 0xC3, 0x28, 0xD9, 0x52, 0xB7, 0xE1, 0x48, 0xD5, 0x2A, 0xC7, 0x9F, 0x6C, 0x14, 0x35, 0xD8, 0x55, 0xB3, 0x1A, 0xC7, 0x0E, 0xF6, 0x4F, 0x65, 0x43, 0x8C, - 0x93, 0xDC, 0x28, 0x82, 0xBF, 0xEA, 0x91, 0x24, 0x46, 0x56, 0x1A, 0x4D, 0x14, 0x88, 0xF3, 0x23, 0x4A, 0x06, 0x6F, 0x9E, 0x77, 0x2B, 0xB0, 0x16, 0x93, 0x50, - 0x35, 0xBA, 0x28, 0x10, 0x17, 0xD1, 0x50, 0x1A, 0x65, 0xF0, 0x77, 0x5B, 0xA1, 0xDE, 0xF8, 0x6E, 0xBC, 0x0C, 0x43, 0xCF, 0x0D, 0xB6, 0x4A, 0x51, 0x79, 0x7E, - 0xF6, 0xC7, 0x32, 0x08, 0xED, 0xC9, 0xBA, 0xC3, 0x5D, 0x1A, 0xFC, 0x6C, 0x61, 0x40, 0x09, 0x39, 0x26, 0xE1, 0x8A, 0x90, 0xE2, 0x72, 0xC3, 0x35, 0xAE, 0x21, - 0xEE, 0x4C, 0xA7, 0x8E, 0xCA, 0xF6, 0xCC, 0xA5, 0x1F, 0x60, 0xDD, 0xB6, 0xF0, 0x6C, 0x40, 0xEC, 0x67, 0x3B, 0x4E, 0xFA, 0x60, 0xC5, 0x8E, 0x3A, 0xE6, 0x58, - 0xD1, 0x97, 0xB7, 0x0C, 0x51, 0xC6, 0x4A, 0x4D, 0x78, 0xC0, 0x8E, 0x1D, 0xAE, 0x95, 0xF7, 0xB8, 0x27, 0x2A, 0xEE, 0x08, 0x17, 0x2C, 0x4C, 0x0B, 0x49, 0xBA, - 0x4E, 0xCD, 0x19, 0x31, 0x3F, 0x13, 0xEB, 0x61, 0x69, 0x19, 0x56, 0x56, 0x1E, 0x76, 0x6D, 0x77, 0xB1, 0x0C, 0x3B, 0x58, 0x4E, 0x2D, 0xBE, 0x88, 0xCE, 0xA9, - 0x41, 0x0A, 0x16, 0x07, 0x83, 0xA2, 0xA2, 0xE2, 0x68, 0x71, 0x53, 0x2C, 0x04, 0x99, 0xD8, 0x91, 0x63, 0x8C, 0x89, 0x53, 0x44, 0x32, 0x77, 0x86, 0x9C, 0xB0, - 0xCB, 0x63, 0x55, 0x7E, 0xED, 0x46, 0x29, 0x8B, 0x93, 0xD7, 0xF0, 0xD1, 0xDF, 0x2A, 0xCB, 0x91, 0x1E, 0xB7, 0x13, 0x97, 0x02, 0xE2, 0x80, 0x83, 0xE5, 0x95, - 0xDE, 0x00, 0xB3, 0x02, 0x1A, 0x0A, 0x3B, 0xF0, 0x0D, 0x77, 0x4A, 0x20, 0x16, 0xDC, 0xB4, 0xC5, 0x61, 0xF1, 0xC0, 0xA0, 0x12, 0xFB, 0x18, 0xAA, 0x8F, 0x8A, - 0x07, 0x22, 0x2C, 0x20, 0xB4, 0xB5, 0x2E, 0x3B, 0xD8, 0xA0, 0x2A, 0x91, 0xF4, 0x5B, 0x48, 0x48, 0x5F, 0x69, 0x1D, 0xAC, 0x30, 0x51, 0x7A, 0x4E, 0xD2, 0xB6, - 0x94, 0x85, 0x7E, 0x69, 0x68, 0x10, 0x43, 0xBE, 0xC9, 0xA4, 0x6C, 0xD0, 0x38, 0x99, 0x1C, 0xF6, 0x0E, 0x87, 0xA5, 0x95, 0x93, 0x92, 0xCB, 0xD4, 0xC0, 0x51, - 0x11, 0x3A, 0xA2, 0xB0, 0x52, 0x68, 0x04, 0x81, 0x71, 0xAD, 0x2C, 0xDA, 0xBD, 0xC0, 0x66, 0x23, 0x37, 0x63, 0x1C, 0xC0, 0xD8, 0x2D, 0x54, 0x0C, 0xBD, 0xB8, - 0xA1, 0x0F, 0x94, 0xF4, 0xD1, 0x92, 0x4E, 0xE9, 0x02, 0x42, 0xBC, 0x6A, 0xB2, 0x13, 0x1A, 0x50, 0x83, 0x48, 0x0A, 0x56, 0x16, 0x95, 0x21, 0xB9, 0x09, 0x3B, - 0x16, 0x31, 0x3D, 0x9F, 0x55, 0x83, 0x39, 0x23, 0xC7, 0x94, 0x22, 0xCB, 0x2D, 0xF6, 0x74, 0xE6, 0x5D, 0x13, 0x5F, 0x21, 0xAC, 0x94, 0x52, 0x87, 0x8F, 0x87, - 0x56, 0x05, 0x6C, 0x06, 0xA4, 0x47, 0xA5, 0xEC, 0x93, 0xE8, 0x06, 0x7D, 0x73, 0x50, 0xE8, 0xC7, 0x0C, 0x5D, 0x17, 0x7C, 0xC6, 0x18, 0x3B, 0xC4, 0x2A, 0xC8, - 0x66, 0x16, 0x99, 0x18, 0x4B, 0x27, 0x2C, 0xB1, 0x4A, 0xA3, 0x87, 0xFF, 0x8A, 0x7A, 0xA4, 0x61, 0xE8, 0x77, 0x9C, 0x17, 0x3A, 0xA7, 0x81, 0xE3, 0x5F, 0x8A, - 0x3E, 0x45, 0xA9, 0x61, 0x2C, 0x16, 0xC4, 0x00, 0x28, 0x93, 0xE4, 0xE9, 0xA1, 0xD2, 0x10, 0x43, 0x1D, 0xE7, 0x2B, 0x8D, 0xDB, 0x4B, 0x1D, 0x36, 0x2A, 0x1E, - 0x6B, 0xF1, 0x7C, 0x3A, 0xF1, 0xCC, 0xA5, 0xAA, 0xAA, 0xA9, 0xE6, 0x78, 0x59, 0x7C, 0xA7, 0x42, 0x64, 0x81, 0x63, 0x53, 0xF7, 0x5F, 0xBA, 0x2E, 0x6A, 0xB4, - 0x13, 0xFA, 0xC0, 0xA6, 0xA2, 0xA3, 0x6A, 0x82, 0xDB, 0x28, 0x86, 0x25, 0x04, 0x9B, 0x37, 0x77, 0x95, 0x0A, 0x53, 0x8A, 0x70, 0x1A, 0x45, 0x5A, 0x0D, 0x62, - 0x88, 0x6D, 0x09, 0x54, 0xDB, 0xC9, 0x25, 0x9C, 0x2D, 0xE7, 0xAA, 0x3A, 0x4A, 0x74, 0xD6, 0x87, 0xA4, 0xCF, 0xBA, 0xF3, 0xA7, 0x63, 0xA3, 0xD9, 0x6B, 0xF7, - 0xDA, 0x87, 0xF0, 0x3F, 0xC5, 0x78, 0xA6, 0xD8, 0xB8, 0xB8, 0x78, 0x73, 0x2C, 0x2F, 0x15, 0xA2, 0xCB, 0xA7, 0x95, 0xF2, 0x82, 0x7D, 0xA9, 0x2E, 0xAA, 0x7B, - 0x52, 0x72, 0x7E, 0xA9, 0xDF, 0x2D, 0xC9, 0xC3, 0x39, 0x26, 0x5D, 0xDF, 0x10, 0x15, 0xD6, 0x52, 0x57, 0xC5, 0x73, 0xEF, 0xCF, 0x0E, 0x2B, 0x42, 0xFE, 0xCF, - 0x5B, 0xBB, 0x24, 0x8A, 0x6F, 0xDA, 0xD2, 0x6B, 0xCB, 0x25, 0xD8, 0xB7, 0x6D, 0xF4, 0xF2, 0xB5, 0xDE, 0xE1, 0x55, 0x1F, 0x50, 0xE8, 0xC2, 0x18, 0xD4, 0x87, - 0xC1, 0x68, 0x6E, 0x65, 0x28, 0xC1, 0x6C, 0x20, 0x83, 0x89, 0xED, 0x38, 0x1D, 0xC7, 0x5B, 0x95, 0x57, 0x22, 0xC5, 0x96, 0x9C, 0xB1, 0xD3, 0x72, 0x93, 0xDF, - 0x94, 0xDA, 0x25, 0x44, 0xAE, 0xFF, 0x08, 0x6A, 0xBF, 0x6D, 0x87, 0x2B, 0x74, 0x8D, 0xCD, 0x12, 0xC5, 0x06, 0xF6, 0xB8, 0x5D, 0x47, 0x95, 0x4C, 0x89, 0x55, - 0x82, 0xC5, 0xC3, 0x9E, 0x95, 0x1D, 0x9A, 0xB3, 0x0D, 0x86, 0x9E, 0xF1, 0xC0, 0xC8, 0x27, 0x8E, 0x81, 0x15, 0xFC, 0x46, 0x33, 0x14, 0xA5, 0xC3, 0x37, 0xB9, - 0x79, 0x15, 0x4E, 0xA8, 0xE8, 0xBE, 0x9E, 0xD9, 0xA5, 0x2E, 0xAB, 0x1D, 0xF2, 0x63, 0xB5, 0xDA, 0xAC, 0x4B, 0xCA, 0xFD, 0xA4, 0x67, 0xA8, 0x81, 0x6A, 0x44, - 0x74, 0x11, 0xB4, 0xA7, 0x3E, 0x59, 0x57, 0x60, 0xA6, 0xCD, 0xFF, 0x9E, 0xB2, 0xF9, 0xE3, 0xCD, 0xA7, 0x4A, 0x68, 0x02, 0xE0, 0x56, 0xD4, 0x1D, 0x06, 0x15, - 0xBA, 0xCE, 0xEF, 0xB2, 0x8A, 0x3D, 0x46, 0xB3, 0xA3, 0xBA, 0x5E, 0x21, 0xDC, 0x14, 0xA4, 0x50, 0xB5, 0xA9, 0x8A, 0xEC, 0xAB, 0x1E, 0xCF, 0x93, 0x49, 0x98, - 0xB3, 0xF8, 0x43, 0xEB, 0xD4, 0xC3, 0xE2, 0xE8, 0xD6, 0x91, 0x66, 0x53, 0x4A, 0x23, 0x47, 0x34, 0x89, 0x99, 0x6F, 0x7D, 0x4A, 0xCC, 0x18, 0x3D, 0x6B, 0x23, - 0xCF, 0x57, 0x89, 0x28, 0x9F, 0xA9, 0x9A, 0x01, 0x66, 0xCE, 0x53, 0x3E, 0xA8, 0x87, 0x7C, 0x68, 0x0E, 0x8E, 0x95, 0x6B, 0x2B, 0x05, 0xC0, 0x45, 0xA4, 0xE5, - 0xCE, 0x02, 0x66, 0x53, 0x56, 0xEE, 0x00, 0x59, 0x8E, 0x45, 0x4A, 0x45, 0x15, 0x7B, 0x65, 0x51, 0x84, 0xC9, 0xCE, 0x64, 0x15, 0x1A, 0xBB, 0x3D, 0x37, 0xA0, - 0xEC, 0x45, 0x73, 0x35, 0x00, 0xA3, 0x4A, 0x7F, 0x55, 0xCC, 0x5D, 0x9A, 0x63, 0xED, 0x1F, 0xF7, 0x4A, 0xBA, 0x34, 0x1D, 0x2F, 0xD8, 0x72, 0x02, 0x2C, 0x7F, - 0xFE, 0x4B, 0x79, 0xA7, 0x52, 0xEA, 0x2E, 0xF4, 0xA9, 0x62, 0x77, 0x4C, 0xC9, 0xBC, 0xDF, 0x53, 0x46, 0xDA, 0xC2, 0x59, 0x4A, 0x3A, 0x83, 0x46, 0xD7, 0x2F, - 0x4F, 0x35, 0x93, 0xA8, 0xC3, 0x68, 0x72, 0xA2, 0xAE, 0xCA, 0x54, 0x69, 0xA1, 0x1E, 0x66, 0xB6, 0x65, 0x91, 0xC2, 0xB9, 0x60, 0x1C, 0xF3, 0x56, 0x2C, 0x1E, - 0x90, 0x7E, 0xD5, 0xA4, 0xD4, 0x17, 0x71, 0x8A, 0xC2, 0xC7, 0x1A, 0xFA, 0x5F, 0xDA, 0x63, 0x78, 0xA2, 0xC9, 0x9B, 0x49, 0x4F, 0x96, 0x22, 0x85, 0xA4, 0x2A, - 0x9D, 0x3B, 0x9A, 0x6B, 0x45, 0x91, 0x81, 0x1C, 0x10, 0x2A, 0x1B, 0xCD, 0x53, 0x54, 0xD1, 0x85, 0x94, 0x2E, 0x5F, 0x5B, 0xE2, 0xCB, 0x80, 0x9D, 0xBC, 0xD5, - 0x95, 0x3B, 0x5C, 0x6A, 0xA3, 0x16, 0x90, 0xEE, 0x37, 0x57, 0x34, 0x7B, 0xAA, 0x8C, 0x0A, 0x88, 0x8C, 0x52, 0x8C, 0x78, 0xB8, 0x2A, 0x09, 0xB5, 0xA9, 0x73, - 0x9C, 0x1D, 0x48, 0x4F, 0xC3, 0x9D, 0x1D, 0xC4, 0x0F, 0xEE, 0x9D, 0xE1, 0x23, 0x71, 0xF2, 0x43, 0x73, 0xBC, 0x1F, 0xD3, 0x31, 0x82, 0xE0, 0x5C, 0xC7, 0x47, - 0xBB, 0xF4, 0xE4, 0x33, 0x74, 0x67, 0x96, 0x7D, 0xAD, 0xD9, 0xD6, 0xB9, 0xEE, 0x78, 0x53, 0x2F, 0x75, 0x8F, 0xDE, 0x67, 0x5A, 0x86, 0x3C, 0x76, 0xAE, 0x27, - 0xD6, 0x17, 0x75, 0xDA, 0x2A, 0xBE, 0xA4, 0x8F, 0x1E, 0x7C, 0xF7, 0xF8, 0xD1, 0xA3, 0xE3, 0x1F, 0x1E, 0xB8, 0xE3, 0x60, 0xC1, 0xFF, 0xFF, 0x0B, 0x5B, 0x8E, - 0xFD, 0xF9, 0xFD, 0xE0, 0x78, 0x08, 0xC3, 0x3D, 0x12, 0x86, 0x60, 0x7A, 0xC1, 0xD9, 0x01, 0x45, 0x9A, 0x22, 0xE4, 0x00, 0x28, 0xC9, 0xA1, 0x8D, 0x97, 0x3B, - 0x2A, 0xF2, 0x04, 0x48, 0x00, 0x19, 0x7C, 0x6C, 0xF8, 0x0A, 0x10, 0x0A, 0xC6, 0x8A, 0x69, 0x1A, 0x4A, 0x74, 0xAA, 0x93, 0xB1, 0x77, 0x93, 0xE6, 0x80, 0x32, - 0xC5, 0x15, 0xC6, 0xA1, 0x88, 0x95, 0x87, 0x10, 0x9A, 0xD1, 0xE6, 0xB8, 0xB8, 0x0A, 0x30, 0x4A, 0xA0, 0x84, 0x0A, 0x10, 0xF8, 0xC6, 0x74, 0x3E, 0x0B, 0xDD, - 0xEB, 0x42, 0x29, 0xAE, 0x17, 0xB2, 0x50, 0x99, 0xD3, 0x55, 0x82, 0x55, 0xDE, 0x46, 0x5A, 0x36, 0x64, 0x5C, 0x80, 0x68, 0x3B, 0x14, 0x3B, 0xBB, 0x56, 0x8C, - 0x89, 0x62, 0x93, 0xF4, 0x2A, 0x1A, 0xEB, 0xA3, 0x0F, 0x17, 0xAF, 0xFF, 0xAE, 0xBD, 0x79, 0xF9, 0xA7, 0x52, 0x43, 0x65, 0x44, 0x61, 0x8C, 0xAE, 0xD0, 0x33, - 0x6D, 0xC6, 0xF4, 0x21, 0x64, 0xA2, 0x73, 0xCD, 0x50, 0x0C, 0x98, 0xED, 0x1D, 0xE2, 0x4E, 0xC3, 0xD9, 0xB9, 0xDE, 0xD7, 0xF1, 0x91, 0x16, 0x71, 0x36, 0xD0, - 0x35, 0x8C, 0xDF, 0xF4, 0xE0, 0xDA, 0x70, 0x96, 0x78, 0xD4, 0xAB, 0xC2, 0x6B, 0xD6, 0xB4, 0x94, 0x60, 0x3C, 0xB0, 0x44, 0x32, 0x96, 0x02, 0x71, 0x52, 0xCA, - 0xFA, 0xE8, 0x8A, 0x84, 0x67, 0x07, 0xEC, 0x56, 0x89, 0xD6, 0x8A, 0xFB, 0x06, 0x4F, 0x66, 0xE6, 0x50, 0x64, 0x42, 0x45, 0x8A, 0x9F, 0xF8, 0xC6, 0x9C, 0xA0, - 0x54, 0x2A, 0x69, 0x5E, 0xD6, 0x7A, 0xD4, 0x52, 0x1F, 0xBD, 0x23, 0xB4, 0x20, 0x02, 0x32, 0x2A, 0x29, 0xFE, 0x8C, 0xD7, 0xA8, 0x89, 0xFE, 0x23, 0x7B, 0xE6, - 0x6B, 0x52, 0x1D, 0x83, 0x99, 0x79, 0x05, 0xB9, 0xDF, 0xEF, 0x74, 0xB4, 0xC1, 0x9B, 0xB7, 0x5A, 0xA7, 0x53, 0x01, 0xD8, 0x5B, 0x50, 0x77, 0xE2, 0xFA, 0xEF, - 0x1F, 0xE9, 0xA3, 0x5F, 0x3F, 0xBC, 0x78, 0xDA, 0x84, 0xBA, 0xB0, 0x77, 0xD3, 0x1F, 0xF4, 0x7A, 0xAD, 0xB3, 0x03, 0x06, 0x52, 0x1F, 0xD7, 0x10, 0xF4, 0x4A, - 0x71, 0x0D, 0x4E, 0x00, 0x57, 0x6F, 0x30, 0xDC, 0x02, 0xD7, 0xA1, 0x3E, 0x7A, 0xF9, 0x9C, 0x61, 0x7A, 0x34, 0xD8, 0x86, 0xA8, 0x01, 0x78, 0x25, 0xD2, 0x04, - 0xE4, 0xDC, 0x3C, 0x3A, 0x3E, 0xD9, 0x02, 0x53, 0x1F, 0xD8, 0x7B, 0x0F, 0xA8, 0x4E, 0x40, 0x52, 0xC7, 0x5B, 0x09, 0x0A, 0x9C, 0x0E, 0x11, 0x41, 0x4C, 0xBF, - 0x19, 0x9E, 0x6C, 0x81, 0xE8, 0x31, 0x08, 0x09, 0x11, 0x01, 0x92, 0x9B, 0xC3, 0x6D, 0xA4, 0x74, 0xA2, 0x8F, 0x2E, 0x5E, 0xFD, 0xD8, 0x1C, 0x02, 0x67, 0x83, - 0xC7, 0xC7, 0x75, 0xF0, 0x80, 0xED, 0x25, 0x51, 0x3D, 0xD2, 0x47, 0x40, 0x0A, 0x92, 0x23, 0xB0, 0x80, 0x59, 0x32, 0x1B, 0xFD, 0xD5, 0x0D, 0x96, 0x0B, 0x7C, - 0xD0, 0x9D, 0x58, 0x1A, 0x34, 0xF0, 0xAE, 0x69, 0x56, 0xDB, 0xC0, 0x6A, 0x8F, 0xF5, 0xD1, 0x3F, 0x90, 0x6F, 0xEC, 0x68, 0x30, 0xDC, 0x82, 0x6F, 0xB0, 0x7E, - 0x68, 0x8F, 0x38, 0x36, 0x46, 0x01, 0x46, 0xFF, 0x92, 0x12, 0x83, 0x88, 0xFA, 0x8F, 0x6A, 0x09, 0x2F, 0x89, 0x09, 0x4C, 0xFE, 0x1F, 0xA8, 0x05, 0x40, 0x72, - 0xD3, 0x1F, 0x6E, 0xE1, 0x3C, 0x60, 0xF2, 0xE0, 0x38, 0xE0, 0xCD, 0x27, 0x9B, 0x9B, 0x28, 0xD0, 0x42, 0xB9, 0x82, 0xB8, 0x80, 0x61, 0x61, 0x73, 0x62, 0xC0, - 0xD6, 0x1F, 0x1F, 0xDF, 0x3C, 0x3E, 0xAE, 0x86, 0x00, 0xE3, 0x39, 0xC6, 0xC6, 0xA2, 0x88, 0x5F, 0x9C, 0x10, 0x8A, 0x82, 0xFD, 0xBF, 0x97, 0x30, 0x84, 0x0B, - 0xD7, 0xB5, 0x43, 0x3D, 0x6F, 0x07, 0x32, 0x61, 0x07, 0xD5, 0xA2, 0xBC, 0x44, 0x49, 0xF4, 0x34, 0x91, 0x3E, 0x1A, 0x56, 0xC8, 0xA6, 0x89, 0x72, 0x8B, 0xB6, - 0x4D, 0xD0, 0x4F, 0x53, 0x3C, 0x5A, 0x1E, 0x26, 0x77, 0xF0, 0x86, 0x43, 0x5D, 0x8A, 0x2C, 0x1B, 0xA5, 0x11, 0x05, 0xAD, 0xC6, 0x8D, 0x3E, 0x3A, 0x3E, 0x2C, - 0x4D, 0xBF, 0x9B, 0x2B, 0x63, 0x4C, 0x27, 0x0B, 0x5C, 0x12, 0x04, 0xB5, 0xF5, 0x11, 0x37, 0xD5, 0x47, 0xCF, 0xA2, 0xE3, 0x6D, 0xB4, 0xD2, 0x19, 0x6C, 0xA1, - 0x16, 0x89, 0x1C, 0xA6, 0x99, 0xCE, 0x80, 0xAB, 0x26, 0x2E, 0xB4, 0xEE, 0x56, 0x31, 0x65, 0xD4, 0x6E, 0xA3, 0x17, 0x1C, 0x2C, 0xF8, 0x46, 0x10, 0xD6, 0xD6, - 0x8A, 0x68, 0x08, 0xB9, 0x84, 0x1F, 0xED, 0x4D, 0x23, 0x11, 0x29, 0xDF, 0x80, 0x3E, 0x02, 0x23, 0x5C, 0xB2, 0xE7, 0xB6, 0x6A, 0x6B, 0x24, 0x6E, 0x0A, 0xA5, - 0x4B, 0x74, 0xBC, 0x37, 0xAD, 0x48, 0xE4, 0x7C, 0x0B, 0x7A, 0x59, 0x10, 0xD3, 0x36, 0x9C, 0x8F, 0x64, 0x32, 0x81, 0x84, 0x55, 0x5F, 0x37, 0x89, 0xE6, 0xA0, - 0x1F, 0x76, 0xAE, 0x5D, 0xD2, 0xF3, 0xDA, 0xE3, 0x88, 0x14, 0xBA, 0xCD, 0x07, 0x13, 0xE9, 0xEC, 0xCD, 0x27, 0xD4, 0x09, 0x1D, 0xBE, 0xB1, 0x23, 0x7D, 0xF4, - 0x93, 0x17, 0xD1, 0xB9, 0x79, 0x81, 0xF1, 0x13, 0x99, 0xD2, 0xF9, 0xEA, 0x6D, 0xEA, 0x9C, 0x17, 0xBE, 0xB1, 0xA6, 0x1B, 0x22, 0xB7, 0xA9, 0xBA, 0xDE, 0x41, - 0x3D, 0xFA, 0x8B, 0xED, 0x6E, 0xCE, 0xCC, 0x10, 0x09, 0x21, 0xC4, 0xDD, 0x0E, 0x0B, 0x14, 0xA3, 0xCF, 0xE0, 0x60, 0x3B, 0x24, 0xC7, 0x38, 0xB6, 0x5E, 0xD8, - 0xC6, 0xD7, 0x50, 0x6E, 0x19, 0xAB, 0x71, 0x6D, 0xB7, 0x80, 0x36, 0xFA, 0xE8, 0xE9, 0x6F, 0xCF, 0x6A, 0x07, 0x29, 0xB6, 0xEA, 0x5B, 0xC5, 0xC2, 0xE3, 0xB9, - 0x13, 0xEC, 0x2C, 0x33, 0xA9, 0xA5, 0xF6, 0x9C, 0xAA, 0x13, 0x5B, 0x0A, 0xBE, 0x04, 0x81, 0x74, 0x91, 0x4C, 0x97, 0xD8, 0xAC, 0xC6, 0xE3, 0x97, 0x8B, 0x60, - 0x40, 0xC4, 0xC7, 0xA9, 0x61, 0xD7, 0xCF, 0x2B, 0xA2, 0x21, 0xD5, 0x94, 0xF6, 0x02, 0x8E, 0x76, 0xA5, 0x2E, 0xD6, 0xED, 0xDE, 0x74, 0xC6, 0xB9, 0xDE, 0xB7, - 0xE2, 0x80, 0x90, 0xB9, 0x67, 0xD5, 0x9F, 0xB2, 0xE2, 0xED, 0xF4, 0x11, 0x68, 0xED, 0x0D, 0x1C, 0xD4, 0xCE, 0x32, 0x02, 0xC1, 0x17, 0x4E, 0x2F, 0x4F, 0x97, - 0xA1, 0xB7, 0x4D, 0x66, 0xB9, 0x5A, 0xBA, 0xEE, 0x7A, 0x9B, 0xB4, 0x72, 0xE1, 0x78, 0x4B, 0x6B, 0x73, 0x0C, 0x90, 0x53, 0x7E, 0x9E, 0x4C, 0x6C, 0x73, 0xF3, - 0xAC, 0x84, 0xB3, 0x0A, 0xDE, 0xBC, 0x62, 0xFB, 0x2F, 0x1C, 0xC5, 0x89, 0x59, 0x3F, 0x40, 0x10, 0x13, 0xB4, 0x78, 0x79, 0xA1, 0x5D, 0x5D, 0xFE, 0x74, 0xF5, - 0xF3, 0xBB, 0xDD, 0x44, 0x07, 0xE8, 0x73, 0x4F, 0x81, 0x01, 0xB9, 0xDD, 0x77, 0x4C, 0x00, 0x22, 0x06, 0x9B, 0xE8, 0x69, 0xC0, 0x14, 0xF5, 0xFC, 0xEA, 0xED, - 0xAE, 0xB4, 0x34, 0xD8, 0x9F, 0x9A, 0x06, 0x5F, 0x83, 0x9E, 0x3E, 0x3A, 0xE4, 0x9A, 0x38, 0x1B, 0xE8, 0x8A, 0x35, 0x44, 0x7D, 0x69, 0xAF, 0xF1, 0x68, 0x6F, - 0x03, 0xB9, 0x88, 0x94, 0x6F, 0x60, 0x18, 0x07, 0x56, 0xF1, 0x91, 0x12, 0xBD, 0x89, 0xF3, 0xB0, 0x96, 0xFA, 0xE8, 0xF2, 0x66, 0xE1, 0x05, 0x4B, 0xBF, 0x62, - 0x42, 0x55, 0x6B, 0xA4, 0xB7, 0x95, 0x42, 0x04, 0x29, 0x4C, 0x23, 0x3D, 0xAE, 0x10, 0x5C, 0xD0, 0x91, 0xD6, 0xFA, 0x86, 0x77, 0xAA, 0x15, 0x44, 0xFE, 0x25, - 0x15, 0x33, 0xDD, 0x20, 0xEF, 0x4C, 0x31, 0xEF, 0xBC, 0xB8, 0xD8, 0x4D, 0x28, 0x9B, 0xEE, 0x2D, 0xE1, 0x4C, 0xF7, 0x9A, 0x70, 0x34, 0xBE, 0xDE, 0x2E, 0xA4, - 0xB0, 0xE1, 0x20, 0x82, 0x37, 0x84, 0xB1, 0xF3, 0x26, 0x03, 0x08, 0xC9, 0x73, 0xFA, 0x37, 0xDB, 0xB8, 0x8E, 0x20, 0x23, 0xE9, 0x39, 0x87, 0xB1, 0xDF, 0x1C, - 0xDD, 0xA9, 0xD7, 0x1C, 0x96, 0x52, 0xBB, 0x8D, 0xD3, 0x20, 0x27, 0x26, 0xB1, 0x1D, 0xDC, 0x76, 0x5D, 0x57, 0x21, 0x52, 0x5B, 0xA6, 0x13, 0xED, 0x82, 0x9D, - 0x6D, 0xA3, 0x9B, 0xC1, 0x36, 0xBA, 0x91, 0x29, 0x4A, 0xAA, 0xE7, 0xF8, 0x0B, 0x65, 0x1A, 0x5C, 0x37, 0xFB, 0x92, 0x6B, 0x1E, 0x8B, 0xFA, 0x31, 0x0D, 0xDA, - 0xE8, 0xA3, 0x67, 0x6F, 0x77, 0x13, 0xD3, 0xB0, 0xB3, 0x8A, 0x31, 0x6D, 0xAB, 0x08, 0x46, 0x99, 0xDA, 0x77, 0x29, 0xB6, 0xDA, 0x40, 0x1B, 0x2B, 0x24, 0xFC, - 0xB7, 0x1D, 0x69, 0x63, 0x55, 0x5D, 0x1B, 0x77, 0x9C, 0x61, 0x56, 0x5F, 0x83, 0x7E, 0x7C, 0x63, 0xF5, 0x71, 0x3A, 0x37, 0x6A, 0xEB, 0x88, 0xB7, 0xD3, 0x47, - 0xEF, 0x8C, 0x95, 0xF6, 0xE2, 0xCD, 0xD3, 0x9D, 0xE8, 0x4A, 0x74, 0xBA, 0x1F, 0x7D, 0x45, 0x2C, 0xEF, 0x5B, 0x67, 0x0E, 0x71, 0xEB, 0x3B, 0x15, 0x36, 0xD2, - 0x47, 0xAF, 0x89, 0x1B, 0x68, 0x17, 0x9E, 0xCF, 0x5F, 0x91, 0xB7, 0x13, 0xAD, 0xD1, 0x9E, 0xF7, 0xA3, 0x32, 0xC6, 0xF4, 0xBE, 0xF5, 0x35, 0x9B, 0xDB, 0xBE, - 0xEF, 0xF9, 0xB5, 0x55, 0xC6, 0xDB, 0xE9, 0xA3, 0x97, 0x9D, 0x37, 0xF4, 0x68, 0x27, 0xEA, 0x12, 0xBD, 0xEE, 0x47, 0x63, 0x11, 0xCF, 0xFB, 0x56, 0xDA, 0xF5, - 0xC4, 0xB1, 0x17, 0xB5, 0x55, 0x46, 0x5B, 0xE9, 0xA3, 0xF7, 0x9D, 0x1F, 0xE1, 0xEF, 0x4E, 0xD4, 0xC5, 0x7A, 0xDC, 0x8F, 0xB2, 0x38, 0xB7, 0xFB, 0x56, 0x95, - 0x65, 0xAE, 0x6A, 0x2B, 0x0A, 0xDA, 0xE8, 0xA3, 0xE7, 0x17, 0xBF, 0x69, 0xCD, 0xE7, 0xDE, 0xCA, 0xC5, 0x87, 0x43, 0xB5, 0xCB, 0x9F, 0x5A, 0x3B, 0xD1, 0x18, - 0x76, 0xBD, 0x1F, 0x7D, 0x51, 0xA6, 0xF7, 0xAD, 0x2D, 0xBA, 0x07, 0x68, 0x6C, 0xD4, 0x0F, 0x87, 0xA2, 0x21, 0x3E, 0xFB, 0x02, 0x47, 0xDA, 0x33, 0x63, 0x37, - 0x01, 0x31, 0xEA, 0x77, 0x17, 0x45, 0x7B, 0xCC, 0xE4, 0xBE, 0xF5, 0xE4, 0x10, 0xAB, 0x82, 0x8A, 0x92, 0x25, 0x86, 0xF5, 0x11, 0xB7, 0xD3, 0xE0, 0x36, 0xD3, - 0x35, 0xD4, 0x1A, 0x97, 0xCF, 0xB5, 0x57, 0xE2, 0xB4, 0x02, 0x37, 0x1B, 0xCF, 0xD9, 0xE5, 0x0D, 0x6D, 0x93, 0xF4, 0x24, 0x07, 0xB7, 0x83, 0xA3, 0xA3, 0xED, - 0x86, 0xB7, 0x79, 0xD3, 0xA8, 0x47, 0x47, 0x5B, 0xEA, 0x44, 0xDE, 0x8C, 0xC1, 0xDF, 0x62, 0x58, 0xE6, 0x24, 0x7C, 0x53, 0x00, 0x1D, 0xCE, 0x93, 0xB0, 0x13, - 0x84, 0xB6, 0xE3, 0xE8, 0xA3, 0x17, 0x24, 0xD4, 0xAE, 0xF0, 0xB0, 0xE2, 0x2E, 0x00, 0x09, 0x8B, 0xD8, 0x02, 0x14, 0xFA, 0xC4, 0x98, 0xEB, 0xA3, 0x2B, 0x7C, - 0xBF, 0x23, 0xE0, 0xC2, 0xB3, 0x72, 0x64, 0x95, 0xF7, 0x0B, 0xD0, 0x0D, 0x42, 0xB8, 0xE3, 0x27, 0xF9, 0x3A, 0x56, 0x30, 0x7D, 0xB6, 0xFD, 0x6F, 0x74, 0x16, - 0x2C, 0x0C, 0x57, 0x80, 0xD1, 0xBD, 0x71, 0x2B, 0xBE, 0xD9, 0x69, 0xEC, 0x39, 0x16, 0x00, 0x3E, 0xB5, 0xAE, 0xF1, 0xD5, 0x34, 0x96, 0x76, 0x15, 0x6D, 0xDB, - 0xC1, 0x26, 0xE0, 0x3B, 0x02, 0x43, 0x89, 0xB0, 0x67, 0xBE, 0x40, 0xCF, 0x36, 0x58, 0xE1, 0xCB, 0x3C, 0x0A, 0xA4, 0x9D, 0xB3, 0xD3, 0xC8, 0x27, 0xD3, 0xC8, - 0x84, 0x54, 0x1B, 0xD0, 0x94, 0xFB, 0x8E, 0xDE, 0x91, 0xA9, 0x1D, 0x00, 0x8D, 0x1A, 0xE8, 0xE9, 0x80, 0xEE, 0xD5, 0x60, 0x1E, 0x52, 0x6D, 0x1F, 0x90, 0xDC, - 0x25, 0xDF, 0xC5, 0xA8, 0xDC, 0xDD, 0x55, 0x2B, 0x85, 0xA4, 0xF7, 0x62, 0x25, 0x31, 0x96, 0x59, 0xE1, 0xFD, 0x4E, 0x67, 0x36, 0xC4, 0x5D, 0x27, 0x9A, 0x60, - 0xED, 0xEC, 0x60, 0x36, 0x2C, 0x7B, 0xF4, 0xBC, 0x74, 0xCB, 0x10, 0x70, 0xBA, 0xF1, 0x8E, 0x21, 0x94, 0xD2, 0x08, 0xA8, 0x69, 0x6B, 0x6F, 0x8C, 0xE0, 0x73, - 0x5B, 0x7B, 0x8F, 0x0E, 0xBF, 0xC3, 0x8D, 0x43, 0x48, 0xBB, 0x61, 0x59, 0x7E, 0xEE, 0xE6, 0xA1, 0x61, 0x62, 0xF3, 0xD0, 0xB1, 0xD8, 0x3C, 0x24, 0x4D, 0xBD, - 0xDD, 0xF4, 0xFB, 0xFD, 0x2A, 0x9C, 0x57, 0xDC, 0x3F, 0x74, 0x27, 0x2C, 0xCD, 0x41, 0x98, 0x15, 0x59, 0x1A, 0x0A, 0x96, 0x86, 0x12, 0x4B, 0x27, 0x77, 0xB9, - 0x23, 0xEA, 0x4E, 0x38, 0xE2, 0x0B, 0x3B, 0x5F, 0x09, 0x4B, 0x95, 0x36, 0x79, 0x51, 0xDB, 0xBE, 0xAB, 0x3D, 0x5E, 0x14, 0x24, 0x1D, 0x0C, 0x8F, 0x0A, 0x63, - 0x21, 0x6D, 0xC2, 0x7C, 0xFE, 0xC5, 0x5D, 0xFA, 0xFC, 0x74, 0x0B, 0x9F, 0x9F, 0x66, 0x7C, 0x7E, 0x87, 0xCE, 0x2E, 0x08, 0xFF, 0xC6, 0x1C, 0x5E, 0xB0, 0x55, - 0xC3, 0xE9, 0x95, 0x6C, 0xED, 0xD6, 0x43, 0x22, 0x4B, 0x78, 0x71, 0x97, 0x1E, 0x92, 0x63, 0xB7, 0x1B, 0x19, 0x29, 0x8F, 0x39, 0xA3, 0xDD, 0xE4, 0x24, 0x5A, - 0x49, 0xC9, 0xEA, 0xE4, 0xBD, 0xE3, 0xCE, 0xA3, 0xC3, 0x21, 0x2F, 0x9B, 0xEE, 0x42, 0x3D, 0xD5, 0x37, 0x93, 0xE6, 0x82, 0xDC, 0x4D, 0x51, 0x86, 0x1B, 0xDF, - 0x16, 0x50, 0x07, 0xD7, 0x2E, 0xCC, 0x2E, 0x5E, 0xFF, 0xBD, 0x5E, 0x2D, 0x96, 0xEE, 0x69, 0x77, 0xF5, 0xD8, 0x66, 0xD6, 0x2A, 0x0B, 0x8C, 0xD3, 0x0E, 0x11, - 0x07, 0xB7, 0x55, 0x0F, 0x3E, 0x44, 0x9C, 0x2B, 0x06, 0xCD, 0x52, 0x50, 0x88, 0x9A, 0xE5, 0x8D, 0x89, 0x69, 0x20, 0xE4, 0x93, 0x18, 0x70, 0x2C, 0xE2, 0x9A, - 0xE6, 0x4D, 0x26, 0xF4, 0x5B, 0x3D, 0x8F, 0x30, 0x60, 0x04, 0x9F, 0xF1, 0x7A, 0xAF, 0x1F, 0x91, 0xA4, 0x1A, 0x11, 0xC7, 0x14, 0x46, 0xB4, 0x51, 0x13, 0xE3, - 0x86, 0x76, 0x67, 0x22, 0x38, 0x64, 0x22, 0x78, 0xFE, 0xEA, 0xBD, 0x4A, 0x06, 0xCC, 0xD7, 0x7A, 0x59, 0x11, 0x1C, 0x6E, 0xBE, 0x31, 0xBC, 0x5F, 0x59, 0x5A, - 0xBD, 0x58, 0x5A, 0x87, 0x93, 0x78, 0xCF, 0xD8, 0x36, 0x21, 0x4B, 0x21, 0x81, 0x23, 0xF6, 0x54, 0xA8, 0xF6, 0x56, 0xF6, 0x80, 0x4A, 0x76, 0x70, 0x54, 0xC7, - 0x0E, 0xAC, 0xC3, 0x2D, 0xCC, 0xE0, 0x28, 0xC7, 0x0C, 0xEE, 0x4A, 0x06, 0x43, 0x7D, 0xF4, 0x76, 0x13, 0x33, 0x18, 0x56, 0x34, 0x83, 0x43, 0x61, 0x06, 0xF1, - 0x86, 0xC2, 0x61, 0x55, 0x61, 0x49, 0x56, 0xF0, 0x68, 0x82, 0xEB, 0xE8, 0x8F, 0xAA, 0x79, 0xC2, 0xEE, 0x62, 0xEE, 0xCA, 0x76, 0xEB, 0xC7, 0xDB, 0xDF, 0x6C, - 0xD7, 0xF2, 0x56, 0xF5, 0x42, 0xAE, 0xDC, 0xD1, 0xD7, 0x1E, 0x6E, 0xEB, 0x8D, 0x5A, 0x71, 0xAA, 0xA5, 0x73, 0x83, 0x95, 0xBD, 0x1B, 0x78, 0xBE, 0x96, 0x7D, - 0xED, 0x41, 0x62, 0x47, 0x92, 0x80, 0xAE, 0x56, 0x04, 0x64, 0x9F, 0xC1, 0x7E, 0xF5, 0xA3, 0xB6, 0xC1, 0x8E, 0x74, 0x05, 0x32, 0xBE, 0x71, 0x5F, 0xDB, 0x60, - 0xE7, 0xBE, 0x02, 0x5B, 0xCE, 0x33, 0xEB, 0xF8, 0x16, 0x05, 0x6D, 0xB3, 0xD7, 0x28, 0x94, 0x3E, 0xBE, 0xCD, 0xA0, 0x36, 0x4F, 0x29, 0xD1, 0xB8, 0x8C, 0x79, - 0x2B, 0xD4, 0x58, 0xD5, 0xF6, 0xDC, 0x52, 0x9C, 0x92, 0x01, 0xF0, 0xE6, 0x37, 0xF4, 0xF1, 0xF6, 0x80, 0x54, 0xDB, 0xA5, 0x96, 0x26, 0xAC, 0x46, 0x65, 0xF8, - 0xE1, 0x54, 0x0A, 0x66, 0x51, 0xE7, 0x35, 0x83, 0x59, 0x5C, 0xE7, 0x83, 0x31, 0xED, 0x7D, 0xF0, 0xF2, 0x4F, 0x05, 0x4B, 0xEB, 0xCD, 0x59, 0x3A, 0xBC, 0x2B, - 0x96, 0xB6, 0x48, 0x55, 0x91, 0x75, 0x85, 0x5E, 0x68, 0x38, 0x1B, 0x1B, 0x17, 0x6B, 0x0D, 0xB6, 0xC5, 0x62, 0xAE, 0x76, 0x05, 0xAC, 0xEE, 0xD4, 0xC0, 0x04, - 0x01, 0xD5, 0x94, 0x31, 0xCC, 0x2A, 0xE3, 0xE4, 0x6B, 0xB3, 0x2F, 0xC6, 0x51, 0x55, 0xF3, 0x52, 0x70, 0x74, 0xFC, 0x35, 0x99, 0x97, 0xB7, 0x0C, 0xF1, 0xEA, - 0xC6, 0xC1, 0x8B, 0x35, 0xC7, 0xE0, 0x45, 0x8F, 0x76, 0x6F, 0x60, 0x11, 0x05, 0x1B, 0xEB, 0xE3, 0xF0, 0x4E, 0xDF, 0xD7, 0x74, 0x17, 0x11, 0x8C, 0xB1, 0xB4, - 0x85, 0x89, 0x0D, 0x86, 0x3B, 0x34, 0x31, 0x69, 0x19, 0x89, 0xE7, 0x41, 0x5E, 0xC0, 0xE8, 0x7C, 0x6D, 0x20, 0x2E, 0x68, 0xEA, 0xAC, 0x24, 0xA9, 0xB3, 0xF2, - 0xD9, 0x01, 0x14, 0x85, 0x59, 0x04, 0x39, 0x74, 0x9E, 0xB1, 0xCF, 0xBE, 0xA9, 0x3B, 0x8C, 0x5F, 0xD3, 0x46, 0xD7, 0xB9, 0xE2, 0x17, 0x82, 0x46, 0x85, 0x66, - 0xFA, 0x45, 0xA1, 0xA5, 0xAF, 0x44, 0x3B, 0x33, 0xF8, 0x9E, 0xFC, 0x6B, 0xC2, 0x17, 0xE5, 0xB4, 0x99, 0x4F, 0x26, 0xE7, 0xFA, 0x77, 0x11, 0x4E, 0x2E, 0x2D, - 0x04, 0xD1, 0x35, 0x08, 0xC9, 0xAE, 0xE3, 0x19, 0x58, 0xAC, 0x1A, 0x8B, 0x10, 0x28, 0xED, 0xFE, 0xB1, 0xC0, 0x49, 0x5E, 0x03, 0x37, 0x70, 0x1B, 0xD5, 0xD6, - 0x71, 0xE9, 0xAB, 0x45, 0xF9, 0x4A, 0x3B, 0x1E, 0x46, 0x8B, 0x78, 0xFF, 0xF3, 0xDF, 0x65, 0x53, 0x33, 0xF8, 0xF1, 0xBF, 0x58, 0x00, 0x60, 0x46, 0xBE, 0x79, - 0xAE, 0x03, 0xA5, 0xBE, 0x17, 0x40, 0x29, 0x6A, 0x4F, 0xED, 0x1C, 0x55, 0xE5, 0x49, 0xFB, 0x40, 0x25, 0xEE, 0x14, 0xB0, 0x62, 0x6C, 0x72, 0x16, 0x98, 0xBE, - 0xBD, 0x80, 0x52, 0xCD, 0xF2, 0xCC, 0xE5, 0x9C, 0xB8, 0x61, 0xD7, 0xB0, 0xAC, 0xCB, 0x6B, 0x38, 0x78, 0x8D, 0x33, 0xCC, 0x20, 0xF9, 0x66, 0xE3, 0xF9, 0xCF, - 0x6F, 0x2E, 0xD8, 0x0B, 0xF7, 0x5E, 0x83, 0xBC, 0x88, 0xD5, 0x68, 0x6B, 0x93, 0xA5, 0xCB, 0xAA, 0xF7, 0x26, 0x41, 0x58, 0xF6, 0x11, 0xC6, 0x6B, 0xC3, 0xD7, - 0xC6, 0x46, 0x40, 0x5E, 0x7A, 0x41, 0xA8, 0x9D, 0x6B, 0x11, 0x46, 0xC7, 0x33, 0xE9, 0x4B, 0x12, 0xBA, 0x8C, 0x2F, 0x0E, 0xC9, 0x18, 0xFF, 0xD5, 0x77, 0x00, - 0x34, 0x6A, 0xF5, 0x50, 0x6B, 0x9C, 0x9E, 0xF4, 0x1B, 0x68, 0x7F, 0x51, 0x17, 0x13, 0xFC, 0xAC, 0x22, 0xC0, 0x35, 0x97, 0xBE, 0xD3, 0xD6, 0xCC, 0x71, 0x8B, - 0xBD, 0x24, 0x91, 0x5E, 0xC6, 0x6B, 0xE2, 0xED, 0xB9, 0xDD, 0x70, 0x46, 0xDC, 0x66, 0x4C, 0x19, 0x38, 0xC3, 0xC2, 0x73, 0x83, 0xC4, 0x17, 0x22, 0xED, 0x49, - 0x7C, 0xBD, 0x0B, 0x05, 0x7D, 0xB8, 0x0C, 0xB4, 0xFB, 0xE7, 0xE7, 0x1A, 0x16, 0xB8, 0x89, 0x97, 0x2F, 0x9A, 0xE3, 0x34, 0x5C, 0x5B, 0x4B, 0x5D, 0xF8, 0x05, - 0x42, 0x83, 0xF4, 0x9A, 0xDF, 0x5B, 0x8D, 0x38, 0xA9, 0xF7, 0xCC, 0x46, 0x0D, 0x30, 0x8A, 0x34, 0x5B, 0x49, 0x02, 0x9B, 0x96, 0x11, 0x1A, 0xAD, 0xE4, 0x0B, - 0x1F, 0xA1, 0x57, 0xA0, 0xA4, 0xAD, 0xD1, 0x5B, 0xF2, 0xDB, 0x27, 0x6F, 0x5B, 0x5D, 0x90, 0x21, 0xF0, 0x1B, 0xB5, 0x26, 0xBE, 0x9F, 0xFE, 0xF4, 0x25, 0xB4, - 0xEE, 0xF4, 0xDB, 0x1A, 0xDE, 0x49, 0xB6, 0x95, 0x88, 0xBC, 0x27, 0xAE, 0x09, 0xA1, 0x15, 0xA3, 0x55, 0xA0, 0x64, 0xE8, 0x6E, 0x13, 0x2A, 0x82, 0xD8, 0xF3, - 0x8E, 0x4C, 0x41, 0x62, 0xD3, 0x36, 0x1F, 0x40, 0xB7, 0xE9, 0xE8, 0xB9, 0xCD, 0x82, 0xA2, 0xA4, 0xB5, 0x83, 0x03, 0x70, 0x69, 0x08, 0x4A, 0x04, 0xAC, 0x62, - 0xDA, 0x6C, 0xF0, 0x05, 0x4C, 0xB0, 0xA8, 0x46, 0xEF, 0xA6, 0xF1, 0x10, 0x10, 0x74, 0x43, 0xEF, 0x2A, 0xF4, 0x6D, 0x77, 0x0A, 0x43, 0x8F, 0x56, 0x8C, 0x8D, - 0xDE, 0x46, 0x94, 0xA9, 0xFB, 0xF4, 0x3A, 0xED, 0x24, 0x7D, 0xA3, 0xC9, 0xAF, 0x3F, 0x6C, 0xB4, 0x1A, 0x9C, 0x78, 0x7A, 0x0E, 0xE6, 0xD6, 0x64, 0x07, 0x0F, - 0x28, 0x8D, 0x2D, 0xED, 0xEC, 0x8C, 0x77, 0xC3, 0xA0, 0xF0, 0x22, 0x00, 0xD1, 0x3F, 0xA9, 0x5B, 0x91, 0x29, 0x7E, 0xFA, 0xFE, 0x2F, 0x61, 0xB3, 0xB7, 0x07, - 0x40, 0xF5, 0x13, 0x9C, 0x41, 0xF8, 0xFE, 0x2F, 0xF8, 0xFF, 0xED, 0x03, 0x3A, 0x6D, 0xF0, 0xFD, 0x5F, 0xF8, 0xE7, 0xF6, 0x01, 0xF4, 0x04, 0xC7, 0xB4, 0xBF, - 0xDB, 0x4F, 0x54, 0x0E, 0x59, 0xE9, 0x4D, 0x73, 0xA5, 0x17, 0x89, 0xAD, 0x36, 0x4D, 0xD3, 0x02, 0xA2, 0x3E, 0xC5, 0xFE, 0xDB, 0x34, 0x3D, 0x0B, 0xD4, 0x13, - 0x82, 0x25, 0x0B, 0xA5, 0x3B, 0xA0, 0x12, 0x21, 0xA8, 0xE8, 0x0D, 0xA8, 0xF6, 0x84, 0x42, 0x6A, 0xDC, 0x55, 0x62, 0x03, 0x11, 0x90, 0x0B, 0xFC, 0x2C, 0xF8, - 0x2B, 0x37, 0x6C, 0x86, 0x09, 0xA7, 0xC8, 0x91, 0xF8, 0x68, 0x94, 0x60, 0x01, 0x7F, 0xD0, 0x0E, 0xE0, 0x1A, 0x5C, 0x69, 0x91, 0xB1, 0xDD, 0x8B, 0xEC, 0x30, - 0xA6, 0x94, 0xDD, 0xCC, 0xB1, 0xC3, 0x0F, 0xA6, 0xF3, 0xB9, 0x89, 0xEF, 0x64, 0x4C, 0x87, 0x8A, 0x8C, 0x88, 0x10, 0xE8, 0x09, 0xFE, 0x0F, 0xE4, 0x82, 0x7F, - 0x72, 0xF5, 0x03, 0x58, 0x59, 0x09, 0xDF, 0xA4, 0x53, 0x00, 0x1F, 0x6F, 0xDA, 0x1A, 0x3B, 0x58, 0x83, 0x67, 0xB8, 0x16, 0x9E, 0xE3, 0x9F, 0xB5, 0xD0, 0x1E, - 0x5E, 0xE0, 0x47, 0x70, 0x8D, 0xD6, 0xAC, 0x78, 0x89, 0x1D, 0x20, 0x14, 0xAD, 0x31, 0x28, 0x14, 0x3B, 0x82, 0x6B, 0xF8, 0xCE, 0x0F, 0xB0, 0xDD, 0xB6, 0x36, - 0xB6, 0x5D, 0x97, 0x1E, 0x94, 0x50, 0x1F, 0xA7, 0xFA, 0x27, 0xC1, 0x0D, 0x70, 0xC0, 0x49, 0xBB, 0x7D, 0x10, 0xAC, 0xA3, 0xB3, 0xF5, 0xED, 0x03, 0x82, 0xF7, - 0x28, 0x91, 0x70, 0xBC, 0xE6, 0xC7, 0x70, 0x1D, 0xE8, 0xC3, 0x3B, 0x82, 0x60, 0x7A, 0x61, 0x1D, 0x5F, 0x00, 0x88, 0x10, 0xEF, 0x73, 0xE2, 0xE1, 0x6C, 0x1D, - 0x9D, 0x61, 0x6B, 0xDA, 0x96, 0xB3, 0x01, 0xA7, 0xEB, 0xF8, 0x14, 0xEE, 0xB2, 0x0F, 0xBA, 0x03, 0x11, 0x8C, 0xA7, 0xDB, 0x07, 0x9C, 0x27, 0xB8, 0xC4, 0x8F, - 0xD2, 0xA2, 0xC6, 0x98, 0x10, 0xF2, 0x28, 0xF2, 0x8C, 0x25, 0x69, 0x29, 0x7F, 0x80, 0x7F, 0x5C, 0x3A, 0x04, 0x0F, 0x9F, 0xAD, 0x5F, 0x59, 0xCD, 0x06, 0x5F, - 0x90, 0x6D, 0x60, 0x0C, 0x93, 0xDB, 0x74, 0x3D, 0xD7, 0x74, 0x6C, 0x13, 0x1D, 0xA5, 0xD9, 0xD2, 0xCE, 0x47, 0x3C, 0x8E, 0xA1, 0x41, 0x03, 0xB8, 0x6C, 0xA4, - 0xB9, 0xA8, 0xC5, 0x92, 0x62, 0xA3, 0xD5, 0xA5, 0x76, 0xC8, 0x6D, 0x0D, 0x51, 0x70, 0x17, 0xAC, 0x86, 0x03, 0x81, 0x15, 0x38, 0x32, 0xDE, 0x52, 0x88, 0x84, - 0x42, 0x4B, 0x58, 0x28, 0x1A, 0x39, 0xD4, 0xF6, 0x52, 0x51, 0xB6, 0xC0, 0xAB, 0x85, 0x03, 0xDF, 0x4F, 0x3B, 0x30, 0xA8, 0xCA, 0x0F, 0x9B, 0x8D, 0x4B, 0x7C, - 0x10, 0xF8, 0xF7, 0xC6, 0x43, 0x04, 0x7A, 0xD8, 0xF8, 0xD7, 0xA9, 0xD6, 0x78, 0x28, 0x7B, 0xF2, 0x6D, 0xDA, 0xE5, 0x98, 0xC6, 0xA6, 0x15, 0x35, 0x36, 0x95, - 0x34, 0x36, 0xBD, 0x5B, 0x8D, 0xC9, 0x0B, 0xC1, 0xDB, 0x68, 0x4D, 0x5E, 0x79, 0x2D, 0xD0, 0x5C, 0x69, 0x7B, 0xAE, 0x34, 0xAE, 0xAD, 0xA9, 0x4A, 0x5B, 0x9B, - 0xA8, 0x89, 0xA5, 0x38, 0xF0, 0x1E, 0xE2, 0xBF, 0xFC, 0xE5, 0xCD, 0x6B, 0x0C, 0x95, 0x6A, 0x95, 0x45, 0x1A, 0x4B, 0x97, 0x23, 0x0A, 0x0C, 0x98, 0x3B, 0x13, - 0x81, 0x3B, 0x91, 0x43, 0x1F, 0x36, 0xB4, 0x26, 0x45, 0x89, 0x19, 0xB4, 0xC4, 0x10, 0x78, 0xE0, 0xAD, 0xE6, 0xBB, 0x18, 0x6C, 0x85, 0xF3, 0xC6, 0xAD, 0x0A, - 0x6C, 0x01, 0x1B, 0x54, 0x52, 0x22, 0xC3, 0x9C, 0x71, 0x18, 0x29, 0x27, 0xEC, 0xDC, 0x45, 0xA8, 0xBF, 0x06, 0x55, 0x83, 0x9A, 0x88, 0xE9, 0x71, 0x6C, 0x0B, - 0x4A, 0xA5, 0xC3, 0x23, 0x7F, 0x25, 0x01, 0xF1, 0x39, 0x6C, 0x85, 0x81, 0x8B, 0x4C, 0x50, 0x09, 0x8D, 0x98, 0xBA, 0xCC, 0xC7, 0xB3, 0xAE, 0x83, 0x67, 0xAD, - 0xC0, 0xC3, 0x33, 0x4F, 0x25, 0x34, 0x7C, 0xA2, 0x2B, 0x17, 0x4B, 0x35, 0x62, 0xF8, 0xE4, 0x92, 0x8A, 0x27, 0x9E, 0xE9, 0xAA, 0xF1, 0xC4, 0x27, 0x45, 0xF2, - 0xF1, 0x54, 0x94, 0x0D, 0x9F, 0x89, 0x50, 0xD8, 0x73, 0xBA, 0x1A, 0xE9, 0x89, 0xFF, 0x36, 0xAF, 0x3F, 0x26, 0x06, 0x44, 0x8B, 0xF8, 0xCF, 0x5E, 0xBC, 0x64, - 0xFA, 0x5E, 0x54, 0x8B, 0xC4, 0x51, 0x66, 0x03, 0xE2, 0x74, 0x8D, 0x10, 0xE2, 0x13, 0x8C, 0xE3, 0x49, 0xD0, 0xC5, 0x0A, 0x37, 0x12, 0x63, 0xE6, 0x56, 0xD7, - 0x05, 0x02, 0x28, 0xC2, 0xD6, 0x69, 0x2F, 0x6D, 0x9E, 0x19, 0x5C, 0xEC, 0x72, 0x1E, 0x3A, 0x76, 0x37, 0x07, 0x23, 0xCF, 0x30, 0xC9, 0x16, 0x78, 0x31, 0x0F, - 0x1B, 0x1D, 0xC5, 0x48, 0xB8, 0x06, 0x47, 0x47, 0xD9, 0x3C, 0xC3, 0x3B, 0xE0, 0x9F, 0x7E, 0x42, 0x0C, 0x38, 0x1F, 0x15, 0x0F, 0xCD, 0x4C, 0x28, 0x04, 0xB5, - 0x86, 0x58, 0xB2, 0x6B, 0x9C, 0x66, 0x2A, 0x6E, 0x68, 0xC1, 0x17, 0xE1, 0xB4, 0x27, 0x8C, 0xC6, 0xC4, 0x07, 0x0D, 0xC6, 0x30, 0xF8, 0x8E, 0xBE, 0x5B, 0xC4, - 0x90, 0xD1, 0x07, 0xAB, 0x23, 0x4C, 0xEC, 0x1A, 0x0E, 0x5C, 0x53, 0x97, 0xD8, 0xDA, 0x4E, 0xC7, 0x73, 0x89, 0xBA, 0xD7, 0x44, 0xFD, 0xCE, 0x3B, 0xE2, 0x67, - 0xFC, 0x89, 0xEF, 0xB8, 0x99, 0x4F, 0xC2, 0xA5, 0xEF, 0xF2, 0x7A, 0x3E, 0x5B, 0xDF, 0x28, 0x87, 0x92, 0x3B, 0xB4, 0xCD, 0x83, 0x03, 0xED, 0x69, 0x18, 0x1A, - 0xA0, 0x00, 0x5C, 0xA7, 0x9C, 0xA1, 0x7C, 0x34, 0x83, 0x4F, 0x4A, 0x78, 0x3E, 0x1A, 0x25, 0x7B, 0xA8, 0x98, 0x30, 0xBF, 0xC5, 0xCF, 0x3C, 0x09, 0x77, 0xA6, - 0xA8, 0xBA, 0xFF, 0x5E, 0x12, 0x7F, 0x7D, 0x45, 0x05, 0xE6, 0xF9, 0x4F, 0x1D, 0xA7, 0xD9, 0xE8, 0xC6, 0xCB, 0xCE, 0x0D, 0x36, 0x06, 0xEF, 0x02, 0xAA, 0x4B, - 0xE8, 0x03, 0x74, 0x1C, 0xDB, 0x3C, 0xE3, 0x26, 0xD2, 0x3B, 0x8C, 0xBB, 0xCE, 0xB9, 0x32, 0xD2, 0x83, 0x7E, 0x80, 0xF0, 0xDC, 0xCF, 0x64, 0xBD, 0x5C, 0x80, - 0xF8, 0xE3, 0x61, 0x7C, 0x6A, 0x62, 0x81, 0x4B, 0x87, 0x74, 0x01, 0xF2, 0x82, 0x0F, 0xE4, 0xFA, 0x87, 0x0A, 0xA0, 0x58, 0x05, 0xD4, 0x3A, 0xD1, 0x13, 0xB3, - 0x5F, 0xC1, 0xB8, 0xBD, 0xA7, 0x3E, 0x53, 0x4C, 0x81, 0x70, 0x02, 0xB9, 0xF0, 0x44, 0xF2, 0x4A, 0xF5, 0x90, 0x9A, 0x9E, 0xB8, 0x6D, 0xDD, 0x8B, 0x23, 0xC3, - 0x72, 0x61, 0x19, 0x21, 0x49, 0x06, 0x87, 0xC8, 0x16, 0xC4, 0xCD, 0xB9, 0x17, 0x92, 0x54, 0xC4, 0xB0, 0x5D, 0x3B, 0xB4, 0x0D, 0xE7, 0x7D, 0x6C, 0x8D, 0x5F, - 0xD4, 0xFD, 0x15, 0x3E, 0x5E, 0xC3, 0xFF, 0x33, 0x73, 0x10, 0xD5, 0xC6, 0xCD, 0x19, 0x0B, 0x89, 0xE2, 0x41, 0x6C, 0x25, 0xB2, 0x1C, 0x12, 0x61, 0x81, 0xDF, - 0x17, 0x3D, 0xDD, 0xBF, 0x4F, 0x8F, 0xEE, 0x45, 0x4A, 0x13, 0xD1, 0xE3, 0x5C, 0x8B, 0x6F, 0xA4, 0x14, 0x9C, 0xC5, 0x9D, 0xC2, 0x21, 0x90, 0x4B, 0x18, 0x98, - 0x6F, 0x45, 0xEA, 0x5D, 0x40, 0xB5, 0x89, 0xB6, 0xF0, 0xFF, 0x51, 0xFF, 0x2B, 0x8A, 0xFA, 0x5F, 0x2E, 0xC4, 0x17, 0xD8, 0x76, 0xCA, 0x03, 0x58, 0x3B, 0xF5, - 0xB4, 0xE0, 0xC3, 0x06, 0x54, 0x3B, 0xCA, 0x79, 0x3F, 0x1E, 0xBA, 0x63, 0xFB, 0x9A, 0xD9, 0x16, 0x23, 0x3A, 0xB6, 0x2C, 0x94, 0x11, 0x4E, 0xDF, 0xE3, 0x04, - 0x37, 0xCE, 0x76, 0x37, 0x1B, 0x6C, 0x6D, 0x81, 0xC6, 0xE3, 0xDB, 0xB8, 0x24, 0x99, 0x79, 0xAB, 0xA2, 0x96, 0x3E, 0x44, 0x9D, 0x6B, 0x92, 0x6A, 0x1C, 0xB5, - 0xE6, 0xDF, 0x6A, 0x2F, 0xED, 0x5A, 0x7C, 0xD3, 0x9D, 0x27, 0x03, 0x00, 0x88, 0xBE, 0xF2, 0x7E, 0xAE, 0x85, 0x3E, 0xF5, 0x1A, 0x09, 0x2D, 0x71, 0xCB, 0xB0, - 0x0A, 0xB2, 0x0A, 0x11, 0xD3, 0x32, 0x2F, 0x89, 0x99, 0x85, 0xD2, 0x1A, 0x41, 0x56, 0xBE, 0x0C, 0x2D, 0x92, 0xA7, 0xE7, 0x9A, 0xBB, 0x74, 0x1C, 0xB0, 0x41, - 0x64, 0x01, 0x6C, 0x50, 0xBE, 0xAB, 0x0C, 0xD1, 0xFF, 0xB9, 0xF1, 0x2C, 0xA2, 0x3C, 0x21, 0x81, 0x07, 0x0F, 0x92, 0xD8, 0x70, 0x91, 0x81, 0x95, 0xF1, 0x51, - 0x6F, 0x0C, 0xFE, 0xC2, 0x73, 0x27, 0xF6, 0x34, 0xCE, 0xB3, 0x9C, 0x24, 0x48, 0xD6, 0xF7, 0x13, 0x82, 0x97, 0x6A, 0x1C, 0x20, 0xC4, 0xB6, 0xA8, 0x80, 0xE8, - 0x9B, 0xFA, 0x32, 0xB3, 0xB1, 0x4F, 0xA8, 0xD5, 0x37, 0x09, 0x7F, 0x87, 0x57, 0x0B, 0xE4, 0x8F, 0xC6, 0x1C, 0x5F, 0x10, 0xF5, 0x4E, 0xD4, 0x95, 0x8C, 0x71, - 0x9A, 0xC0, 0x88, 0x8C, 0xA5, 0xE8, 0xC6, 0x1F, 0xC5, 0x87, 0x6F, 0xB3, 0xE1, 0x6F, 0xD4, 0x91, 0xBF, 0x60, 0x48, 0x3B, 0x07, 0x34, 0xF8, 0xC6, 0x1D, 0x29, - 0xB5, 0x67, 0x6B, 0x03, 0x0A, 0x98, 0x83, 0x84, 0x76, 0x90, 0x45, 0x52, 0x48, 0xB9, 0x78, 0x9D, 0xA9, 0x42, 0x20, 0x14, 0xDD, 0x6A, 0x8C, 0xA2, 0xA0, 0xBD, - 0xC2, 0x61, 0x2E, 0x2A, 0x2D, 0xB5, 0x97, 0x31, 0x83, 0x6E, 0xA4, 0x75, 0xFA, 0x02, 0x27, 0x80, 0xBE, 0xC0, 0xB5, 0xFB, 0x08, 0x73, 0x74, 0x21, 0x59, 0x54, - 0x0A, 0x67, 0x8B, 0x26, 0x95, 0x65, 0xED, 0xB3, 0xD4, 0x17, 0xE7, 0xBD, 0xD8, 0xBC, 0xEE, 0x28, 0x13, 0xF4, 0x35, 0xF9, 0x93, 0x65, 0x72, 0xBC, 0xDE, 0x32, - 0x09, 0x14, 0xE0, 0x64, 0x8B, 0xAD, 0x69, 0xA4, 0xCB, 0xF1, 0xDC, 0x0E, 0x15, 0x08, 0x1B, 0xFD, 0x46, 0x9D, 0x7C, 0x22, 0xFB, 0x1E, 0x8B, 0x5F, 0xB4, 0xD4, - 0x06, 0x44, 0x89, 0x49, 0x72, 0xFA, 0xDA, 0x7C, 0xCF, 0x79, 0x72, 0x6D, 0xF8, 0x38, 0xF5, 0x8D, 0x0A, 0x4E, 0x2D, 0xC9, 0x30, 0x14, 0x6C, 0x2D, 0x91, 0xA2, - 0x48, 0xAE, 0x26, 0x8A, 0x15, 0xBC, 0x64, 0x65, 0x2E, 0x2F, 0x61, 0x7D, 0xF2, 0x09, 0xB4, 0x0B, 0x70, 0xAA, 0x41, 0xFB, 0xFE, 0x2F, 0x8A, 0xE2, 0x56, 0x9B, - 0x80, 0xEF, 0x07, 0x33, 0x62, 0xD1, 0x85, 0x82, 0x10, 0xBF, 0xF2, 0x87, 0xCB, 0x30, 0x89, 0xD5, 0xC3, 0xDB, 0x4F, 0x91, 0x85, 0x44, 0xA9, 0xA3, 0x74, 0xF0, - 0x40, 0x17, 0x99, 0x8B, 0xC7, 0x0D, 0xAC, 0xDC, 0x56, 0x4C, 0x15, 0xE1, 0x8F, 0xC5, 0x05, 0xA7, 0xCB, 0x3E, 0x4D, 0xFE, 0x13, 0x54, 0x23, 0x29, 0x33, 0x6D, - 0xF1, 0x61, 0x0F, 0x68, 0xC0, 0x12, 0x01, 0x8C, 0xE9, 0x08, 0x07, 0x37, 0x4C, 0x4C, 0x09, 0x09, 0x33, 0x66, 0x38, 0x2F, 0xE5, 0x2B, 0xB0, 0x3C, 0xAB, 0x47, - 0xB2, 0xF8, 0x23, 0x80, 0xC1, 0x4A, 0xEB, 0x5E, 0x24, 0x86, 0x2C, 0x0E, 0xEC, 0x40, 0x42, 0x90, 0x10, 0x51, 0x9E, 0x98, 0x92, 0x3B, 0x8B, 0x1B, 0x71, 0xFC, - 0xC8, 0x1D, 0x6B, 0x69, 0x72, 0xFE, 0xA3, 0xC9, 0x8F, 0xF6, 0xFB, 0x3B, 0x35, 0x99, 0x7F, 0xF1, 0x79, 0x11, 0x29, 0x0E, 0xB5, 0xEA, 0x90, 0x93, 0x19, 0xF2, - 0x95, 0x90, 0x72, 0x87, 0xC5, 0xAF, 0xF8, 0x41, 0x78, 0xA3, 0xF8, 0xA0, 0xC4, 0xCC, 0x0C, 0xFA, 0xE4, 0x0A, 0x2D, 0x62, 0x30, 0x71, 0x96, 0x1C, 0x83, 0x49, - 0xE2, 0x51, 0x56, 0x67, 0xB9, 0xE2, 0x62, 0xD6, 0xC5, 0xDC, 0xF5, 0xDA, 0x26, 0xAB, 0xC2, 0xE9, 0x50, 0xFA, 0x74, 0x00, 0x95, 0x57, 0xDC, 0xE0, 0x22, 0x7A, - 0x1A, 0xA4, 0xB4, 0x65, 0xFC, 0xE4, 0x88, 0x84, 0x83, 0x3E, 0x16, 0x52, 0x6D, 0xB5, 0x82, 0x82, 0x26, 0x9A, 0x22, 0xD6, 0xF2, 0xB6, 0x89, 0xCD, 0xDC, 0x52, - 0x7B, 0xEA, 0xB9, 0xE5, 0xCD, 0xE5, 0xA7, 0x48, 0xE4, 0xDE, 0x8D, 0xEB, 0x0A, 0x8D, 0xE3, 0x47, 0x5F, 0xA4, 0xA6, 0x22, 0x1F, 0x15, 0x35, 0x8C, 0xDE, 0x3E, - 0xD0, 0x90, 0x34, 0x14, 0x84, 0xDE, 0x82, 0xED, 0x42, 0x4F, 0x05, 0x92, 0x15, 0x9D, 0x7D, 0xEC, 0xE2, 0xFD, 0x26, 0x2F, 0x5A, 0x64, 0xE9, 0x24, 0x97, 0x18, - 0xE4, 0xDD, 0xEC, 0x8D, 0x64, 0xC5, 0x49, 0xA7, 0x2F, 0x95, 0x3D, 0xA0, 0xAE, 0xBB, 0x81, 0x6F, 0xB2, 0x70, 0x1E, 0x3D, 0x28, 0x82, 0xD1, 0x06, 0x0F, 0x3F, - 0xB1, 0x3E, 0x31, 0xFD, 0x26, 0xAC, 0xA2, 0x55, 0x4A, 0x8B, 0xB7, 0x48, 0x93, 0x12, 0x4F, 0xF1, 0x30, 0x0F, 0x0D, 0x30, 0x8E, 0xF3, 0x37, 0x01, 0xDC, 0xD3, - 0x64, 0x8B, 0xC9, 0x09, 0xAB, 0xB1, 0x98, 0x78, 0x1C, 0x4B, 0x12, 0x2F, 0xE5, 0x22, 0xF6, 0x94, 0xD1, 0x93, 0x8F, 0xE6, 0x18, 0xD2, 0xCF, 0x73, 0x70, 0x1F, - 0xF0, 0xD7, 0x55, 0xB3, 0x75, 0x5B, 0xC4, 0x0E, 0x13, 0x57, 0x6C, 0x3B, 0x55, 0x89, 0xA0, 0x81, 0x5E, 0x8D, 0x2D, 0x21, 0x1F, 0x35, 0x3A, 0xD9, 0xE4, 0x2F, - 0x5D, 0x31, 0x68, 0xC8, 0x13, 0xEC, 0x79, 0x56, 0xB4, 0xAC, 0x6E, 0x4C, 0x20, 0x88, 0x43, 0x78, 0x86, 0xD8, 0x54, 0x69, 0x28, 0xD9, 0x85, 0x00, 0x88, 0x68, - 0x8F, 0xFC, 0x20, 0x87, 0x72, 0x7C, 0xB0, 0xC8, 0x34, 0xDC, 0x6B, 0x23, 0x90, 0xED, 0xDD, 0x04, 0x5C, 0x21, 0xE1, 0x26, 0xDF, 0xD4, 0x19, 0x80, 0xCE, 0x6D, - 0x97, 0x9D, 0x75, 0xE9, 0x4E, 0x0C, 0x2C, 0xED, 0x51, 0x7D, 0xF4, 0x24, 0x71, 0x9B, 0x7D, 0xF8, 0x55, 0xDC, 0x67, 0x67, 0x0C, 0x20, 0xEA, 0x05, 0x3F, 0xB5, - 0xDA, 0x35, 0x16, 0x0B, 0xE2, 0x5A, 0x17, 0x33, 0xDB, 0xB1, 0x9A, 0xAC, 0x69, 0xF4, 0xEC, 0x89, 0xCF, 0xBE, 0xD2, 0x4E, 0x9F, 0x73, 0xE0, 0x58, 0xC1, 0x11, - 0x2F, 0xD8, 0xB5, 0x66, 0x63, 0x60, 0x89, 0xC7, 0x54, 0x38, 0x58, 0xD7, 0xF2, 0x8D, 0xD5, 0x2B, 0x7C, 0x0C, 0x8E, 0x6A, 0xB2, 0xDD, 0x6B, 0xF7, 0x38, 0x40, - 0x08, 0x95, 0x8E, 0x90, 0x16, 0xE2, 0xC5, 0xC7, 0x85, 0x7E, 0x7D, 0xF7, 0x3A, 0xC6, 0x1B, 0x7A, 0xCF, 0xD9, 0xA5, 0x66, 0x83, 0x3E, 0x47, 0x77, 0xF0, 0xC7, - 0x02, 0x57, 0x5F, 0x45, 0x8C, 0x97, 0xC4, 0x88, 0x8F, 0xC8, 0xA1, 0xA8, 0x18, 0xF8, 0x0F, 0x32, 0x52, 0xB8, 0xEC, 0x42, 0x90, 0x46, 0x4B, 0x6D, 0xAA, 0x9A, - 0x8A, 0x07, 0xE8, 0xB0, 0x39, 0x72, 0xF2, 0x23, 0x8C, 0xF8, 0xFE, 0x49, 0x0C, 0x1F, 0xF4, 0xF1, 0x50, 0x6B, 0xEA, 0x3D, 0xFD, 0x61, 0x93, 0x5E, 0x7F, 0x03, - 0xEC, 0xCC, 0x9A, 0xAD, 0x87, 0xFD, 0x56, 0x0B, 0x3F, 0xAC, 0x6E, 0x92, 0x66, 0x67, 0x20, 0x40, 0xE0, 0x0F, 0x85, 0x61, 0x9D, 0xE4, 0xDF, 0x7F, 0xE9, 0x2D, - 0xFD, 0xA0, 0x08, 0xE0, 0x8D, 0xED, 0x62, 0x1A, 0x2C, 0x02, 0xB9, 0x22, 0x20, 0x58, 0x2B, 0x03, 0xA2, 0xD3, 0xE7, 0xFE, 0xC4, 0xE0, 0x8B, 0x3E, 0x0E, 0x05, - 0xF5, 0xB6, 0x54, 0x69, 0xF3, 0x62, 0x8F, 0xE0, 0xE4, 0x71, 0x53, 0x2C, 0xE7, 0xDC, 0xCA, 0xC6, 0x11, 0x97, 0x53, 0x7C, 0xF8, 0x9D, 0xD1, 0x7F, 0x2A, 0xD6, - 0xF0, 0x02, 0x25, 0x33, 0xAD, 0x5C, 0xA5, 0x06, 0x54, 0x16, 0x37, 0x85, 0xC5, 0x60, 0x72, 0xEE, 0x35, 0x3D, 0xEC, 0x4C, 0x16, 0x7E, 0x17, 0x4B, 0x70, 0xCF, - 0xB9, 0x08, 0x86, 0xEC, 0x1A, 0x8E, 0xC1, 0xA2, 0xA8, 0x0D, 0x63, 0xB2, 0xA2, 0x54, 0x02, 0xB7, 0xA5, 0xE4, 0xC3, 0x07, 0x70, 0x25, 0x0D, 0xA4, 0xD7, 0xED, - 0x4A, 0x6D, 0xA5, 0x81, 0x61, 0x61, 0xB2, 0x4E, 0xBF, 0x20, 0x96, 0xA2, 0x00, 0xAC, 0x59, 0xCE, 0xE5, 0x79, 0x0B, 0xCE, 0x3F, 0xC0, 0xB5, 0xA2, 0x78, 0x85, - 0x8D, 0xF8, 0x98, 0x49, 0x8A, 0x56, 0x39, 0x23, 0xDD, 0xEC, 0x28, 0x37, 0x15, 0xC6, 0xF2, 0x46, 0xB7, 0xD9, 0x91, 0xED, 0xAD, 0x64, 0x20, 0xE2, 0xC5, 0xDB, - 0xB1, 0x08, 0x49, 0xB1, 0xBC, 0x89, 0x2C, 0x6F, 0x31, 0xC2, 0x2F, 0x69, 0x21, 0xBF, 0x1F, 0x9C, 0x89, 0x8B, 0x54, 0x14, 0x17, 0xE1, 0xE2, 0xC2, 0x06, 0xF1, - 0xF0, 0xB2, 0x7C, 0xBA, 0x21, 0xB2, 0xFF, 0xDF, 0x9E, 0xC5, 0x9C, 0xAD, 0xC6, 0x85, 0x74, 0xF2, 0xE1, 0xBC, 0xC4, 0x5E, 0x71, 0x83, 0xC4, 0x47, 0x44, 0x18, - 0x5B, 0xAB, 0x71, 0x35, 0xB6, 0xC4, 0x74, 0x00, 0x36, 0x88, 0xD9, 0x52, 0x4F, 0x1A, 0x08, 0x56, 0x9E, 0x93, 0x90, 0xEF, 0x60, 0x33, 0x5C, 0x4B, 0x8B, 0x3E, - 0x7B, 0x1B, 0x11, 0x1B, 0x5D, 0x29, 0xA2, 0x39, 0x02, 0x62, 0x95, 0x57, 0x74, 0x5A, 0x89, 0xEC, 0x08, 0x3A, 0x36, 0xE1, 0x18, 0x81, 0x98, 0xAA, 0x38, 0x4A, - 0x4F, 0x38, 0xB1, 0x1A, 0xDE, 0xA2, 0xD4, 0xA7, 0x2A, 0x75, 0x19, 0xC0, 0x87, 0x68, 0x39, 0x75, 0x01, 0x53, 0x02, 0x86, 0x99, 0x2A, 0x8B, 0x16, 0xEC, 0x77, - 0x76, 0x20, 0x9E, 0x20, 0x66, 0x67, 0xEC, 0x83, 0xE3, 0x67, 0x07, 0xB3, 0x70, 0xEE, 0x8C, 0xEE, 0xFD, 0x2F, 0xFC, 0x34, 0x4E, 0xF9, 0x5F, 0xA4, 0x00, 0x00 + 0x1F, 0x8B, 0x08, 0x08, 0xA5, 0xF6, 0xDA, 0x67, 0x00, 0xFF, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x5F, 0x6F, 0x76, 0x32, 0x36, 0x34, 0x30, 0x2E, 0x68, 0x74, 0x6D, + 0x6C, 0x2E, 0x67, 0x7A, 0x00, 0xED, 0x7D, 0x7B, 0x73, 0xDB, 0x36, 0xD6, 0xF7, 0xFF, 0xFD, 0x14, 0x8C, 0xDA, 0xB5, 0xE4, 0xB1, 0x24, 0xDB, 0xB2, 0xE3, 0x24, + 0x5E, 0x5B, 0x79, 0x72, 0x71, 0x93, 0xCE, 0x93, 0xB4, 0xDD, 0xBA, 0x97, 0xEC, 0xEC, 0xEC, 0xA4, 0x94, 0x08, 0x49, 0x6C, 0x28, 0x52, 0x4B, 0x52, 0xBE, 0xB4, + 0xE3, 0xCF, 0xF1, 0x7E, 0xA0, 0xE7, 0x8B, 0xED, 0xEF, 0x00, 0x20, 0x09, 0x92, 0xE0, 0x4D, 0xB2, 0xA5, 0x6C, 0xF7, 0x95, 0x34, 0x12, 0x05, 0x02, 0x07, 0x07, + 0xE7, 0x86, 0x83, 0x83, 0x0B, 0xCF, 0x1E, 0x59, 0xDE, 0x38, 0xBC, 0x5D, 0x30, 0x63, 0x16, 0xCE, 0x9D, 0xE1, 0x17, 0x67, 0xE2, 0xC7, 0xC0, 0xEB, 0x6C, 0xC6, + 0x4C, 0x4B, 0x5C, 0xF2, 0xBF, 0x73, 0x16, 0x9A, 0xC6, 0x78, 0x66, 0xFA, 0x01, 0x0B, 0xCF, 0x5B, 0xCB, 0x70, 0xD2, 0x7B, 0xDA, 0xCA, 0xDE, 0x76, 0xCD, 0x39, + 0x3B, 0x6F, 0x5D, 0xD9, 0xEC, 0x7A, 0xE1, 0xF9, 0x61, 0xCB, 0x18, 0x7B, 0x6E, 0xC8, 0x5C, 0x64, 0xBF, 0xB6, 0xAD, 0x70, 0x76, 0x6E, 0xB1, 0x2B, 0x7B, 0xCC, + 0x7A, 0xFC, 0x4F, 0xD7, 0x76, 0xED, 0xD0, 0x36, 0x9D, 0x5E, 0x30, 0x36, 0x1D, 0x76, 0x7E, 0xA8, 0xC2, 0x0A, 0xED, 0xD0, 0x61, 0xC3, 0x8B, 0xCB, 0xEF, 0x8F, + 0x06, 0xC6, 0x77, 0x3F, 0x0F, 0x4E, 0x8E, 0x0F, 0xCE, 0xF6, 0x45, 0x5A, 0x92, 0x27, 0x08, 0x6F, 0xD5, 0xFF, 0xF4, 0x1A, 0x79, 0xD6, 0xAD, 0xF1, 0x47, 0x2A, + 0x89, 0x5E, 0x13, 0x20, 0xD1, 0x9B, 0x98, 0x73, 0xDB, 0xB9, 0x3D, 0x35, 0x5E, 0xF8, 0xA8, 0xB3, 0xFB, 0x96, 0x39, 0x57, 0x2C, 0xB4, 0xC7, 0x66, 0x37, 0x30, + 0xDD, 0xA0, 0x17, 0x30, 0xDF, 0x9E, 0xFC, 0x35, 0x57, 0x70, 0x64, 0x8E, 0x3F, 0x4D, 0x7D, 0x6F, 0xE9, 0x5A, 0xA7, 0xC6, 0x97, 0x87, 0x4F, 0xE9, 0x9D, 0xCF, + 0x34, 0xF6, 0x1C, 0xCF, 0xC7, 0xFD, 0x8B, 0xAF, 0xE9, 0x9D, 0xBF, 0xCF, 0x6B, 0x0F, 0xEC, 0xDF, 0xD9, 0xA9, 0x71, 0x78, 0xB2, 0xB8, 0x49, 0xDD, 0xBF, 0xFB, + 0x22, 0xF5, 0x77, 0x36, 0x28, 0xC2, 0x5E, 0x96, 0x7F, 0x5A, 0x5E, 0x3E, 0x60, 0xE3, 0xD0, 0xF6, 0xDC, 0xFE, 0xDC, 0xB4, 0x5D, 0x0D, 0x24, 0xCB, 0x0E, 0x16, + 0x8E, 0x09, 0x1A, 0x4C, 0x1C, 0x56, 0x0A, 0xE7, 0xCB, 0x39, 0x73, 0x97, 0xDD, 0x0A, 0x68, 0x04, 0xA4, 0x67, 0xD9, 0xBE, 0xC8, 0x75, 0x4A, 0x74, 0x58, 0xCE, + 0xDD, 0x4A, 0xB0, 0x65, 0x78, 0xB9, 0x9E, 0xCB, 0x34, 0x04, 0xA4, 0x8A, 0xAE, 0x7D, 0x73, 0x41, 0x19, 0xE8, 0x37, 0x9F, 0x65, 0x6E, 0xBB, 0x42, 0xA8, 0x4E, + 0x8D, 0xA3, 0xE3, 0x83, 0xC5, 0x4D, 0x05, 0x2B, 0x8F, 0x4E, 0xE8, 0x9D, 0xCF, 0xB4, 0x30, 0x2D, 0xCB, 0x76, 0xA7, 0xA7, 0x06, 0xE8, 0xAC, 0x01, 0xE1, 0xF9, + 0x16, 0xF3, 0x7B, 0xBE, 0x69, 0xD9, 0xCB, 0xE0, 0xD4, 0x38, 0xD6, 0xE5, 0x99, 0x9B, 0xFE, 0x14, 0xB8, 0x84, 0x1E, 0x90, 0xED, 0x1D, 0x6A, 0x31, 0x91, 0x59, + 0x7C, 0x7B, 0x3A, 0x0B, 0xC1, 0xD2, 0x5C, 0x9E, 0x2C, 0xD1, 0xA4, 0x0A, 0x55, 0xF1, 0xB3, 0x94, 0x6E, 0x7A, 0xAA, 0x99, 0x8E, 0x3D, 0x75, 0x7B, 0x76, 0xC8, + 0xE6, 0x68, 0x4E, 0x10, 0xFA, 0x2C, 0x1C, 0xCF, 0xCA, 0x50, 0x99, 0xD8, 0xD3, 0xA5, 0xCF, 0x34, 0x88, 0xC4, 0x74, 0x2B, 0x69, 0x30, 0x6E, 0xE6, 0x6F, 0xF5, + 0xAE, 0xD9, 0xE8, 0x93, 0x1D, 0xF6, 0x24, 0x4D, 0x46, 0x6C, 0xE2, 0xF9, 0x90, 0x73, 0x4D, 0xCE, 0x28, 0x87, 0xE3, 0x8D, 0x3F, 0xF5, 0x82, 0xD0, 0xF4, 0x41, + 0xBB, 0x6A, 0x80, 0xE6, 0x24, 0x64, 0xD0, 0xCD, 0x2A, 0x78, 0x8C, 0xA4, 0xA2, 0x1A, 0x5A, 0x71, 0xB5, 0x32, 0x83, 0xED, 0x3A, 0xB6, 0xCB, 0xEA, 0xA3, 0x57, + 0x54, 0x6F, 0x1A, 0x9C, 0xC8, 0x55, 0x83, 0x31, 0xF6, 0x7C, 0x5A, 0x26, 0x25, 0xBC, 0xAD, 0xF9, 0xCA, 0xA4, 0xDE, 0x1C, 0x1E, 0x1C, 0xFC, 0x25, 0x7F, 0x73, + 0xC6, 0x84, 0x98, 0x9A, 0xCB, 0xD0, 0x5B, 0x5F, 0x23, 0x72, 0x6A, 0x95, 0x69, 0xC7, 0xFF, 0xCC, 0x99, 0x65, 0x9B, 0x46, 0x47, 0x51, 0xE7, 0xA7, 0x07, 0x90, + 0xA9, 0x5D, 0xC3, 0x74, 0x2D, 0xA3, 0xE3, 0xF9, 0x36, 0x14, 0xC1, 0xE4, 0xE6, 0xC6, 0x41, 0x0A, 0x3A, 0x8E, 0x05, 0xDB, 0xD5, 0x34, 0xB9, 0x44, 0x67, 0x54, + 0x8A, 0xE8, 0xD5, 0xA6, 0xA6, 0xC9, 0xA9, 0xA5, 0x40, 0x9A, 0x36, 0x56, 0xF2, 0xAB, 0x0E, 0xCF, 0x04, 0x61, 0x81, 0x62, 0x19, 0xEF, 0xA2, 0x4C, 0x11, 0x0F, + 0xD1, 0xCD, 0x8E, 0x3B, 0xC8, 0x7A, 0x35, 0x33, 0x7A, 0x06, 0x59, 0xC9, 0x5D, 0x7D, 0x19, 0x09, 0x54, 0xCF, 0xF2, 0xAC, 0x50, 0x34, 0x68, 0xAE, 0xBE, 0xA9, + 0x89, 0xED, 0x10, 0x6F, 0x9D, 0x0C, 0x55, 0x58, 0x91, 0x66, 0x96, 0xA4, 0x81, 0x35, 0x69, 0x64, 0x51, 0x6A, 0x5B, 0x95, 0x46, 0x96, 0xA5, 0x89, 0x75, 0x69, + 0x60, 0x61, 0x6A, 0x59, 0x19, 0xC1, 0xCE, 0x6A, 0x7F, 0xE3, 0xCB, 0xD1, 0x32, 0x0C, 0x3D, 0x37, 0x58, 0xAB, 0x8B, 0x2A, 0xD2, 0xB3, 0xDF, 0x96, 0x41, 0x68, + 0x4F, 0x6E, 0x7B, 0x52, 0xA5, 0xA1, 0x67, 0x0B, 0x13, 0x2E, 0xE4, 0x88, 0x85, 0xD7, 0x8C, 0x95, 0xBB, 0x1B, 0xAE, 0x79, 0x05, 0xBB, 0x33, 0x9D, 0x3A, 0x3A, + 0xD9, 0x1B, 0x2F, 0xFD, 0x80, 0xFC, 0xB6, 0x85, 0x67, 0x03, 0xB0, 0x9F, 0xAF, 0x38, 0xAD, 0x83, 0x35, 0x2B, 0xEA, 0x8D, 0x47, 0x9A, 0xBA, 0xBC, 0x65, 0x48, + 0x34, 0xD6, 0x72, 0xC2, 0x43, 0x73, 0xEC, 0x10, 0xD5, 0x68, 0xEE, 0x49, 0x4D, 0xD4, 0xDC, 0x89, 0x54, 0xB0, 0xB4, 0x5B, 0x48, 0xE3, 0x75, 0x3A, 0x9E, 0xB1, + 0xF1, 0x27, 0x66, 0xED, 0x55, 0xBA, 0x61, 0x55, 0xEE, 0x61, 0xDF, 0x76, 0x17, 0xCB, 0xB0, 0x47, 0xEE, 0xD4, 0xE2, 0x41, 0x78, 0xCE, 0x05, 0x32, 0x6A, 0xE2, + 0x60, 0x50, 0xE6, 0x54, 0x3C, 0x5E, 0xDC, 0x94, 0x13, 0x41, 0x45, 0x76, 0xE8, 0x98, 0x23, 0xE6, 0x94, 0xA1, 0x2C, 0x95, 0xA1, 0xC0, 0xEC, 0x4A, 0x5B, 0x55, + 0xEC, 0xBB, 0x65, 0x7C, 0xD1, 0xE3, 0x27, 0x7F, 0xA9, 0x4D, 0x47, 0x7E, 0xDD, 0x4D, 0x25, 0x05, 0xCC, 0x81, 0x82, 0x15, 0xB9, 0xDE, 0xC8, 0x73, 0x0D, 0x1C, + 0x4A, 0x2B, 0xF0, 0x4D, 0x77, 0xCA, 0x60, 0x0B, 0x6E, 0xBA, 0xD1, 0x65, 0xF9, 0xC0, 0xA0, 0x56, 0xF3, 0xC9, 0x54, 0x83, 0xEC, 0x65, 0x15, 0x0B, 0x83, 0xD0, + 0x35, 0xFA, 0xE2, 0x62, 0x05, 0xAF, 0x44, 0xE1, 0x6F, 0x29, 0x22, 0x87, 0x5A, 0xE9, 0x10, 0x8E, 0x89, 0x56, 0x73, 0xD2, 0xB2, 0xA5, 0x75, 0xF4, 0x2B, 0x4D, + 0x43, 0x34, 0xE4, 0x9B, 0x4C, 0xAA, 0x06, 0x8D, 0x93, 0xC9, 0xD1, 0xC1, 0xD1, 0x71, 0xA5, 0xE7, 0xA4, 0x6D, 0x65, 0x66, 0xE0, 0xA8, 0x31, 0x1D, 0xB1, 0x59, + 0x29, 0x15, 0x82, 0xC0, 0xBC, 0xD2, 0x3A, 0xED, 0x5E, 0x80, 0xF1, 0x37, 0x8D, 0xDC, 0xCC, 0x51, 0x80, 0xB1, 0x5B, 0xA8, 0x19, 0x7A, 0x49, 0x41, 0x1F, 0x68, + 0xF1, 0xE3, 0x2E, 0x9D, 0x56, 0x05, 0x22, 0xF2, 0xEA, 0xD1, 0x4E, 0x71, 0x40, 0x9F, 0x45, 0x61, 0xB0, 0xD6, 0xA9, 0x0C, 0xD9, 0x4D, 0xD8, 0xB3, 0xD8, 0xD8, + 0xF3, 0x85, 0x37, 0x58, 0x30, 0x72, 0xCC, 0x30, 0xB2, 0x5A, 0x62, 0x4F, 0x67, 0xDE, 0x15, 0xF3, 0x35, 0xC4, 0xCA, 0x30, 0xF5, 0xF8, 0xD9, 0xB1, 0x55, 0x03, + 0x9A, 0x89, 0xEE, 0x51, 0x4B, 0xFB, 0x34, 0xB8, 0xC1, 0xE1, 0x78, 0x50, 0xAA, 0xC7, 0x02, 0x5C, 0x1F, 0x3A, 0x63, 0x8E, 0x1C, 0x66, 0x95, 0xF4, 0x66, 0x16, + 0x9B, 0x98, 0x4B, 0x27, 0xAC, 0x90, 0x4A, 0xF3, 0x80, 0xDE, 0x65, 0x35, 0x72, 0x33, 0xF4, 0x0F, 0x8A, 0x0B, 0x9D, 0x73, 0xC3, 0xF1, 0x4F, 0x4D, 0x9D, 0x91, + 0xAB, 0x61, 0x2E, 0x16, 0xCC, 0x44, 0xAE, 0x31, 0x24, 0x51, 0xCF, 0x87, 0x5A, 0x43, 0x0C, 0xBD, 0x9D, 0xAF, 0x35, 0x6E, 0xAF, 0x54, 0xD8, 0xD8, 0x79, 0x6C, + 0xD4, 0xE6, 0xD3, 0x89, 0x37, 0x5E, 0xEA, 0xBC, 0x9A, 0x7A, 0x8A, 0x97, 0x87, 0x77, 0x1A, 0x91, 0x2C, 0x70, 0x6C, 0xAE, 0xFE, 0x4B, 0xD7, 0x25, 0x8E, 0xF6, + 0x42, 0x1F, 0xCD, 0xD4, 0x54, 0x54, 0x8F, 0x70, 0x2B, 0xD9, 0xB0, 0x14, 0x61, 0x8B, 0x62, 0x57, 0x19, 0x33, 0xA5, 0x31, 0xA7, 0xB1, 0xA5, 0x35, 0x60, 0x43, + 0x6C, 0x2B, 0x02, 0xB5, 0x1E, 0x5D, 0xC2, 0xD9, 0x72, 0xAE, 0xF3, 0xA3, 0xA2, 0xCA, 0x0E, 0xD1, 0xE9, 0x8B, 0xEA, 0xFC, 0xE9, 0xC8, 0xEC, 0x1C, 0x74, 0x0F, + 0xBA, 0x47, 0xF8, 0xD2, 0x8C, 0x67, 0xCA, 0x85, 0x4B, 0x92, 0xB7, 0x40, 0xF2, 0x32, 0x26, 0xBA, 0x3A, 0xAC, 0x54, 0x64, 0xEC, 0x2B, 0x79, 0x51, 0x5F, 0x93, + 0xD2, 0xF1, 0xA5, 0xC3, 0x7E, 0x45, 0x3F, 0x5C, 0x20, 0xD2, 0xCD, 0x05, 0x51, 0x23, 0x2D, 0x4D, 0x59, 0x3C, 0xF7, 0x7E, 0x07, 0x31, 0xC9, 0x09, 0xF9, 0xAF, + 0x97, 0x76, 0x85, 0x14, 0x7F, 0x6A, 0x49, 0x6F, 0x4C, 0x97, 0x60, 0xDB, 0xB2, 0x81, 0x00, 0x44, 0x21, 0x7D, 0xA4, 0xD7, 0x07, 0x0C, 0x5D, 0x8C, 0x41, 0x7D, + 0x0C, 0x46, 0x0B, 0x3D, 0x43, 0x25, 0xCF, 0x0A, 0x34, 0x98, 0xD8, 0x8E, 0xD3, 0x73, 0xBC, 0xEB, 0x6A, 0x4F, 0xA4, 0x5C, 0x92, 0x73, 0x72, 0x5A, 0x2D, 0xF2, + 0xAB, 0x62, 0xBB, 0x84, 0xE5, 0xFA, 0x8F, 0xC0, 0xF6, 0xBF, 0xAD, 0x6B, 0x51, 0x54, 0x63, 0xB5, 0x8E, 0x62, 0x05, 0x79, 0x5C, 0xAF, 0xA2, 0x5A, 0xA2, 0x24, + 0x3C, 0xC1, 0xF2, 0x61, 0xCF, 0xB5, 0x8D, 0x70, 0xEC, 0x0A, 0x43, 0xCF, 0x64, 0x60, 0xE4, 0x33, 0x07, 0xE3, 0x8B, 0x2B, 0x4D, 0x3F, 0x5C, 0x23, 0x42, 0x51, + 0x39, 0x7C, 0x53, 0x8B, 0xD7, 0x69, 0x09, 0x27, 0xDD, 0xE7, 0x13, 0x5D, 0xEA, 0x0B, 0xDF, 0xA1, 0xD8, 0x56, 0xEB, 0xC5, 0xBA, 0xC2, 0xDD, 0x4F, 0x6B, 0x86, + 0x3E, 0x53, 0x03, 0x8B, 0x1E, 0x19, 0xED, 0xA9, 0xCF, 0x6E, 0x6B, 0x34, 0xA6, 0x2B, 0x7F, 0x4F, 0x45, 0xFC, 0x78, 0xF5, 0x50, 0x09, 0xEF, 0x00, 0xA4, 0x14, + 0xF5, 0x8F, 0x83, 0x1A, 0x55, 0x17, 0x57, 0x59, 0x47, 0x1E, 0xE3, 0xE8, 0x68, 0xAB, 0x55, 0xC3, 0xDC, 0x94, 0x74, 0xA1, 0x7A, 0x51, 0x8D, 0x7A, 0x5F, 0xFD, + 0x78, 0x9E, 0x4D, 0x50, 0x50, 0x3F, 0x4E, 0x27, 0x3F, 0xF5, 0xA8, 0xDC, 0xBA, 0x45, 0x2C, 0xA2, 0x68, 0x4A, 0xA5, 0xE5, 0x88, 0x83, 0x98, 0xC5, 0xD2, 0xA7, + 0x85, 0x4C, 0xD6, 0xB3, 0x31, 0xF0, 0x62, 0x96, 0x44, 0xEE, 0x33, 0x67, 0x33, 0xF2, 0xCC, 0x65, 0x97, 0x0F, 0xF6, 0xB0, 0x0F, 0x9D, 0x01, 0xC8, 0xA4, 0xE9, + 0x30, 0x4A, 0x32, 0x97, 0x07, 0xD9, 0x0B, 0xA2, 0x80, 0xF9, 0x2E, 0xAB, 0x70, 0x80, 0xAC, 0xDA, 0x22, 0x2D, 0xA3, 0xCA, 0xB5, 0xB2, 0xCC, 0xC2, 0xE4, 0x23, + 0x59, 0xE5, 0x21, 0xCF, 0xB9, 0x09, 0xB7, 0x97, 0xC4, 0x15, 0xAB, 0x0A, 0xB4, 0xFC, 0xAB, 0x23, 0xEE, 0x4A, 0x8C, 0xF5, 0xF0, 0x04, 0x66, 0xA6, 0xB4, 0xCA, + 0xB1, 0xE3, 0x05, 0x6B, 0x06, 0xC0, 0x8A, 0xE3, 0x5F, 0xDA, 0x3B, 0xB5, 0xBA, 0xEE, 0x52, 0x9D, 0x2A, 0x57, 0xC7, 0x0C, 0xCD, 0xE1, 0x14, 0x6B, 0xCD, 0x64, + 0x59, 0x94, 0x92, 0x47, 0xD0, 0xF8, 0xFC, 0x25, 0x26, 0x06, 0x61, 0x39, 0x74, 0x66, 0x34, 0x1D, 0xA8, 0xAB, 0x13, 0x2A, 0x2D, 0xE5, 0xC3, 0xCC, 0xB6, 0x2C, + 0x56, 0x1A, 0x0B, 0xA6, 0x31, 0x6F, 0x4D, 0xE7, 0x81, 0xF0, 0xD7, 0x05, 0xA5, 0x1E, 0x44, 0x29, 0x4A, 0x97, 0x35, 0xA0, 0xA6, 0x87, 0xD5, 0x18, 0xD9, 0xD1, + 0x14, 0x45, 0xD2, 0xD3, 0xAE, 0x48, 0x29, 0xAA, 0x5A, 0xE5, 0x8E, 0x63, 0xAD, 0x44, 0x32, 0xD0, 0x81, 0x72, 0xE5, 0xAD, 0x79, 0x06, 0x2B, 0x3E, 0x91, 0xD2, + 0x97, 0x73, 0x4B, 0x72, 0x1A, 0xB0, 0x57, 0x34, 0xBB, 0x72, 0x8F, 0x53, 0x6D, 0x5C, 0x02, 0xB2, 0xF5, 0x16, 0x92, 0x66, 0x4B, 0x9E, 0x51, 0x09, 0x92, 0x71, + 0x17, 0x13, 0x2D, 0xAE, 0x4A, 0xE7, 0x5A, 0x55, 0x39, 0xCE, 0xF6, 0x95, 0xD5, 0x70, 0x67, 0xFB, 0xC9, 0xC2, 0xBD, 0x33, 0x5A, 0x12, 0xA7, 0x2E, 0x9A, 0x93, + 0xF5, 0x8C, 0x1D, 0x33, 0x08, 0xCE, 0x5B, 0xB4, 0xB4, 0x4B, 0x59, 0x77, 0xC7, 0xB3, 0x58, 0xF6, 0x95, 0x61, 0x5B, 0xE7, 0x2D, 0xC7, 0x9B, 0x7A, 0x99, 0x7B, + 0xFC, 0xBE, 0xE0, 0x32, 0xFA, 0xB1, 0xF3, 0x56, 0x6A, 0x7E, 0xB1, 0xC5, 0x4B, 0x25, 0x49, 0xAD, 0xE1, 0xCE, 0x97, 0xCF, 0x9E, 0x3C, 0x39, 0xF9, 0xEB, 0x8E, + 0x3B, 0x0A, 0x16, 0xF2, 0xFB, 0x47, 0x31, 0x1D, 0x2B, 0xD6, 0xF4, 0xA1, 0x6B, 0x0B, 0x43, 0x88, 0x5E, 0x70, 0xB6, 0xCF, 0x81, 0x66, 0x10, 0xD9, 0x07, 0x26, + 0x05, 0xB8, 0x49, 0x77, 0x47, 0x87, 0x5E, 0x94, 0x25, 0x40, 0x0F, 0x3E, 0x32, 0x7D, 0x4D, 0x16, 0x9E, 0x4D, 0x38, 0xD3, 0xDC, 0x94, 0xB4, 0x38, 0x4F, 0x46, + 0xDE, 0x4D, 0xB6, 0x05, 0xBC, 0x51, 0x92, 0x61, 0x32, 0x17, 0xB3, 0x8A, 0x00, 0xA2, 0x18, 0x2F, 0x4E, 0x93, 0xAB, 0xC8, 0xA3, 0xCD, 0x94, 0x62, 0x01, 0x65, + 0xBE, 0x19, 0x3B, 0x58, 0x7F, 0x20, 0x12, 0x50, 0x95, 0x60, 0x8A, 0xEB, 0x85, 0xC2, 0x54, 0x16, 0x54, 0x95, 0x6A, 0xAA, 0x2C, 0xA3, 0x4C, 0x1B, 0x8A, 0x56, + 0x80, 0xB4, 0x3D, 0x0E, 0x5D, 0xA4, 0x95, 0x43, 0xCA, 0xF2, 0x35, 0x2A, 0xDC, 0x1A, 0x7E, 0x78, 0xF5, 0xEE, 0x7F, 0x8D, 0xF7, 0x6F, 0x7F, 0xD7, 0x72, 0xA8, + 0x0A, 0x29, 0xB2, 0xD1, 0x35, 0x6A, 0x56, 0xF8, 0x11, 0xD1, 0xA4, 0x25, 0x39, 0xC3, 0x21, 0x50, 0x6F, 0xEF, 0x30, 0x77, 0x8A, 0xF5, 0xA3, 0xAD, 0x43, 0xFC, + 0x33, 0x6F, 0xA2, 0x7F, 0x83, 0x96, 0x41, 0xF6, 0x9B, 0x5F, 0x5C, 0x99, 0xCE, 0x92, 0xAE, 0x0E, 0xEA, 0xB4, 0x35, 0x2F, 0x5A, 0xDA, 0x6C, 0xD2, 0xB0, 0xC4, + 0x34, 0x56, 0x0C, 0x71, 0x9A, 0xCA, 0xAD, 0xE1, 0x25, 0x0B, 0xCF, 0xF6, 0xC5, 0xAD, 0x0A, 0xAE, 0x95, 0xD7, 0x0D, 0x4D, 0x16, 0xE2, 0x50, 0x26, 0x42, 0x65, + 0x8C, 0x9F, 0xF8, 0x58, 0x82, 0x4B, 0x54, 0xA9, 0xC5, 0x79, 0x95, 0xEB, 0x71, 0xC9, 0xD6, 0xF0, 0x07, 0xC6, 0x1D, 0x22, 0xA0, 0x51, 0x8B, 0xF1, 0x90, 0x69, + 0xEE, 0xA3, 0xA6, 0xEA, 0x8F, 0xE5, 0x59, 0xCE, 0x49, 0xF5, 0x68, 0x36, 0x0C, 0x84, 0xAB, 0x41, 0xF7, 0x47, 0xBD, 0x9E, 0x31, 0x78, 0xFF, 0xBD, 0xD1, 0xEB, + 0xD5, 0xC8, 0xEC, 0x2D, 0xB8, 0x3A, 0x49, 0xFE, 0x1F, 0x3E, 0x6E, 0x0D, 0x7F, 0xFA, 0xF0, 0xE6, 0x45, 0x07, 0x7E, 0xE1, 0xC1, 0xCD, 0xE1, 0xE0, 0xE0, 0x60, + 0xF7, 0x6C, 0x5F, 0x64, 0x69, 0x0E, 0xEB, 0x18, 0x7C, 0xE5, 0xB0, 0x06, 0x4F, 0x01, 0xEB, 0x60, 0x70, 0xBC, 0x06, 0xAC, 0xA3, 0xD6, 0xF0, 0xED, 0x6B, 0x01, + 0xE9, 0xC9, 0x60, 0x1D, 0xA4, 0x06, 0xD0, 0x4A, 0xC2, 0x09, 0xE8, 0xDC, 0x3C, 0x39, 0x79, 0xBA, 0x06, 0x24, 0x2C, 0xB9, 0xBE, 0xFC, 0x19, 0xA0, 0xB0, 0xC6, + 0xEE, 0x06, 0xD4, 0x5A, 0x03, 0x12, 0x94, 0x8E, 0x00, 0xC1, 0xA6, 0xDF, 0x1C, 0x3F, 0x5D, 0x03, 0xD0, 0x33, 0x10, 0x89, 0x00, 0x01, 0xC8, 0xCD, 0xD1, 0x3A, + 0x54, 0xC2, 0xCA, 0xF4, 0x57, 0xDF, 0x7C, 0xDD, 0x39, 0x46, 0xCB, 0x06, 0xCF, 0x4E, 0x9A, 0xC0, 0x81, 0xEC, 0xA5, 0x41, 0x3D, 0x69, 0x0D, 0x81, 0x0A, 0xA1, + 0x13, 0x41, 0x81, 0x58, 0x0A, 0x19, 0xFD, 0xC9, 0x0D, 0x10, 0xAD, 0xC2, 0x42, 0x77, 0xCC, 0xC9, 0xA2, 0x80, 0x77, 0xC5, 0x7B, 0xB5, 0x15, 0xA4, 0xF6, 0xA4, + 0x35, 0xFC, 0x1B, 0xB5, 0x9B, 0x2A, 0x1A, 0x1C, 0xAF, 0xD1, 0x6E, 0x48, 0x3F, 0xCA, 0x13, 0x8C, 0x95, 0x41, 0x40, 0xE8, 0xDF, 0x72, 0x64, 0x08, 0xD0, 0xE1, + 0x93, 0x46, 0xC4, 0x4B, 0x43, 0x82, 0xC8, 0xFF, 0x8D, 0xB8, 0x00, 0x20, 0x37, 0x87, 0xC7, 0x6B, 0x28, 0x0F, 0x44, 0x1E, 0x8A, 0x03, 0x6D, 0x7E, 0xBA, 0xBA, + 0x88, 0x02, 0x17, 0xDE, 0x2A, 0xD8, 0x05, 0x32, 0x0B, 0xAB, 0x23, 0x03, 0x59, 0x7F, 0x76, 0x72, 0xF3, 0xEC, 0xA4, 0x1E, 0x00, 0xB2, 0xE7, 0x64, 0x1B, 0xCB, + 0x2C, 0x7E, 0x79, 0x87, 0x50, 0x66, 0xEC, 0xFF, 0xB5, 0xC4, 0x10, 0x2E, 0xBC, 0x6D, 0x6C, 0xEA, 0x65, 0x39, 0xD0, 0x44, 0x5C, 0xD4, 0xB3, 0xF2, 0x0A, 0x26, + 0xF1, 0x6A, 0xA2, 0xD6, 0xF0, 0xB8, 0x46, 0x6F, 0x9A, 0x72, 0xB7, 0x78, 0xD9, 0x14, 0xFE, 0xBC, 0x8B, 0x27, 0xC9, 0xA3, 0xCE, 0x1D, 0xDA, 0x70, 0x14, 0x77, + 0xE7, 0xB0, 0x2C, 0x2B, 0x75, 0x23, 0x1A, 0x5C, 0xCD, 0x9B, 0xD6, 0xF0, 0xE4, 0xA8, 0xB2, 0xFB, 0x5D, 0x9D, 0x19, 0x23, 0x1E, 0x2C, 0x70, 0x59, 0x10, 0x34, + 0xE6, 0x47, 0x52, 0xB4, 0x35, 0x7C, 0x19, 0x5F, 0xAF, 0xC3, 0x95, 0xDE, 0x60, 0x0D, 0xB6, 0x28, 0xE8, 0x08, 0xCE, 0xF4, 0xE0, 0x60, 0x71, 0xD6, 0x24, 0x8E, + 0xD6, 0xFD, 0x32, 0xA6, 0x0A, 0xDB, 0x75, 0xF8, 0x42, 0x83, 0x05, 0xDF, 0x0C, 0xA2, 0xB4, 0xFA, 0x5C, 0x89, 0x0A, 0xA2, 0x2F, 0x91, 0x57, 0x5B, 0xE3, 0x48, + 0x8C, 0xCA, 0x9F, 0x80, 0x1F, 0x81, 0x19, 0x2E, 0xC5, 0xBA, 0xAD, 0xC6, 0x1C, 0x49, 0x8A, 0xC2, 0x75, 0x89, 0xAF, 0xB7, 0xC6, 0x15, 0x05, 0x9D, 0x3F, 0x03, + 0x5F, 0x16, 0x6C, 0x8C, 0xBD, 0x71, 0x1F, 0xD9, 0x64, 0x82, 0x0E, 0xAB, 0x39, 0x6F, 0x52, 0xC5, 0xC1, 0x1F, 0xF1, 0xDF, 0xB8, 0xE0, 0xFF, 0x1B, 0x8F, 0x23, + 0x32, 0xE0, 0x56, 0x1F, 0x4C, 0x64, 0x7B, 0x6F, 0x19, 0x50, 0xA7, 0x21, 0x7D, 0x74, 0xD5, 0x1A, 0x7E, 0xEB, 0xC5, 0x78, 0xAE, 0xEE, 0x60, 0x7C, 0xCB, 0xA6, + 0x3C, 0x5E, 0xBD, 0x8E, 0x9F, 0xF3, 0xC6, 0x37, 0x6F, 0xF9, 0x86, 0xC8, 0x75, 0xBC, 0xAE, 0x1F, 0xE0, 0x8F, 0xFE, 0x88, 0x58, 0xDB, 0x3A, 0x3E, 0xE0, 0x1B, + 0x1F, 0xCB, 0xEB, 0xD7, 0x83, 0x02, 0x67, 0xF4, 0x25, 0x2E, 0xD6, 0x03, 0x02, 0xD7, 0xF8, 0x92, 0x2D, 0x6C, 0xF3, 0x73, 0x70, 0xB7, 0xCC, 0xEB, 0x51, 0x63, + 0xB5, 0x40, 0x99, 0xD6, 0xF0, 0xC5, 0x2F, 0x2F, 0x1B, 0x1B, 0x29, 0x31, 0xEB, 0x5B, 0x47, 0xC2, 0x93, 0xD8, 0x09, 0x55, 0x96, 0x0B, 0x6A, 0xE9, 0x35, 0xA7, + 0x6E, 0x60, 0x4B, 0xD3, 0xAE, 0x08, 0x41, 0x3E, 0x49, 0xD6, 0x52, 0x9A, 0x59, 0xAF, 0x8D, 0x0F, 0x67, 0xC1, 0x80, 0xC4, 0xC7, 0x29, 0x42, 0x9A, 0xAB, 0x30, + 0x89, 0x17, 0xE4, 0x9C, 0x32, 0xDE, 0xE0, 0x6A, 0x53, 0xEC, 0x12, 0xD5, 0x6E, 0x8D, 0x67, 0xB2, 0xD5, 0xDB, 0x66, 0x1C, 0x10, 0x99, 0x7B, 0x56, 0xF3, 0x90, + 0x95, 0x2C, 0xD7, 0x1A, 0x82, 0x6B, 0xEF, 0x71, 0xD1, 0xB8, 0x97, 0x89, 0x00, 0x3C, 0x70, 0xF7, 0xF2, 0x02, 0x3B, 0xE5, 0xD6, 0xE9, 0x59, 0x2E, 0xB1, 0x3E, + 0x13, 0x83, 0xB4, 0xD5, 0xBB, 0x95, 0x57, 0x8E, 0xB7, 0xB4, 0x56, 0x87, 0x80, 0x3E, 0xE5, 0xBB, 0xC9, 0x04, 0x5B, 0xF7, 0xD7, 0x8A, 0x2A, 0x78, 0xF3, 0x9A, + 0xE5, 0x1F, 0xD8, 0x8A, 0xB3, 0x71, 0x73, 0x03, 0xC1, 0xC6, 0xE0, 0xE2, 0xC5, 0x2B, 0xE3, 0xF2, 0xE2, 0xDB, 0xCB, 0xEF, 0x7E, 0xD8, 0x8C, 0x75, 0x40, 0x9D, + 0x5B, 0x32, 0x0C, 0xD4, 0xDA, 0xAD, 0x1B, 0x73, 0x36, 0x1E, 0xAC, 0xC2, 0x27, 0x48, 0x3B, 0x31, 0xEA, 0xF5, 0xE5, 0xF7, 0x9B, 0xE2, 0x12, 0x9C, 0xFD, 0x6D, + 0xB1, 0x09, 0x8D, 0xDD, 0x3E, 0x9F, 0x3E, 0x3A, 0xEC, 0x8A, 0x39, 0x2B, 0xF0, 0x4A, 0x14, 0x24, 0x7E, 0x19, 0xEF, 0xE8, 0x6A, 0x6B, 0x03, 0xB9, 0x18, 0x95, + 0x3F, 0xC1, 0x30, 0x0E, 0x52, 0xF1, 0x91, 0x23, 0xBD, 0x8A, 0xF2, 0x88, 0x92, 0xAD, 0xE1, 0xC5, 0x0D, 0x56, 0xC7, 0x60, 0xD3, 0xF6, 0x3A, 0x1C, 0x41, 0x08, + 0x7A, 0x0D, 0x86, 0x44, 0xA8, 0x08, 0x8E, 0x80, 0xFC, 0x9C, 0x21, 0x34, 0xA1, 0xA3, 0xCC, 0xF5, 0x21, 0x62, 0x78, 0x8F, 0x5C, 0x21, 0xE0, 0x0F, 0xC9, 0x98, + 0xE9, 0x0A, 0xFD, 0xCE, 0x94, 0xFA, 0x9D, 0x37, 0xAF, 0x36, 0x63, 0xCA, 0x50, 0xD9, 0x96, 0x2C, 0x19, 0x35, 0x73, 0x7B, 0x86, 0xCC, 0x90, 0xF3, 0xED, 0x11, + 0x15, 0x56, 0x1C, 0x44, 0xC8, 0x82, 0x18, 0x3B, 0xAF, 0x32, 0x80, 0x50, 0x34, 0xE7, 0xF0, 0x66, 0x1D, 0xD5, 0x89, 0xD0, 0x48, 0x6B, 0xCE, 0x51, 0xA2, 0x37, + 0x8F, 0xEF, 0x55, 0x6B, 0x8E, 0x2A, 0xB1, 0x5D, 0x47, 0x69, 0xA8, 0x25, 0x63, 0x66, 0x63, 0xE6, 0x7D, 0xDA, 0x98, 0x21, 0x4A, 0x59, 0xC1, 0x13, 0xE3, 0x95, + 0xF8, 0xB7, 0x0E, 0x6F, 0x06, 0xEB, 0xF0, 0x46, 0xC5, 0x28, 0xCD, 0x9E, 0x93, 0x07, 0xEA, 0x69, 0x68, 0xDE, 0xEC, 0x21, 0xE7, 0x3C, 0x16, 0xCD, 0x6D, 0x1A, + 0xCA, 0x20, 0x30, 0xF4, 0xFD, 0x66, 0x6C, 0x1A, 0x55, 0x56, 0xD3, 0xA6, 0xAD, 0x65, 0xC1, 0x78, 0xA3, 0xB6, 0x3E, 0x8C, 0x5E, 0x81, 0x1B, 0x28, 0x83, 0xE1, + 0xF3, 0x86, 0xB8, 0x41, 0x95, 0x6D, 0xA7, 0x87, 0xE1, 0xCD, 0xDC, 0x36, 0x7F, 0x7C, 0xF3, 0xFA, 0xE3, 0x74, 0x6E, 0x36, 0xE6, 0x91, 0x2C, 0x87, 0xC0, 0xAE, + 0x79, 0x6D, 0xBC, 0x79, 0xFF, 0x62, 0x23, 0xBC, 0x8A, 0x2A, 0xDD, 0x0E, 0xBF, 0xE2, 0x26, 0x6F, 0x9B, 0x67, 0x58, 0x6B, 0xD6, 0x5C, 0xA9, 0xA8, 0x50, 0x6B, + 0xF8, 0x8E, 0xE1, 0x4C, 0x9C, 0x57, 0x9E, 0x2F, 0x8F, 0xC8, 0xDB, 0x08, 0xD7, 0x78, 0xCD, 0xDB, 0x61, 0x99, 0x68, 0xF4, 0xB6, 0xF9, 0x35, 0x9B, 0xDB, 0xBE, + 0xEF, 0xF9, 0x8D, 0x59, 0x26, 0xCB, 0x21, 0x4C, 0xD5, 0x7B, 0xCF, 0xAF, 0x36, 0xC2, 0xAE, 0xA8, 0xD6, 0xED, 0x70, 0x2C, 0x6E, 0xF3, 0xB6, 0x99, 0x76, 0x35, + 0x71, 0xEC, 0x45, 0x63, 0x96, 0xF1, 0x52, 0x58, 0x79, 0xD6, 0xFB, 0x1A, 0xBF, 0x1B, 0x61, 0x97, 0xA8, 0x71, 0x3B, 0xCC, 0x92, 0xAD, 0xDD, 0x36, 0xAB, 0xAC, + 0xF1, 0x75, 0x63, 0x46, 0xA1, 0x4C, 0x6B, 0xF8, 0xFA, 0xD5, 0x2F, 0x46, 0xE7, 0xB5, 0x77, 0x8D, 0x7D, 0x71, 0xBF, 0x33, 0xE3, 0xE2, 0x5B, 0xAC, 0xC0, 0xDA, + 0x00, 0xC7, 0xA8, 0xEA, 0xED, 0xF0, 0x8B, 0x37, 0x7A, 0xDB, 0xDC, 0xE2, 0x7B, 0x80, 0xB0, 0x0C, 0x7E, 0x85, 0xB5, 0x2F, 0xA2, 0x20, 0xAD, 0x7D, 0xC1, 0x95, + 0xF1, 0xD2, 0xDC, 0x8C, 0x41, 0x8C, 0xEB, 0xDD, 0x84, 0xD3, 0x9E, 0x34, 0x72, 0xFB, 0x5E, 0x86, 0x55, 0x83, 0x45, 0x69, 0x17, 0xC3, 0xFA, 0x48, 0xDB, 0x69, + 0x68, 0x9B, 0x29, 0x16, 0xF2, 0xBD, 0xBB, 0x78, 0x6D, 0x7C, 0x13, 0xFD, 0xAD, 0xD1, 0x9A, 0x95, 0x63, 0x76, 0x45, 0x43, 0xDB, 0x34, 0x3E, 0xE9, 0xC1, 0xED, + 0xE0, 0x31, 0x42, 0x0E, 0xEB, 0x0C, 0x6F, 0x8B, 0xC2, 0xA8, 0x8F, 0x1F, 0xAF, 0xC9, 0x13, 0x75, 0x33, 0x86, 0x3C, 0xC5, 0xB0, 0x4A, 0x49, 0xE4, 0xA6, 0x00, + 0x3E, 0x9C, 0xC7, 0xF2, 0x7F, 0x9C, 0x4E, 0xE8, 0x20, 0x84, 0xFD, 0x86, 0x85, 0xC6, 0x25, 0x5D, 0xD6, 0xDC, 0x05, 0xA0, 0x40, 0x89, 0xB6, 0x00, 0xE1, 0xFC, + 0x50, 0x73, 0x8E, 0xB9, 0x3E, 0x3A, 0xDF, 0x11, 0xB0, 0xE8, 0x5F, 0x35, 0xB0, 0xDA, 0xFB, 0x05, 0xF8, 0x06, 0x21, 0xDA, 0xF1, 0x93, 0x3E, 0x8E, 0x15, 0xA2, + 0x2F, 0xB6, 0xFF, 0x0D, 0xCF, 0x70, 0x60, 0x85, 0x1B, 0x65, 0xE3, 0x7B, 0xE3, 0xAE, 0xE5, 0x66, 0xA7, 0x91, 0xE7, 0x58, 0xC8, 0xF8, 0xC2, 0xBA, 0xA2, 0xA3, + 0x69, 0x2C, 0x03, 0x7B, 0x1D, 0xE4, 0xB6, 0x1D, 0x2A, 0x02, 0xDD, 0x89, 0x20, 0x54, 0x10, 0x7B, 0xE6, 0x47, 0xE0, 0xC5, 0x06, 0x2B, 0x3A, 0xCC, 0xA3, 0x84, + 0xDA, 0x05, 0x3B, 0x8D, 0x7C, 0x86, 0xD8, 0x49, 0xB4, 0xC3, 0x44, 0xB3, 0x01, 0x4D, 0xBB, 0xEF, 0xE8, 0x07, 0x36, 0xB5, 0x03, 0xE0, 0x68, 0x80, 0x4F, 0xFB, + 0x7C, 0xAF, 0x86, 0xD0, 0x90, 0x7A, 0xFB, 0x80, 0xD4, 0x2A, 0xE5, 0x2E, 0x46, 0xED, 0xEE, 0xAE, 0x46, 0x5D, 0x48, 0x76, 0x2F, 0x56, 0x1A, 0x62, 0x95, 0x14, + 0x62, 0xF9, 0xF9, 0xEC, 0x98, 0x76, 0x9D, 0x18, 0x51, 0xD3, 0xB0, 0xED, 0xEB, 0xB8, 0x6A, 0xE9, 0x79, 0xE5, 0x96, 0x21, 0xB4, 0x74, 0xE5, 0x1D, 0x43, 0x44, + 0x25, 0x2C, 0x3D, 0x9A, 0x76, 0x8D, 0xF7, 0x66, 0xF0, 0xA9, 0x6B, 0xFC, 0x4C, 0x0A, 0xBF, 0xC1, 0x8D, 0x43, 0x84, 0x3B, 0xF6, 0x32, 0xC6, 0x5D, 0x47, 0x6E, + 0xF3, 0x90, 0x58, 0x5F, 0x1C, 0xFD, 0x43, 0xC4, 0x4D, 0x6C, 0x1E, 0x52, 0x42, 0x6F, 0x37, 0x87, 0xB4, 0x29, 0xE2, 0xDE, 0xF6, 0x0F, 0xDD, 0x4B, 0x93, 0xE6, + 0x20, 0x66, 0xCD, 0x26, 0xE1, 0x9F, 0x68, 0x12, 0x2E, 0xE2, 0x26, 0x3D, 0xBD, 0xCF, 0x1D, 0x51, 0xF7, 0xD2, 0x22, 0x39, 0xB1, 0xF3, 0x99, 0x34, 0xA9, 0xD6, + 0x26, 0x2F, 0x2E, 0xDB, 0xF7, 0xB5, 0xC7, 0x4B, 0x6B, 0x0C, 0x71, 0x2A, 0x43, 0x3D, 0x9D, 0xA7, 0x9E, 0xE6, 0xDE, 0x74, 0x9E, 0x7A, 0xB0, 0x55, 0x75, 0x5E, + 0x96, 0x55, 0x74, 0x7E, 0x83, 0xCA, 0x1E, 0x21, 0xFE, 0x27, 0x53, 0xF8, 0xA8, 0x59, 0x0D, 0x94, 0x5E, 0xDB, 0xAC, 0xCD, 0x6A, 0x48, 0x2C, 0x09, 0x90, 0xCD, + 0xFB, 0xD3, 0x90, 0x02, 0xB9, 0x5D, 0x49, 0x48, 0xA5, 0xCD, 0x19, 0x6E, 0xA6, 0x4F, 0xE2, 0x9E, 0x94, 0xCA, 0x4E, 0x59, 0x3B, 0xED, 0x3C, 0x3A, 0xC2, 0x7E, + 0x19, 0xEE, 0x36, 0xDD, 0x07, 0x7B, 0xEA, 0x6F, 0x26, 0x7D, 0x60, 0xA7, 0x8C, 0x36, 0xBE, 0x2D, 0xE0, 0x07, 0x37, 0x76, 0xCC, 0xB0, 0xBF, 0xB8, 0x99, 0x2F, + 0x96, 0xAD, 0x69, 0x73, 0xFE, 0xD8, 0x6A, 0xD2, 0xAA, 0x12, 0x4C, 0xE2, 0x0E, 0x8B, 0x43, 0xDB, 0xAA, 0x07, 0x1F, 0xE2, 0x96, 0x6B, 0x06, 0xCD, 0x8A, 0x51, + 0x88, 0x8B, 0x15, 0x8D, 0x89, 0xB9, 0x21, 0x94, 0x41, 0x0C, 0x5C, 0x47, 0x76, 0xCD, 0xF0, 0x26, 0x13, 0xFE, 0xAC, 0x9E, 0x27, 0x64, 0x30, 0x82, 0x4F, 0x94, + 0x7E, 0x80, 0xCA, 0x4B, 0x46, 0xC4, 0x09, 0x86, 0x31, 0x6E, 0x5C, 0xC4, 0xA4, 0xA0, 0xDD, 0x1B, 0x09, 0xB0, 0xA0, 0x90, 0x48, 0xF0, 0xFA, 0x9B, 0x9F, 0x75, + 0x34, 0x10, 0xBA, 0x76, 0x90, 0x27, 0x01, 0x36, 0x86, 0xAD, 0xBA, 0x31, 0x1C, 0x19, 0x6A, 0x52, 0x8B, 0x8F, 0x5A, 0x05, 0xB5, 0x8E, 0x26, 0xC9, 0x9E, 0xB1, + 0x75, 0x4C, 0x96, 0x86, 0x02, 0x58, 0x1C, 0x4F, 0xAB, 0x42, 0x8D, 0xEF, 0x55, 0x0D, 0xA8, 0x25, 0x07, 0x18, 0x4B, 0xD7, 0x97, 0x03, 0x0B, 0x24, 0x5B, 0x59, + 0x0C, 0x80, 0xA3, 0x56, 0x0C, 0xEE, 0x8B, 0x06, 0x58, 0x14, 0x4A, 0xCD, 0x6F, 0x2C, 0x06, 0xE8, 0x00, 0x6B, 0x89, 0x01, 0xDA, 0x2E, 0xC4, 0x20, 0xD9, 0x50, + 0x98, 0xAC, 0x18, 0xAA, 0x20, 0x96, 0x22, 0x05, 0x4F, 0x20, 0x05, 0x87, 0x83, 0x27, 0xF5, 0x34, 0x61, 0x73, 0x36, 0xF7, 0x9A, 0xD6, 0x78, 0x34, 0xB5, 0xB7, + 0xBF, 0xD8, 0xAE, 0xE5, 0x5D, 0x37, 0x33, 0xB9, 0x6A, 0x45, 0x9F, 0xBB, 0xB9, 0x6D, 0x36, 0x6A, 0xA5, 0x50, 0x4B, 0x0F, 0x81, 0xA4, 0x4B, 0x84, 0xAD, 0x10, + 0xE4, 0xCC, 0x1F, 0x7B, 0x90, 0xDA, 0x91, 0x14, 0xE5, 0xAE, 0xE7, 0x04, 0xE4, 0xD7, 0x60, 0x7F, 0xF3, 0xB5, 0xB1, 0xC2, 0x8E, 0xF4, 0x82, 0x15, 0xE1, 0xD8, + 0xCB, 0x6C, 0xAC, 0xB0, 0x73, 0xBF, 0xFE, 0x9A, 0x75, 0x3A, 0x45, 0xC1, 0x58, 0xED, 0x18, 0x85, 0xCA, 0xE5, 0xDB, 0x8A, 0xEF, 0xB2, 0x5E, 0xBC, 0x42, 0x68, + 0x2B, 0x7C, 0xAC, 0x7A, 0x7B, 0x6E, 0xB3, 0x02, 0x20, 0x8B, 0x83, 0xA7, 0x58, 0xDE, 0x8E, 0xAB, 0x87, 0xF6, 0x0C, 0x3F, 0x9C, 0x2A, 0xC6, 0x2C, 0xAE, 0xBC, + 0xA1, 0x31, 0x4B, 0xFC, 0x7C, 0x08, 0xD3, 0xD6, 0x07, 0x2F, 0x7F, 0xD7, 0x34, 0x09, 0xF1, 0xDF, 0x55, 0x9B, 0x74, 0x74, 0x5F, 0x4D, 0x5A, 0xA3, 0xAB, 0x8A, + 0xA5, 0x2B, 0xF4, 0x42, 0x3C, 0x9F, 0x70, 0x55, 0xE1, 0x12, 0xA5, 0x21, 0x5B, 0xC2, 0xE6, 0x1A, 0x97, 0x68, 0xEA, 0x46, 0x05, 0x2C, 0x42, 0xA0, 0x1E, 0x33, + 0xE2, 0x48, 0x4B, 0xC2, 0x0C, 0x98, 0x97, 0xCF, 0x4B, 0xBE, 0x44, 0x8B, 0xEA, 0x8A, 0x97, 0xA6, 0x45, 0xB0, 0x66, 0x9F, 0x8F, 0x78, 0xE1, 0x78, 0x32, 0x4A, + 0x5D, 0xD9, 0x78, 0x89, 0xE2, 0x64, 0xBC, 0xF8, 0xD5, 0xE6, 0x05, 0x2C, 0xC6, 0x60, 0x65, 0x7E, 0xE0, 0xC0, 0x93, 0xCF, 0xCC, 0x82, 0x89, 0x26, 0xAD, 0x21, + 0x62, 0x38, 0x36, 0x65, 0x73, 0x22, 0xA6, 0x4C, 0x23, 0xC9, 0x7E, 0x50, 0x3A, 0x30, 0x3C, 0x5A, 0x99, 0x72, 0x68, 0x9A, 0xCC, 0x24, 0xE9, 0x7B, 0xE5, 0xB3, + 0x7D, 0x38, 0x85, 0x9A, 0x23, 0xD7, 0xF4, 0x78, 0x9E, 0x89, 0xC7, 0xBE, 0x15, 0x1C, 0x97, 0x16, 0x1F, 0xD3, 0xC6, 0xE7, 0xB9, 0x92, 0x03, 0x41, 0x63, 0x47, + 0x33, 0x7B, 0x50, 0x68, 0xE5, 0x91, 0x68, 0x67, 0xA6, 0xDC, 0x93, 0x7F, 0x45, 0x73, 0x69, 0x34, 0x29, 0x67, 0xCC, 0x7C, 0x36, 0x39, 0x6F, 0x7D, 0x19, 0xC3, + 0x94, 0xD4, 0xA2, 0x2C, 0x2D, 0x03, 0x26, 0xD9, 0x75, 0x3C, 0x93, 0x9C, 0x55, 0x73, 0x81, 0x7D, 0xFC, 0xAC, 0xFF, 0xDB, 0x82, 0x82, 0xBC, 0xB8, 0x79, 0xB6, + 0x6F, 0xD6, 0x9B, 0xC7, 0xE5, 0x47, 0x8B, 0xCA, 0x99, 0x76, 0xBA, 0x8C, 0x27, 0xF1, 0xFE, 0xEF, 0xFF, 0x55, 0x85, 0x66, 0xE8, 0xE1, 0x7F, 0x09, 0x01, 0x20, + 0x46, 0xFE, 0xF8, 0xBC, 0x05, 0x4C, 0x7D, 0x2F, 0x80, 0x2B, 0x6A, 0x63, 0x92, 0xAE, 0x80, 0x72, 0x05, 0xD4, 0xDE, 0xD7, 0x91, 0x3B, 0x93, 0x59, 0x33, 0x36, + 0x39, 0x0B, 0xC6, 0xBE, 0xBD, 0x80, 0xAB, 0x86, 0xC7, 0x00, 0x2F, 0x71, 0x76, 0x5D, 0xD8, 0x47, 0x44, 0xF5, 0xE2, 0x0A, 0x17, 0xEF, 0x28, 0xC2, 0x0C, 0xCA, + 0x77, 0xDA, 0xAF, 0xBF, 0x7B, 0x4F, 0x07, 0x60, 0x50, 0x1A, 0xE8, 0xC5, 0xAC, 0x76, 0xD7, 0x98, 0x2C, 0x5D, 0xE1, 0xBD, 0x77, 0xB0, 0x6D, 0xC6, 0x0D, 0xC5, + 0x43, 0x18, 0xAF, 0x4C, 0x1F, 0x47, 0x9F, 0x06, 0xEC, 0xAD, 0x17, 0x84, 0xC6, 0x39, 0x08, 0x2C, 0x21, 0xE2, 0x50, 0x47, 0x7E, 0x48, 0x42, 0x5F, 0xB4, 0x4B, + 0xE6, 0x14, 0x0D, 0xFF, 0xC9, 0x77, 0x90, 0x35, 0x2E, 0xB5, 0x67, 0xB4, 0x4F, 0x9F, 0x1E, 0xB6, 0x49, 0xFE, 0xE2, 0x2A, 0x26, 0xF4, 0x58, 0x45, 0xE4, 0xEB, + 0x2C, 0x7D, 0xA7, 0x6B, 0x8C, 0x47, 0xBB, 0xE2, 0x90, 0x44, 0x9E, 0x4C, 0x69, 0xD1, 0xE9, 0xB9, 0xFD, 0x70, 0xC6, 0xDC, 0x4E, 0x82, 0x19, 0x94, 0x61, 0x81, + 0xF9, 0xDC, 0xD4, 0x13, 0x22, 0xED, 0x49, 0x92, 0xDE, 0x87, 0x43, 0x1F, 0xE2, 0xF9, 0x2E, 0x8F, 0xCE, 0xCF, 0x71, 0x6E, 0xE6, 0x41, 0xFA, 0x41, 0x92, 0xE3, + 0x51, 0x36, 0x5F, 0x17, 0xA3, 0xC4, 0x54, 0xC2, 0x8F, 0x30, 0x0D, 0xCA, 0x31, 0xBF, 0x77, 0x06, 0x73, 0x32, 0xE7, 0xCC, 0xC6, 0x05, 0xC8, 0x8A, 0x74, 0x76, + 0xD3, 0x08, 0x76, 0x2C, 0x33, 0x34, 0x65, 0x5B, 0x94, 0x5A, 0x81, 0x49, 0xD7, 0xE0, 0xB7, 0xD4, 0xD3, 0x27, 0xEF, 0x76, 0xFB, 0xA0, 0x21, 0xDA, 0x1B, 0x97, + 0x66, 0xBE, 0x9F, 0x7D, 0xF4, 0x25, 0x4A, 0xF7, 0x0E, 0xBB, 0x06, 0xDD, 0x49, 0x97, 0x55, 0x90, 0x94, 0x57, 0x77, 0x31, 0xD1, 0xCA, 0xC1, 0x6A, 0x40, 0x0A, + 0x70, 0xFC, 0xF0, 0xC9, 0x98, 0xD6, 0xB0, 0x3D, 0x98, 0x04, 0x00, 0xC5, 0x30, 0x11, 0x20, 0x7C, 0xC0, 0x2E, 0x1F, 0x3D, 0x77, 0x85, 0x51, 0x54, 0xB8, 0xB6, + 0xBF, 0x0F, 0x95, 0x86, 0x51, 0x62, 0x90, 0x8A, 0x69, 0xA7, 0x2D, 0x27, 0x30, 0x21, 0x51, 0xED, 0x83, 0x9B, 0xF6, 0x1E, 0x00, 0xE0, 0x44, 0x4C, 0xCC, 0x7D, + 0x63, 0x7A, 0x19, 0x43, 0x8F, 0xDD, 0x04, 0x1A, 0xBF, 0x4D, 0x20, 0x33, 0xF7, 0x79, 0x3A, 0xAF, 0x24, 0x7B, 0xA3, 0x23, 0xD3, 0xF7, 0xDA, 0xBB, 0x6D, 0x89, + 0x3C, 0xFF, 0x0F, 0x71, 0xEB, 0x88, 0x8B, 0x1D, 0x8E, 0xE3, 0xAE, 0x71, 0x76, 0x26, 0xAB, 0x11, 0xB9, 0x28, 0x11, 0x99, 0xF8, 0x4F, 0xE6, 0x56, 0x2C, 0x8A, + 0xBF, 0x7E, 0xF5, 0x47, 0x24, 0xB3, 0x77, 0xFB, 0xC0, 0xFA, 0x39, 0x45, 0x10, 0xBE, 0xFA, 0x03, 0xDF, 0x77, 0x3B, 0x3C, 0x6C, 0xF0, 0xD5, 0x1F, 0xF4, 0x73, + 0xB7, 0x83, 0x9A, 0x70, 0xCD, 0xEB, 0xBB, 0xFB, 0x95, 0xD3, 0x21, 0x4F, 0x3D, 0x44, 0x89, 0x0B, 0xA8, 0x17, 0x93, 0xAD, 0x31, 0x4E, 0x38, 0xF0, 0xBC, 0x10, + 0x29, 0xE0, 0x11, 0xF3, 0x7B, 0x8C, 0xDD, 0xCF, 0x5D, 0x23, 0x84, 0x24, 0x47, 0x4C, 0x77, 0xC0, 0x92, 0x88, 0x50, 0xF1, 0x09, 0xA8, 0xF6, 0x84, 0xE7, 0x34, + 0xA4, 0xAA, 0x24, 0x02, 0x12, 0xE5, 0xC4, 0xC3, 0x2E, 0x02, 0x86, 0x05, 0x28, 0x1D, 0x02, 0x95, 0xC8, 0x5B, 0x01, 0xC5, 0x87, 0xC3, 0x54, 0x13, 0xF8, 0x81, + 0xC4, 0x37, 0x64, 0x33, 0xDA, 0x92, 0x69, 0xB1, 0xB0, 0xC9, 0x5F, 0xC8, 0x61, 0x82, 0xA9, 0xB8, 0x59, 0x20, 0x87, 0x1F, 0x70, 0x1C, 0x63, 0x87, 0xCE, 0x64, + 0xCC, 0x9A, 0x8A, 0x1C, 0x89, 0x28, 0xD3, 0x73, 0xFA, 0x02, 0x5D, 0xE8, 0xA7, 0x90, 0x3F, 0x80, 0x2A, 0x5C, 0xF8, 0x0E, 0x0F, 0x01, 0x7C, 0xBC, 0xE9, 0xC2, + 0x78, 0xD1, 0xC5, 0x2D, 0x34, 0xC3, 0xB5, 0xE8, 0x3F, 0xFD, 0xE0, 0x9F, 0x68, 0x14, 0x25, 0xC8, 0x2B, 0xA4, 0x71, 0x9F, 0x95, 0x92, 0xC4, 0x05, 0xE5, 0xE2, + 0x3E, 0x06, 0xCF, 0x25, 0xAE, 0x90, 0x46, 0x67, 0x7E, 0x40, 0x76, 0xBB, 0xC6, 0xC8, 0x76, 0x5D, 0x7E, 0x51, 0x81, 0x7D, 0xD2, 0xD5, 0x3F, 0x0F, 0x6E, 0xD0, + 0x02, 0x89, 0xDA, 0xDD, 0x4E, 0x70, 0x1B, 0xFF, 0xBB, 0xBD, 0xDB, 0x61, 0x74, 0x8F, 0x23, 0x89, 0x6B, 0xBA, 0xC3, 0x31, 0xBD, 0xDB, 0x01, 0x7E, 0x74, 0x27, + 0x42, 0x98, 0x27, 0xD0, 0xED, 0x08, 0xEF, 0xBB, 0x9D, 0x90, 0xEE, 0x4B, 0xE4, 0xF1, 0x8F, 0x6E, 0xCA, 0x16, 0x20, 0x33, 0x2F, 0x2B, 0x9B, 0x81, 0xBF, 0xBC, + 0xA4, 0x6C, 0x0B, 0x30, 0xE0, 0x0F, 0x74, 0x07, 0x12, 0xA2, 0x4D, 0x77, 0x3B, 0xB2, 0x4D, 0x48, 0x92, 0x57, 0x59, 0x52, 0x93, 0x4D, 0x08, 0xA5, 0x15, 0x79, + 0x29, 0x3A, 0x69, 0xA5, 0xFF, 0x80, 0x7E, 0x5C, 0x38, 0x8C, 0x2E, 0x5F, 0xDE, 0x7E, 0x63, 0x75, 0xDA, 0x72, 0x42, 0xB6, 0x4D, 0x36, 0x4C, 0x2D, 0xD3, 0xF7, + 0xDC, 0xB1, 0x63, 0xE3, 0xF1, 0x31, 0x90, 0xB7, 0x5D, 0xE3, 0x7C, 0x28, 0xED, 0x18, 0x09, 0x34, 0xB2, 0xAB, 0x42, 0x5A, 0x08, 0x3A, 0x9A, 0x52, 0x6C, 0xEF, + 0xF6, 0xB9, 0x1C, 0x4A, 0x59, 0x23, 0x10, 0x52, 0x05, 0xEB, 0xC1, 0xA0, 0xCC, 0x1A, 0x18, 0x39, 0x6D, 0x29, 0x05, 0xC2, 0x73, 0x2B, 0x50, 0x38, 0x18, 0xD5, + 0xD4, 0xA2, 0xA7, 0x48, 0x59, 0xD9, 0x12, 0xAD, 0x8E, 0x14, 0xF8, 0x51, 0x56, 0x81, 0xC1, 0x2A, 0x3F, 0xEC, 0xB4, 0x2F, 0x68, 0x21, 0xF0, 0x3F, 0xDA, 0x7B, + 0x94, 0x69, 0xAF, 0xFD, 0xCF, 0x53, 0xA3, 0xBD, 0xA7, 0x6A, 0xB2, 0xD0, 0x43, 0x45, 0xE5, 0x04, 0xC7, 0x84, 0xE5, 0xAA, 0xE6, 0x98, 0x9C, 0x07, 0xE3, 0x1C, + 0x53, 0xCB, 0xDC, 0x03, 0xC7, 0xD4, 0x89, 0xE0, 0x75, 0xB8, 0xA6, 0xCE, 0xBC, 0x96, 0x70, 0xAE, 0xB2, 0xBC, 0x64, 0x9A, 0xE4, 0x96, 0x6A, 0xDA, 0x63, 0x6E, + 0xAD, 0xC2, 0x26, 0xD1, 0xC5, 0x41, 0x7B, 0x98, 0xFF, 0xF6, 0xC7, 0xF7, 0xEF, 0xC8, 0x54, 0xEA, 0x59, 0x16, 0x73, 0x2C, 0xEB, 0x8E, 0x68, 0x20, 0x50, 0xDF, + 0x99, 0x32, 0xDC, 0xA9, 0x3E, 0x74, 0xAF, 0x6D, 0xA0, 0x0F, 0x45, 0x32, 0xF5, 0xA0, 0x15, 0x82, 0x20, 0x0D, 0x6F, 0x3D, 0xDD, 0x25, 0x63, 0x1B, 0x29, 0x6F, + 0x52, 0xAA, 0x44, 0x16, 0xA8, 0x40, 0x2D, 0x26, 0x0A, 0xC8, 0x39, 0x85, 0x51, 0xFA, 0x84, 0x8D, 0xAB, 0x08, 0xD7, 0xD7, 0xA0, 0xAE, 0x51, 0x8B, 0x6C, 0x7A, + 0x62, 0xDB, 0x64, 0xD1, 0x12, 0xEA, 0x48, 0xCB, 0x5F, 0x8B, 0x40, 0x32, 0x86, 0xAD, 0x11, 0xF0, 0xA8, 0x27, 0xA8, 0x05, 0x26, 0x0A, 0x5D, 0x16, 0xC3, 0xB9, + 0x6D, 0x02, 0xE7, 0x56, 0x03, 0x47, 0xF6, 0x3C, 0xB5, 0xC0, 0xC8, 0x40, 0x57, 0x21, 0x94, 0x7A, 0xC8, 0xC8, 0xE0, 0x92, 0xAE, 0x4D, 0xB2, 0xA7, 0xAB, 0xD7, + 0x26, 0x19, 0x14, 0x29, 0x86, 0x53, 0x93, 0x36, 0x32, 0x12, 0xA1, 0x91, 0xE7, 0xAC, 0x37, 0x02, 0xCB, 0x22, 0x3E, 0xAB, 0xFB, 0x1F, 0x13, 0x13, 0xD6, 0x22, + 0xF9, 0xD9, 0x8A, 0x96, 0x4C, 0xF9, 0xEA, 0x0C, 0x92, 0x70, 0xE6, 0x68, 0x7B, 0x03, 0x3C, 0x72, 0xC0, 0x0C, 0x61, 0x9F, 0x30, 0x8E, 0x67, 0x41, 0x9F, 0x3C, + 0xDC, 0x98, 0x8C, 0xB9, 0x5B, 0x7D, 0x17, 0x08, 0x70, 0x80, 0xBB, 0xA7, 0xD2, 0x8D, 0x4D, 0xC4, 0x33, 0x07, 0x4B, 0x24, 0x17, 0x81, 0x13, 0x77, 0x0B, 0x20, + 0xCA, 0x1E, 0x26, 0x5D, 0x82, 0x12, 0x8B, 0xA0, 0xF1, 0x51, 0x8C, 0x02, 0x0B, 0xAB, 0x98, 0xF3, 0xFD, 0x8C, 0xAC, 0x40, 0x3E, 0xFA, 0x89, 0x20, 0x50, 0x3C, + 0x2A, 0x19, 0x9A, 0x8D, 0xE1, 0x08, 0x1A, 0xED, 0x68, 0xCA, 0xAE, 0x7D, 0x9A, 0xF3, 0xB8, 0x51, 0x42, 0x4E, 0xC2, 0x19, 0xCF, 0x05, 0x8E, 0xA9, 0x07, 0x1A, + 0x8C, 0x30, 0xF8, 0x8E, 0x9F, 0x5B, 0x24, 0x80, 0xF1, 0x85, 0xD5, 0x31, 0x24, 0x91, 0x46, 0x03, 0xD7, 0x4C, 0x92, 0x98, 0xDB, 0xE9, 0xE1, 0x69, 0x04, 0xFA, + 0x5A, 0x53, 0xFE, 0xBB, 0xAC, 0x48, 0xFE, 0x93, 0x2B, 0xBE, 0x93, 0x62, 0x3E, 0x43, 0xE0, 0xC5, 0x95, 0xFE, 0x7C, 0xDE, 0xBF, 0xD1, 0x0E, 0x25, 0x37, 0x28, + 0x9B, 0xFB, 0xFB, 0xC6, 0x8B, 0x30, 0x34, 0xC1, 0x00, 0x9A, 0xA7, 0x9C, 0x11, 0x7D, 0x0C, 0x31, 0x65, 0x4C, 0x11, 0x58, 0x12, 0x4A, 0xB1, 0xA8, 0x18, 0x14, + 0x21, 0xBD, 0xA5, 0xC7, 0x3C, 0x45, 0xEA, 0xCC, 0x41, 0xF5, 0xFF, 0xB5, 0x64, 0xFE, 0xED, 0x25, 0x27, 0x98, 0xE7, 0xBF, 0x70, 0x9C, 0x4E, 0x9B, 0x44, 0x53, + 0x4E, 0x3B, 0x73, 0x1B, 0x8F, 0x4C, 0x00, 0x75, 0x81, 0x3A, 0xC0, 0xE3, 0x44, 0xE6, 0xA3, 0x58, 0x85, 0xE4, 0x3B, 0xC6, 0x5D, 0xE8, 0xAE, 0x39, 0x33, 0xB2, + 0x83, 0x7E, 0xE4, 0xF0, 0xDC, 0x4F, 0xEC, 0x16, 0xA7, 0x18, 0x9C, 0x27, 0xB4, 0x61, 0x99, 0xC0, 0x82, 0xA4, 0x0E, 0xEB, 0x23, 0xE7, 0x2B, 0x39, 0x90, 0x3B, + 0x3C, 0xD2, 0x64, 0x4A, 0x58, 0xC0, 0xA5, 0x93, 0x34, 0x31, 0xFF, 0x14, 0x8C, 0x68, 0x54, 0x96, 0xFD, 0xA7, 0x09, 0x81, 0x48, 0x04, 0x25, 0xF1, 0xA2, 0xCE, + 0x2B, 0x53, 0x43, 0x26, 0x3C, 0x81, 0xE0, 0x44, 0x62, 0x19, 0x96, 0x0B, 0x04, 0x43, 0x58, 0xDA, 0x38, 0xC4, 0xB2, 0x10, 0xDD, 0x9C, 0x7B, 0x21, 0x74, 0x23, + 0x65, 0x31, 0x6C, 0x17, 0x0F, 0xF7, 0x31, 0x1D, 0x5E, 0x6A, 0x03, 0xEA, 0xAF, 0xD1, 0xF1, 0x06, 0xFA, 0x9F, 0x8B, 0x41, 0xD4, 0x1B, 0x37, 0xE7, 0x24, 0x24, + 0xB6, 0x07, 0x89, 0x94, 0xA8, 0x74, 0x48, 0x99, 0x05, 0x79, 0x3F, 0xAA, 0xE9, 0xD1, 0x23, 0x7E, 0x25, 0x53, 0x15, 0xEB, 0x71, 0x2E, 0xB2, 0x08, 0xCE, 0xA4, + 0x19, 0x9C, 0x87, 0x9D, 0x81, 0x11, 0x01, 0x57, 0x20, 0x08, 0xDD, 0x8A, 0xD9, 0xBB, 0x80, 0xB7, 0x49, 0xB2, 0xF0, 0xFF, 0xAD, 0xFE, 0x67, 0x64, 0xF5, 0x1F, + 0xCE, 0xC4, 0xD7, 0x8F, 0xC2, 0x89, 0x72, 0xFA, 0xB0, 0xE0, 0x1E, 0xE2, 0x85, 0xFA, 0xB8, 0x9F, 0x34, 0xDD, 0x89, 0x7C, 0x61, 0xDA, 0x40, 0x20, 0x9D, 0x48, + 0x16, 0xD1, 0x88, 0xC2, 0xF7, 0x14, 0xE0, 0xA6, 0x68, 0x77, 0xA7, 0x2D, 0xE6, 0x16, 0xB8, 0x3D, 0x26, 0x14, 0xA5, 0x4B, 0x32, 0xC3, 0x9C, 0x6D, 0x49, 0x49, + 0x1F, 0x56, 0xE7, 0x8A, 0x65, 0x0A, 0xC7, 0xA5, 0xE5, 0xB3, 0xDA, 0x2B, 0xAB, 0x8E, 0x9E, 0xE9, 0x2E, 0x3B, 0x03, 0x64, 0x88, 0x9F, 0xF2, 0x7E, 0x8E, 0xC7, + 0xC4, 0x71, 0xAD, 0x51, 0xC0, 0x32, 0xFE, 0x98, 0xE6, 0x3A, 0x68, 0x95, 0x02, 0xE6, 0x6E, 0x5E, 0x1A, 0xB2, 0x30, 0xA5, 0x0D, 0x8C, 0xAC, 0x9A, 0x8C, 0x12, + 0xE9, 0xBF, 0xE7, 0x86, 0xBB, 0x74, 0x1C, 0xC8, 0x20, 0x35, 0x01, 0x32, 0xA8, 0xDE, 0xD5, 0x9A, 0xE8, 0xFF, 0x5C, 0x7B, 0x16, 0x63, 0x9E, 0xA2, 0xC0, 0xCE, + 0x4E, 0x1A, 0x1A, 0x4D, 0x32, 0x08, 0x37, 0x3E, 0xAE, 0x4D, 0xE4, 0xC7, 0xCC, 0x0A, 0x66, 0x6E, 0x92, 0x7E, 0x56, 0xA2, 0x84, 0xCE, 0xFA, 0x51, 0x8A, 0xF0, + 0x8A, 0x8F, 0x03, 0x44, 0xF0, 0x5C, 0x33, 0x22, 0x10, 0x3F, 0xA9, 0x2F, 0x17, 0x8D, 0x7D, 0xCE, 0xA5, 0xBE, 0xC3, 0xE4, 0x19, 0x5E, 0xBB, 0xA0, 0x3F, 0x09, + 0x73, 0x92, 0x90, 0x0E, 0x11, 0x64, 0x20, 0xE2, 0x28, 0x26, 0x05, 0x22, 0x35, 0x2C, 0x83, 0x37, 0xB7, 0x50, 0x04, 0x8F, 0x4E, 0xB3, 0x91, 0x27, 0xEA, 0xA8, + 0x4F, 0x30, 0xE4, 0x95, 0x03, 0x0C, 0x9D, 0xB8, 0xA3, 0x74, 0xED, 0x79, 0xDF, 0x80, 0x67, 0x2C, 0x00, 0xC2, 0x2B, 0xC8, 0x03, 0x29, 0xC5, 0x3C, 0x3A, 0xCE, + 0x54, 0x43, 0x10, 0x0E, 0xEE, 0x7A, 0x44, 0xA4, 0xE0, 0xB5, 0xE2, 0xB2, 0x10, 0x94, 0x91, 0xD9, 0xCB, 0x98, 0x03, 0x37, 0xC4, 0xA3, 0xD7, 0x23, 0x98, 0xC8, + 0xFA, 0x86, 0xE6, 0xEE, 0x63, 0xC8, 0x71, 0x42, 0xDA, 0xA9, 0xCC, 0x05, 0x95, 0x55, 0xEE, 0x8B, 0xAE, 0x2F, 0xE9, 0xF7, 0x12, 0xF1, 0xBA, 0xA7, 0x9E, 0xE0, + 0x90, 0xBA, 0x01, 0xAD, 0xBD, 0x5E, 0xB3, 0x13, 0x28, 0x81, 0x29, 0x26, 0x5B, 0xB3, 0x40, 0x97, 0xA3, 0xB9, 0x9D, 0x8C, 0x28, 0x12, 0x80, 0x6D, 0x4C, 0xFA, + 0x35, 0xE8, 0x4F, 0x54, 0xDD, 0x13, 0xF6, 0x8B, 0xBB, 0xDA, 0x00, 0x94, 0x0A, 0x92, 0xF3, 0x63, 0xF3, 0x3D, 0xE7, 0x39, 0xE6, 0x1B, 0x29, 0xF4, 0x4D, 0x0C, + 0xCE, 0x4C, 0xC9, 0x08, 0x10, 0x62, 0x2E, 0x91, 0x83, 0x48, 0xCF, 0x26, 0x46, 0x33, 0x78, 0x69, 0xCF, 0x5C, 0x9D, 0xC2, 0xFA, 0xD5, 0x67, 0x28, 0x07, 0x04, + 0xB0, 0x96, 0xF7, 0xAB, 0x3F, 0x38, 0x88, 0x3B, 0x63, 0x02, 0xDD, 0x0F, 0x66, 0xCC, 0xE2, 0x13, 0x05, 0x98, 0x2A, 0x3C, 0xC5, 0xAD, 0xCC, 0xEC, 0xE1, 0xDD, + 0xAF, 0xB1, 0x84, 0xC4, 0x5D, 0x47, 0xE5, 0xE0, 0x81, 0x4F, 0x32, 0x97, 0x8F, 0x1B, 0x84, 0xBB, 0xAD, 0x09, 0x15, 0xC5, 0x1A, 0x87, 0x1C, 0xE2, 0xD1, 0xE4, + 0xDF, 0xC2, 0x1B, 0xC9, 0x88, 0x29, 0x3C, 0x6F, 0x3E, 0xEC, 0x01, 0x07, 0xAC, 0xC8, 0x80, 0x09, 0x1E, 0xD1, 0xE0, 0x46, 0x90, 0x29, 0x45, 0x61, 0xD1, 0x18, + 0xD9, 0x96, 0xEA, 0x19, 0x58, 0xD9, 0xAB, 0xC7, 0xB4, 0xF8, 0x2D, 0xC0, 0x60, 0x45, 0x14, 0x96, 0x53, 0x92, 0x59, 0x18, 0x54, 0x81, 0x02, 0x20, 0x45, 0xA2, + 0x22, 0x32, 0xA5, 0x77, 0x16, 0x4B, 0x7A, 0x95, 0x8E, 0xB5, 0x22, 0x6B, 0x1C, 0x0D, 0x49, 0x04, 0xE3, 0xD8, 0x3F, 0xB8, 0xC8, 0xFC, 0x53, 0xC6, 0x45, 0x14, + 0x3B, 0x14, 0x5D, 0xD6, 0x42, 0x27, 0x37, 0xE4, 0xAB, 0x40, 0xE5, 0x1E, 0x9D, 0x5F, 0x65, 0xEC, 0xC7, 0xE1, 0xC1, 0xC5, 0xCC, 0x0D, 0xFA, 0x54, 0x0F, 0x4D, + 0x3F, 0xC2, 0x4B, 0x8F, 0xC1, 0x14, 0xF2, 0x68, 0xBD, 0xB3, 0x42, 0x72, 0x09, 0xE9, 0x12, 0xEA, 0x7A, 0x65, 0x33, 0xF2, 0xAE, 0x4A, 0x02, 0x95, 0xB4, 0x3A, + 0x80, 0xD3, 0x2B, 0x29, 0x40, 0xAB, 0x10, 0xC4, 0x6A, 0x90, 0xCA, 0x92, 0xC9, 0xCA, 0x11, 0x05, 0x06, 0x5F, 0x16, 0x52, 0x6F, 0xB6, 0x82, 0x67, 0x4D, 0x15, + 0x25, 0xA8, 0xD5, 0x65, 0x53, 0x9B, 0xB9, 0x95, 0xF2, 0x5C, 0x73, 0xAB, 0x8B, 0xAB, 0xAB, 0x48, 0xD4, 0xDA, 0xB1, 0x28, 0xA5, 0x46, 0x08, 0x39, 0x5E, 0xFA, + 0xA2, 0x14, 0x8D, 0xFA, 0xA3, 0xB2, 0x82, 0xF1, 0xE9, 0x03, 0x28, 0xA7, 0xB4, 0xD8, 0x5B, 0x88, 0x5D, 0xE8, 0x19, 0x43, 0x82, 0xE5, 0xE0, 0x88, 0x3E, 0xC2, + 0x8C, 0x79, 0x8B, 0x8E, 0x74, 0x5A, 0x54, 0xEA, 0xA4, 0xA7, 0x18, 0xD4, 0xDD, 0xEC, 0x64, 0xE1, 0xD5, 0x98, 0x1F, 0xDD, 0xD2, 0xD6, 0x40, 0xBC, 0xEE, 0x63, + 0x41, 0x8C, 0x30, 0xE7, 0xF1, 0x42, 0x11, 0xB2, 0x36, 0x74, 0xF9, 0xAB, 0xA8, 0x93, 0xBA, 0xDF, 0x94, 0x54, 0x08, 0x29, 0x2B, 0xC3, 0xC5, 0x5B, 0x64, 0x51, + 0x49, 0x42, 0x3C, 0x42, 0x43, 0x03, 0xB2, 0xE3, 0xF2, 0x24, 0x00, 0x0A, 0xC1, 0x27, 0x12, 0x53, 0x60, 0x56, 0x13, 0x32, 0x49, 0x3B, 0x96, 0x46, 0x5E, 0xE9, + 0x8B, 0xC4, 0x2A, 0xA3, 0xE7, 0x1F, 0xC7, 0x23, 0x74, 0x3F, 0xAF, 0xA1, 0x3E, 0xD0, 0xD7, 0xEB, 0xCE, 0x2E, 0xFA, 0xA0, 0xE2, 0xE6, 0x08, 0x72, 0x25, 0xB2, + 0x53, 0x17, 0x09, 0x6E, 0xE8, 0xF5, 0xD0, 0x52, 0xF4, 0xD1, 0x83, 0x53, 0x45, 0xFE, 0x82, 0x8F, 0x38, 0xC8, 0x6D, 0x2E, 0x22, 0x2C, 0x39, 0xEA, 0x19, 0xD2, + 0x0A, 0xBF, 0x31, 0x05, 0x20, 0x31, 0xE1, 0x39, 0x64, 0x33, 0xAE, 0xA1, 0x22, 0x17, 0x51, 0x86, 0x18, 0xF7, 0x58, 0x0F, 0x0A, 0x30, 0xA7, 0x85, 0x45, 0x63, + 0xD3, 0xBD, 0x32, 0x03, 0x55, 0xDE, 0xC7, 0x80, 0x15, 0x32, 0x29, 0xF2, 0x1D, 0xAC, 0xF7, 0xA2, 0x0C, 0x2D, 0x29, 0xBB, 0xE2, 0x5F, 0x9F, 0xEF, 0xC4, 0x20, + 0xD7, 0x9E, 0xD8, 0xC7, 0xFF, 0xA4, 0x6E, 0x8B, 0x07, 0xBF, 0x46, 0xF7, 0xC5, 0x3F, 0x91, 0x21, 0xAE, 0x85, 0x1E, 0xB5, 0xDA, 0x37, 0x17, 0x0B, 0xCC, 0xB0, + 0xBF, 0x9A, 0xD9, 0x8E, 0xD5, 0x11, 0x45, 0xE3, 0xB5, 0x27, 0xC0, 0x8C, 0x56, 0x51, 0xF1, 0x75, 0x0E, 0x12, 0x2A, 0x14, 0x91, 0xAF, 0xAC, 0xC2, 0xEA, 0xA0, + 0xF6, 0x00, 0x43, 0x35, 0x59, 0xA5, 0x48, 0xEA, 0x5B, 0x38, 0x04, 0xED, 0x1B, 0x5A, 0x06, 0xC7, 0x39, 0xD9, 0x3D, 0xE8, 0x1E, 0xC8, 0x0C, 0x21, 0x3C, 0x9D, + 0x88, 0x5A, 0x04, 0x97, 0x96, 0x0B, 0xFD, 0xF4, 0x03, 0xC9, 0xB8, 0x84, 0x1B, 0x7A, 0x90, 0x2F, 0x4A, 0xEA, 0xB4, 0xF9, 0x3A, 0xBA, 0xFD, 0xDF, 0x16, 0x34, + 0xFB, 0x1A, 0xD9, 0x78, 0x85, 0x8C, 0xB4, 0x44, 0x8E, 0x48, 0x25, 0xB2, 0x47, 0x19, 0x38, 0x50, 0x24, 0xBB, 0x30, 0xD2, 0x24, 0xA9, 0x91, 0x9E, 0xA7, 0x8A, + 0x46, 0x0B, 0xE8, 0xA8, 0x38, 0xB5, 0xE4, 0x6B, 0x8C, 0xF8, 0xFE, 0xCE, 0x4C, 0x1F, 0xFC, 0xD8, 0x33, 0x3A, 0xD8, 0x56, 0xB0, 0xD7, 0xE1, 0xE9, 0xEF, 0xD1, + 0x9C, 0x59, 0x67, 0x77, 0xEF, 0x70, 0x77, 0x97, 0x1E, 0xAC, 0x3E, 0x66, 0x9D, 0xDE, 0x20, 0xCA, 0x82, 0x1F, 0x9E, 0x47, 0x54, 0x52, 0x7C, 0xFF, 0xAD, 0x87, + 0x67, 0x08, 0x97, 0x65, 0x78, 0x6F, 0xBB, 0xD4, 0x0D, 0x96, 0x65, 0xB9, 0x64, 0x20, 0xAC, 0x95, 0xCB, 0xD2, 0xE2, 0xEB, 0xFE, 0xA2, 0xC1, 0x17, 0x5F, 0x0E, + 0x05, 0x7F, 0x5B, 0xF1, 0xB4, 0xA5, 0xB3, 0x87, 0x35, 0x50, 0x9E, 0x8F, 0x1B, 0x6A, 0x28, 0x43, 0x92, 0x3B, 0x71, 0xA7, 0xE4, 0xF0, 0x3B, 0xC7, 0xFF, 0x8C, + 0xAD, 0x91, 0x0E, 0x4A, 0x2E, 0xAC, 0x5C, 0xC7, 0x07, 0xD4, 0x3A, 0x37, 0xA5, 0xCE, 0x60, 0x3A, 0xF6, 0x9A, 0x1D, 0x76, 0xA6, 0x1D, 0xBF, 0x57, 0x4B, 0xA8, + 0xE7, 0x3C, 0x32, 0x86, 0x22, 0x8D, 0xC6, 0x60, 0xB1, 0xD5, 0xC6, 0x98, 0xAC, 0xAC, 0x2B, 0xC1, 0x6D, 0xA5, 0xF3, 0x91, 0x03, 0xB8, 0x8A, 0x02, 0xCA, 0x71, + 0xBB, 0x4A, 0x59, 0x65, 0x60, 0x58, 0xDA, 0x59, 0x67, 0x0F, 0x88, 0xE5, 0x20, 0x00, 0x35, 0xDF, 0x72, 0x35, 0x6E, 0x21, 0xDB, 0x8F, 0x7C, 0x82, 0x00, 0x64, + 0xAF, 0xA8, 0x90, 0x1C, 0x33, 0x29, 0xD6, 0xAA, 0x60, 0xA4, 0x9B, 0x1F, 0xE5, 0x66, 0xCC, 0x58, 0xD1, 0xE8, 0x36, 0x3F, 0xB2, 0x8D, 0xCD, 0x1B, 0x68, 0x1D, + 0x1D, 0xBC, 0x9D, 0x90, 0x90, 0x95, 0xD3, 0x9B, 0xA9, 0xF4, 0x8E, 0x46, 0xF8, 0x15, 0x25, 0xD4, 0xF3, 0xC1, 0x05, 0xB9, 0x58, 0x4D, 0x72, 0x31, 0x49, 0x2E, + 0x2A, 0x90, 0x0C, 0x2F, 0xAB, 0xC3, 0x0D, 0xB1, 0xFC, 0xFF, 0xF2, 0x32, 0x69, 0xD9, 0xF5, 0xA8, 0x14, 0x4F, 0x39, 0x9C, 0x57, 0x9A, 0x57, 0x5E, 0x20, 0xF5, + 0x10, 0x11, 0xD1, 0xAC, 0xEB, 0x51, 0xBD, 0x66, 0x45, 0xE1, 0x00, 0x2A, 0x90, 0x34, 0x4B, 0x1F, 0x34, 0x88, 0x9A, 0xF2, 0x9A, 0x85, 0x72, 0x07, 0x9B, 0xE9, + 0x5A, 0x46, 0xFC, 0xD8, 0xDB, 0x18, 0xD9, 0x38, 0xA5, 0x0C, 0xE7, 0x38, 0x93, 0xF0, 0xBC, 0xE2, 0xBF, 0xB5, 0xD0, 0x8E, 0x73, 0x27, 0x22, 0x9C, 0x00, 0x88, + 0x42, 0x15, 0x98, 0x5B, 0x48, 0x07, 0x9C, 0x84, 0x0F, 0x6F, 0x71, 0xEC, 0x33, 0x9E, 0xBA, 0x9A, 0x01, 0x87, 0x56, 0x7A, 0x53, 0x17, 0x90, 0x52, 0x79, 0x84, + 0xA8, 0x0A, 0x6B, 0x11, 0xAF, 0x29, 0x96, 0x2B, 0x88, 0xC5, 0x3F, 0xF1, 0xC0, 0x71, 0x1C, 0x4C, 0x11, 0xCE, 0x9D, 0xE1, 0x17, 0xFF, 0x06, 0x6E, 0xDA, 0x6F, + 0xC1, 0x5F, 0xA4, 0x00, 0x00 }; //File: index_ov3660.html.gz, Size: 8636 diff --git a/libraries/ESP32/examples/RMT/RMTLoopback/RMTLoopback.ino b/libraries/ESP32/examples/RMT/RMTLoopback/RMTLoopback.ino index 17e7af290bf..5d0406aee0e 100644 --- a/libraries/ESP32/examples/RMT/RMTLoopback/RMTLoopback.ino +++ b/libraries/ESP32/examples/RMT/RMTLoopback/RMTLoopback.ino @@ -1,4 +1,4 @@ -// Copyright 2023 Espressif Systems (Shanghai) PTE LTD +// Copyright 2025 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -35,14 +35,11 @@ rmt_data_t my_data[256]; rmt_data_t data[256]; -static EventGroupHandle_t events; - #define RMT_FREQ 10000000 // tick time is 100ns -#define RMT_NUM_EXCHANGED_DATA 30 +#define RMT_NUM_EXCHANGED_DATA 32 void setup() { Serial.begin(115200); - events = xEventGroupCreate(); if (!rmtInit(RMT_TX_PIN, RMT_TX_MODE, RMT_MEM_NUM_BLOCKS_1, RMT_FREQ)) { Serial.println("init sender failed\n"); @@ -50,25 +47,41 @@ void setup() { if (!rmtInit(RMT_RX_PIN, RMT_RX_MODE, RMT_MEM_RX, RMT_FREQ)) { Serial.println("init receiver failed\n"); } + Serial.println(); + Serial.println("RMT tick set to: 100ns"); // End of transmission shall be detected when line is idle for 2us = 20*100ns rmtSetRxMaxThreshold(RMT_RX_PIN, 20); // Disable Glitch filter rmtSetRxMinThreshold(RMT_RX_PIN, 0); - Serial.println("real tick set to: 100ns"); - Serial.printf("\nPlease connect GPIO %d to GPIO %d, now.\n", RMT_TX_PIN, RMT_RX_PIN); -} - -void loop() { - // Init data - int i; - for (i = 0; i < 255; i++) { - data[i].val = 0x80010001 + ((i % 13) << 16) + 13 - (i % 13); + // create multiple pulses with different width to be sent + for (int i = 0; i < 255; i++) { + data[i].level0 = 1; // HIGH + data[i].duration0 = 1 + 13 - (i % 13); // number of Tick on High + data[i].level1 = 0; // LOW + data[i].duration1 = 1 + (i % 13); // number of Ticks on Low my_data[i].val = 0; } data[255].val = 0; + Serial.println(); + Serial.println("===================================================================================================="); + Serial.println("Preloaded Data that will sent (time in 0.1us):"); + // Printout the received data plus the original values + for (int i = 0; i < RMT_NUM_EXCHANGED_DATA; i++) { + Serial.printf("%08lx=[%c 0x%02x|%c 0x%02x] ", data[i].val, data[i].level0 ? 'H' : 'L', data[i].duration0, data[i].level1 ? 'H' : 'L', data[i].duration1); + if (!((i + 1) % 4)) { + Serial.println(); + } + } + Serial.println("===================================================================================================="); + Serial.printf("Please connect GPIO %d to GPIO %d, now.", RMT_TX_PIN, RMT_RX_PIN); + Serial.println(); + Serial.println(); +} + +void loop() { // Start an async data read size_t rx_num_symbols = RMT_NUM_EXCHANGED_DATA; rmtReadAsync(RMT_RX_PIN, my_data, &rx_num_symbols); @@ -84,13 +97,13 @@ void loop() { Serial.printf("Got %d RMT symbols\n", rx_num_symbols); // Printout the received data plus the original values - for (i = 0; i < 60; i++) { + for (int i = 0; i < RMT_NUM_EXCHANGED_DATA; i++) { Serial.printf("%08lx=%08lx ", my_data[i].val, data[i].val); if (!((i + 1) % 4)) { - Serial.println(""); + Serial.println(); } } - Serial.println("\n"); + Serial.println(); - delay(500); + delay(2000); } diff --git a/libraries/ESP32/examples/RMT/RMTReadXJT/RMTReadXJT.ino b/libraries/ESP32/examples/RMT/RMTReadXJT/RMTReadXJT.ino index d9e86ce8399..762225bcdf5 100644 --- a/libraries/ESP32/examples/RMT/RMTReadXJT/RMTReadXJT.ino +++ b/libraries/ESP32/examples/RMT/RMTReadXJT/RMTReadXJT.ino @@ -13,7 +13,7 @@ // limitations under the License. /** - * @brief This example demonstrates usage of RMT for receiving XJT D12 data + * @brief This example demonstrates usage of RMT for receiving XJT D16 data * * The output is the RMT data read and processed * @@ -21,7 +21,7 @@ // // Note: This example uses a FrSKY device communication -// using XJT D12 protocol +// using XJT D16 protocol // // ; 0 bit = 6us low/10us high // ; 1 bit = 14us low/10us high diff --git a/libraries/ESP32/examples/RMT/RMT_LED_Blink/RMT_LED_Blink.ino b/libraries/ESP32/examples/RMT/RMT_LED_Blink/RMT_LED_Blink.ino index 8c2b8db3cd1..1cdd2224ea5 100644 --- a/libraries/ESP32/examples/RMT/RMT_LED_Blink/RMT_LED_Blink.ino +++ b/libraries/ESP32/examples/RMT/RMT_LED_Blink/RMT_LED_Blink.ino @@ -1,4 +1,4 @@ -// Copyright 2023 Espressif Systems (Shanghai) PTE LTD +// Copyright 2025 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,16 +13,16 @@ // limitations under the License. /** - * @brief This example demonstrate how to use RMT to just blink a regular LED (GPIO) - * It uses all the different RMT Writing APIs to blink the LED by hardware, not being - * necessary the regular Blink code in Arduino. - * - * The output is the Blinking LED in the GPIO and a serial output describing what is - * going on, along the execution. - * - * The circuit is just a LED and a resistor of 270 ohms connected to the GPIO - * GPIO ---> resistor 270 ohms ---> + LED - ---> GND - */ + @brief This example demonstrate how to use RMT to just blink a regular LED (GPIO) + It uses all the different RMT Writing APIs to blink the LED by hardware, not being + necessary the regular Blink code in Arduino. + + The output is the Blinking LED in the GPIO and a serial output describing what is + going on, along the execution. + + The circuit is just a LED and a resistor of 270 ohms connected to the GPIO + GPIO ---> resistor 270 ohms ---> + LED - ---> GND +*/ #define BLINK_GPIO 2 @@ -232,7 +232,7 @@ void RMT_Mixed_Write_Blink() { Serial.println("===> rmtWrite() (Blocking Mode) to Blink the LED."); Serial.println("Blinking at 500ms on + 500ms off :: 4 blinks"); for (uint8_t i = 0; i < 4; i++) { - if (!rmtWrite(BLINK_GPIO, blink_500ms_rmt_data, RMT_SYMBOLS_OF(blink_500ms_rmt_data) - 2, RMT_WAIT_FOR_EVER)) { + if (!rmtWrite(BLINK_GPIO, blink_500ms_rmt_data, RMT_SYMBOLS_OF(blink_500ms_rmt_data) - 1, RMT_WAIT_FOR_EVER)) { Serial.println("===> rmtWrite Blink 0.5s Error!"); } } @@ -240,7 +240,7 @@ void RMT_Mixed_Write_Blink() { Serial.println("===> rmtWriteAsync() (Non-Blocking Mode) to Blink the LED."); Serial.println("Blinking at 250ms on + 250ms off :: 5 blinks"); for (uint8_t i = 0; i < 5; i++) { - if (!rmtWriteAsync(BLINK_GPIO, blink_250ms_rmt_data, RMT_SYMBOLS_OF(blink_250ms_rmt_data) - 2)) { + if (!rmtWriteAsync(BLINK_GPIO, blink_250ms_rmt_data, RMT_SYMBOLS_OF(blink_250ms_rmt_data) - 1)) { Serial.println("===> rmtWrite Blink 0.25s Error!"); } // wait (blocks) until all the data is sent out @@ -267,9 +267,11 @@ void RMT_Loop_Write_Blink() { Serial.println("===> rmtWriteLooping Blink 0.25s Error!"); } delay(5000); + Serial.println("Blinking OFF for 2 seconds"); - if (!rmtWriteLooping(BLINK_GPIO, NULL, 0)) { - Serial.println("===> rmtWriteLooping Blink OFF Error!"); + rmt_data_t blink_STOP_rmt_data[] = {{0, 0, 0, 0}}; + if (!rmtWrite(BLINK_GPIO, blink_STOP_rmt_data, RMT_SYMBOLS_OF(blink_STOP_rmt_data), RMT_WAIT_FOR_EVER)) { + Serial.println("===> rmtWrite Blink STOP Error!"); } delay(2000); } @@ -278,19 +280,19 @@ void RMT_Single_Write_Blocking_Blink() { Serial.println("Using RMT Writing and its Completion to blink an LED."); Serial.println("Blinking at 1s on + 1s off :: 2 blinks"); for (uint8_t i = 0; i < 2; i++) { - if (!rmtWrite(BLINK_GPIO, blink_1s_rmt_data, RMT_SYMBOLS_OF(blink_1s_rmt_data) - 2, RMT_WAIT_FOR_EVER)) { + if (!rmtWrite(BLINK_GPIO, blink_1s_rmt_data, RMT_SYMBOLS_OF(blink_1s_rmt_data) - 1, RMT_WAIT_FOR_EVER)) { Serial.println("===> rmtWrite Blink 1s Error!"); } } Serial.println("Blinking at 500ms on + 500ms off :: 4 blinks"); for (uint8_t i = 0; i < 4; i++) { - if (!rmtWrite(BLINK_GPIO, blink_500ms_rmt_data, RMT_SYMBOLS_OF(blink_500ms_rmt_data) - 2, RMT_WAIT_FOR_EVER)) { + if (!rmtWrite(BLINK_GPIO, blink_500ms_rmt_data, RMT_SYMBOLS_OF(blink_500ms_rmt_data) - 1, RMT_WAIT_FOR_EVER)) { Serial.println("===> rmtWrite Blink 0.5s Error!"); } } Serial.println("Blinking at 250ms on + 250ms off :: 8 blinks"); for (uint8_t i = 0; i < 8; i++) { - if (!rmtWrite(BLINK_GPIO, blink_250ms_rmt_data, RMT_SYMBOLS_OF(blink_250ms_rmt_data) - 2, RMT_WAIT_FOR_EVER)) { + if (!rmtWrite(BLINK_GPIO, blink_250ms_rmt_data, RMT_SYMBOLS_OF(blink_250ms_rmt_data) - 1, RMT_WAIT_FOR_EVER)) { Serial.println("===> rmtWrite Blink 0.25s Error!"); } } @@ -302,7 +304,7 @@ void RMT_Write_Aync_Non_Blocking_Blink() { Serial.println("Using RMT Async Writing and its Completion to blink an LED."); Serial.println("Blinking at 1s on + 1s off :: 5 blinks"); for (uint8_t i = 0; i < 5; i++) { - if (!rmtWriteAsync(BLINK_GPIO, blink_1s_rmt_data, RMT_SYMBOLS_OF(blink_1s_rmt_data) - 2)) { + if (!rmtWriteAsync(BLINK_GPIO, blink_1s_rmt_data, RMT_SYMBOLS_OF(blink_1s_rmt_data) - 1)) { Serial.println("===> rmtWrite Blink 1s Error!"); } // wait (blocks) until all the data is sent out @@ -310,7 +312,7 @@ void RMT_Write_Aync_Non_Blocking_Blink() { } Serial.println("Blinking at 500ms on + 500ms off :: 5 blinks"); for (uint8_t i = 0; i < 5; i++) { - if (!rmtWriteAsync(BLINK_GPIO, blink_500ms_rmt_data, RMT_SYMBOLS_OF(blink_500ms_rmt_data) - 2)) { + if (!rmtWriteAsync(BLINK_GPIO, blink_500ms_rmt_data, RMT_SYMBOLS_OF(blink_500ms_rmt_data) - 1)) { Serial.println("===> rmtWrite Blink 0.5s Error!"); } // wait (blocks) until all the data is sent out @@ -318,7 +320,7 @@ void RMT_Write_Aync_Non_Blocking_Blink() { } Serial.println("Blinking at 250ms on + 250ms off :: 5 blinks"); for (uint8_t i = 0; i < 5; i++) { - if (!rmtWriteAsync(BLINK_GPIO, blink_250ms_rmt_data, RMT_SYMBOLS_OF(blink_250ms_rmt_data) - 2)) { + if (!rmtWriteAsync(BLINK_GPIO, blink_250ms_rmt_data, RMT_SYMBOLS_OF(blink_250ms_rmt_data) - 1)) { Serial.println("===> rmtWrite Blink 0.25s Error!"); } // wait (blocks) until all the data is sent out @@ -345,7 +347,6 @@ void setup() { RMT_Mixed_Write_Blink(); Serial.println("End of Mixed Calls testing"); - delay(1000); Serial.println("\n==============================="); Serial.println("Starting a Blinking sequence..."); diff --git a/libraries/ESP32/examples/Serial/RxTimeout_Demo/RxTimeout_Demo.ino b/libraries/ESP32/examples/Serial/RxTimeout_Demo/RxTimeout_Demo.ino index 64d15d3d916..35d2da5c199 100644 --- a/libraries/ESP32/examples/Serial/RxTimeout_Demo/RxTimeout_Demo.ino +++ b/libraries/ESP32/examples/Serial/RxTimeout_Demo/RxTimeout_Demo.ino @@ -21,6 +21,15 @@ If UART receives less than 120 bytes, it will wait RX Timeout to understand that the bus is IDLE and then copy the data from the FIFO to the Arduino internal buffer, making it available to the Arduino API. + There is an important detail about how HardwareSerial works using ESP32 and ESP32-S2: + If the baud rate is lower than 250,000, it will select REF_TICK as clock source in order to avoid that + the baud rate may change when the CPU Frequency is changed. Default UART clock source is APB, which changes + when CPU clock source is also changed. But when it selects REF_TICK as UART clock source, RX Timeout is limited to 1. + Therefore, in order to change the ESP32/ESP32-S2 RX Timeout it is necessary to fix the UART Clock Source to APB. + + In the case of the other SoC, such as ESP32-S3, C3, C6, H2 and P4, there is no such RX Timeout limitation. + Those will set the UART Source Clock as XTAL, which allows the baud rate to be high and it is steady, not + changing with the CPU Frequency. */ #include @@ -45,6 +54,12 @@ void setup() { // UART1 will have its RX<->TX cross connected // GPIO4 <--> GPIO5 using external wire +#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 + // UART_CLK_SRC_APB will allow higher values of RX Timeout + // default for ESP32 and ESP32-S2 is REF_TICK which limits the RX Timeout to 1 + // setClockSource() must be called before begin() + Serial1.setClockSource(UART_CLK_SRC_APB); +#endif Serial1.begin(BAUD, SERIAL_8N1, RXPIN, TXPIN); // Rx = 4, Tx = 5 will work for ESP32, S2, S3 and C3 #if USE_INTERNAL_PIN_LOOPBACK uart_internal_loopback(TEST_UART, RXPIN); diff --git a/libraries/ESP32/examples/Serial/onReceiveExample/onReceiveExample.ino b/libraries/ESP32/examples/Serial/onReceiveExample/onReceiveExample.ino index fe66b07b875..17d800b3b39 100644 --- a/libraries/ESP32/examples/Serial/onReceiveExample/onReceiveExample.ino +++ b/libraries/ESP32/examples/Serial/onReceiveExample/onReceiveExample.ino @@ -5,20 +5,20 @@ void HardwareSerial::onReceive(OnReceiveCb function, bool onlyOnTimeout = false) It is possible to register an UART callback function that will be called - every time that UART receives data and an associated interrupt is generated. + every time that UART receives data and an associated UART interrupt is generated. - In summary, HardwareSerial::onReceive() works like an RX Interrupt callback, that can be adjusted - using HardwareSerial::setRxFIFOFull() and HardwareSerial::setRxTimeout(). + In summary, HardwareSerial::onReceive() works like an RX Interrupt callback, that + can be adjusted using HardwareSerial::setRxFIFOFull() and HardwareSerial::setRxTimeout(). - OnReceive will be called, while receiving a stream of data, when every 120 bytes are received (default FIFO Full), - which may not help in case that the application needs to get all data at once before processing it. - Therefore, a way to make it work is by detecting the end of a stream transmission. This can be based on a protocol - or based on timeout with the UART line in idle (no data received - this is the case of this example). + In case that is not changed or it is set to , the callback function is + executed whenever any event happens first (FIFO Full or RX Timeout). + OnReceive will be called when every 120 bytes are received(default FIFO Full), + or when RX Timeout occurs after 1 UART symbol by default. - In some cases, it is necessary to wait for receiving all the data before processing it and parsing the - UART input. This example demonstrates a way to create a String with all data received from UART0 and - signaling it using a Mutex for another task to process it. This example uses a timeout of 500ms as a way to - know when the reception of data has finished. + This example demonstrates a way to create a String with all data received from UART0 only + after RX Timeout. This example uses an RX timeout of about 3.5 Symbols as a way to know + when the reception of data has finished. + In order to achieve it, the sketch sets to . The onReceive() callback is called whenever the RX ISR is triggered. It can occur because of two possible events: @@ -34,90 +34,73 @@ 2- UART RX Timeout: it happens, based on a timeout equivalent to a number of symbols at the current baud rate. If the UART line is idle for this timeout, it will raise an interrupt. - This time can be changed by HardwareSerial::setRxTimeout(uint8_t rxTimeout) + This time can be changed by HardwareSerial::setRxTimeout(uint8_t rxTimeout). + is bound to the clock source. + In order to use it properly, ESP32 and ESP32-S2 shall set the UART Clock Source to APB. When any of those two interrupts occur, IDF UART driver will copy FIFO data to its internal RingBuffer and then Arduino can read such data. At the same time, Arduino Layer will execute the callback function defined with HardwareSerial::onReceive(). - parameter (default false) can be used by the application to tell Arduino to - only execute the callback when the second event above happens (Rx Timeout). At this time all - received data will be available to be read by the Arduino application. But if the number of - received bytes is higher than the FIFO space, it will generate an error of FIFO overflow. - In order to avoid such problem, the application shall set an appropriate RX buffer size using + parameter can be used by the application to tell Arduino to only execute + the callback when Rx Timeout happens, by setting it to . + At this time all received data will be available to be read by the Arduino application. + The application shall set an appropriate RX buffer size using HardwareSerial::setRxBufferSize(size_t new_size) before executing begin() for the Serial port. -*/ -// this will make UART0 work in any case (using or not USB) -#if ARDUINO_USB_CDC_ON_BOOT -#define UART0 Serial0 -#else -#define UART0 Serial -#endif + MODBUS timeout of 3.5 symbol is based on these documents: + https://www.automation.com/en-us/articles/2012-1/introduction-to-modbus + https://minimalmodbus.readthedocs.io/en/stable/serialcommunication.html +*/ // global variable to keep the results from onReceive() String uart_buffer = ""; -// a pause of a half second in the UART transmission is considered the end of transmission. -const uint32_t communicationTimeout_ms = 500; - -// Create a mutex for the access to uart_buffer -// only one task can read/write it at a certain time -SemaphoreHandle_t uart_buffer_Mutex = NULL; - -// UART_RX_IRQ will be executed as soon as data is received by the UART -// This is a callback function executed from a high priority -// task created when onReceive() is used +// The Modbus RTU standard prescribes a silent period corresponding to 3.5 characters between each +// message, to be able to figure out where one message ends and the next one starts. +const uint32_t modbusRxTimeoutLimit = 4; +const uint32_t baudrate = 19200; + +// UART_RX_IRQ will be executed as soon as data is received by the UART and an RX Timeout occurs +// This is a callback function executed from a high priority monitor task +// All data will be buffered into RX Buffer, which may have its size set to whatever necessary void UART0_RX_CB() { - // take the mutex, waits forever until loop() finishes its processing - if (xSemaphoreTake(uart_buffer_Mutex, portMAX_DELAY)) { - uint32_t now = millis(); // tracks timeout - while ((millis() - now) < communicationTimeout_ms) { - if (UART0.available()) { - uart_buffer += (char)UART0.read(); - now = millis(); // reset the timer - } - } - // releases the mutex for data processing - xSemaphoreGive(uart_buffer_Mutex); + while (Serial0.available()) { + uart_buffer += (char)Serial0.read(); } } // setup() and loop() are functions executed by a low priority task // Therefore, there are 2 tasks running when using onReceive() void setup() { - UART0.begin(115200); - - // creates a mutex object to control access to uart_buffer - uart_buffer_Mutex = xSemaphoreCreateMutex(); - if (uart_buffer_Mutex == NULL) { - log_e("Error creating Mutex. Sketch will fail."); - while (true) { - UART0.println("Mutex error (NULL). Program halted."); - delay(2000); - } - } - - UART0.onReceive(UART0_RX_CB); // sets the callback function - UART0.println("Send data to UART0 in order to activate the RX callback"); + // Using Serial0 will work in any case (using or not USB CDC on Boot) +#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 + // UART_CLK_SRC_APB will allow higher values of RX Timeout + // default for ESP32 and ESP32-S2 is REF_TICK which limits the RX Timeout to 1 + // setClockSource() must be called before begin() + Serial0.setClockSource(UART_CLK_SRC_APB); +#endif + // the amount of data received or waiting to be proessed shall not exceed this limit of 1024 bytes + Serial0.setRxBufferSize(1024); // default is 256 bytes + Serial0.begin(baudrate); // default pins and default mode 8N1 (8 bits data, no parity bit, 1 stopbit) + // set RX Timeout based on UART symbols ~ 3.5 symbols of 11 bits (MODBUS standard) ~= 2 ms at 19200 + Serial0.setRxTimeout(modbusRxTimeoutLimit); // 4 symbols at 19200 8N1 is about 2.08 ms (40 bits) + // sets the callback function that will be executed only after RX Timeout + Serial0.onReceive(UART0_RX_CB, true); + Serial0.println("Send data using Serial Monitor in order to activate the RX callback"); } uint32_t counter = 0; void loop() { + // String is filled by the UART Callback whenever data is received and RX Timeout occurs if (uart_buffer.length() > 0) { - // signals that the onReceive function shall not change uart_buffer while processing - if (xSemaphoreTake(uart_buffer_Mutex, portMAX_DELAY)) { - // process the received data from UART0 - example, just print it beside a counter - UART0.print("["); - UART0.print(counter++); - UART0.print("] ["); - UART0.print(uart_buffer.length()); - UART0.print(" bytes] "); - UART0.println(uart_buffer); - uart_buffer = ""; // reset uart_buffer for the next UART reading - // releases the mutex for more data to be received - xSemaphoreGive(uart_buffer_Mutex); - } + // process the received data from Serial - example, just print it beside a counter + Serial0.print("["); + Serial0.print(counter++); + Serial0.print("] ["); + Serial0.print(uart_buffer.length()); + Serial0.print(" bytes] "); + Serial0.println(uart_buffer); + uart_buffer = ""; // reset uart_buffer for the next UART reading } - UART0.println("Sleeping for 1 second..."); - delay(1000); + delay(1); } diff --git a/libraries/ESP_SR/src/esp32-hal-sr.c b/libraries/ESP_SR/src/esp32-hal-sr.c index 06db7236541..eb87ef636c1 100644 --- a/libraries/ESP_SR/src/esp32-hal-sr.c +++ b/libraries/ESP_SR/src/esp32-hal-sr.c @@ -192,6 +192,7 @@ static void audio_feed_task(void *arg) { /* Feed samples of an audio stream to the AFE_SR */ g_sr_data->afe_handle->feed(g_sr_data->afe_data, audio_buffer); + vTaskDelay(2); } vTaskDelete(NULL); } diff --git a/libraries/Ethernet/src/ETH.cpp b/libraries/Ethernet/src/ETH.cpp index 542a7e2a218..3dfba37c684 100644 --- a/libraries/Ethernet/src/ETH.cpp +++ b/libraries/Ethernet/src/ETH.cpp @@ -124,7 +124,8 @@ void ETHClass::_onEthEvent(int32_t event_id, void *event_data) { } ETHClass::ETHClass(uint8_t eth_index) - : _eth_handle(NULL), _eth_index(eth_index), _phy_type(ETH_PHY_MAX), _glue_handle(NULL), _mac(NULL), _phy(NULL) + : _eth_handle(NULL), _eth_index(eth_index), _phy_type(ETH_PHY_MAX), _glue_handle(NULL), _mac(NULL), _phy(NULL), _eth_started(false), _link_speed(100), + _full_duplex(true), _auto_negotiation(true) #if ETH_SPI_SUPPORTS_CUSTOM , _spi(NULL) @@ -136,7 +137,7 @@ ETHClass::ETHClass(uint8_t eth_index) _pin_mcd(-1), _pin_mdio(-1), _pin_power(-1), _pin_rmii_clock(-1) #endif /* CONFIG_ETH_USE_ESP32_EMAC */ , - _task_stack_size(4096) { + _task_stack_size(4096), _eth_connected_event_handle(0) { } ETHClass::~ETHClass() {} @@ -351,6 +352,19 @@ bool ETHClass::begin(eth_phy_type_t type, int32_t phy_addr, int mdc, int mdio, i return false; } + // auto negotiation needs to be disabled to change duplex mode and link speed + if (!_auto_negotiation) { + if (!_setAutoNegotiation(_auto_negotiation)) { + return false; + } + if (!_setFullDuplex(_full_duplex)) { + return false; + } + if (!_setLinkSpeed(_link_speed)) { + return false; + } + } + if (_eth_ev_instance == NULL && esp_event_handler_instance_register(ETH_EVENT, ESP_EVENT_ANY_ID, &_eth_event_cb, NULL, &_eth_ev_instance)) { log_e("event_handler_instance_register for ETH_EVENT Failed!"); return false; @@ -359,7 +373,7 @@ bool ETHClass::begin(eth_phy_type_t type, int32_t phy_addr, int mdc, int mdio, i /* attach to receive events */ initNetif((Network_Interface_ID)(ESP_NETIF_ID_ETH + _eth_index)); - Network.onSysEvent(onEthConnected, ARDUINO_EVENT_ETH_CONNECTED); + _eth_connected_event_handle = Network.onSysEvent(onEthConnected, ARDUINO_EVENT_ETH_CONNECTED); ret = esp_eth_start(_eth_handle); if (ret != ESP_OK) { @@ -367,6 +381,8 @@ bool ETHClass::begin(eth_phy_type_t type, int32_t phy_addr, int mdc, int mdio, i return false; } + _eth_started = true; + if (!perimanSetPinBus(_pin_rmii_clock, ESP32_BUS_TYPE_ETHERNET_CLK, (void *)(this), -1, -1)) { goto err; } @@ -788,6 +804,19 @@ bool ETHClass::beginSPI( return false; } + // auto negotiation needs to be disabled to change duplex mode and link speed + if (!_auto_negotiation) { + if (!_setAutoNegotiation(_auto_negotiation)) { + return false; + } + if (!_setFullDuplex(_full_duplex)) { + return false; + } + if (!_setLinkSpeed(_link_speed)) { + return false; + } + } + if (_eth_ev_instance == NULL && esp_event_handler_instance_register(ETH_EVENT, ESP_EVENT_ANY_ID, &_eth_event_cb, NULL, &_eth_ev_instance)) { log_e("event_handler_instance_register for ETH_EVENT Failed!"); return false; @@ -803,6 +832,8 @@ bool ETHClass::beginSPI( return false; } + _eth_started = true; + // If Arduino's SPI is used, cs pin is in GPIO mode #if ETH_SPI_SUPPORTS_CUSTOM if (_spi == NULL) { @@ -849,7 +880,7 @@ bool ETHClass::beginSPI( perimanSetPinBusExtraType(_pin_rst, "ETH_RST"); } - Network.onSysEvent(onEthConnected, ARDUINO_EVENT_ETH_CONNECTED); + _eth_connected_event_handle = Network.onSysEvent(onEthConnected, ARDUINO_EVENT_ETH_CONNECTED); return true; @@ -885,7 +916,8 @@ static bool empty_ethDetachBus(void *bus_pointer) { void ETHClass::end(void) { - Network.removeEvent(onEthConnected, ARDUINO_EVENT_ETH_CONNECTED); + Network.removeEvent(_eth_connected_event_handle); + _eth_connected_event_handle = 0; if (_eth_handle != NULL) { if (esp_eth_stop(_eth_handle) != ESP_OK) { @@ -896,6 +928,9 @@ void ETHClass::end(void) { while (getStatusBits() & ESP_NETIF_STARTED_BIT) { delay(10); } + + _eth_started = false; + //delete glue first if (_glue_handle != NULL) { if (esp_eth_del_netif_glue(_glue_handle) != ESP_OK) { @@ -1009,7 +1044,7 @@ bool ETHClass::fullDuplex() const { return (link_duplex == ETH_DUPLEX_FULL); } -bool ETHClass::setFullDuplex(bool on) { +bool ETHClass::_setFullDuplex(bool on) { if (_eth_handle == NULL) { return false; } @@ -1021,6 +1056,18 @@ bool ETHClass::setFullDuplex(bool on) { return err == ESP_OK; } +bool ETHClass::setFullDuplex(bool on) { + if (_eth_started) { + log_e("This method must be called before ETH.begin()"); + return false; + } + if (_auto_negotiation) { + log_w("Auto Negotiation MUST be OFF for this setting to be applied"); + } + _full_duplex = on; + return true; +} + bool ETHClass::autoNegotiation() const { if (_eth_handle == NULL) { return false; @@ -1030,7 +1077,7 @@ bool ETHClass::autoNegotiation() const { return auto_nego; } -bool ETHClass::setAutoNegotiation(bool on) { +bool ETHClass::_setAutoNegotiation(bool on) { if (_eth_handle == NULL) { return false; } @@ -1041,6 +1088,15 @@ bool ETHClass::setAutoNegotiation(bool on) { return err == ESP_OK; } +bool ETHClass::setAutoNegotiation(bool on) { + if (_eth_started) { + log_e("This method must be called before ETH.begin()"); + return false; + } + _auto_negotiation = on; + return true; +} + uint32_t ETHClass::phyAddr() const { if (_eth_handle == NULL) { return 0; @@ -1059,7 +1115,7 @@ uint16_t ETHClass::linkSpeed() const { return (link_speed == ETH_SPEED_10M) ? 10 : 100; } -bool ETHClass::setLinkSpeed(uint16_t speed) { +bool ETHClass::_setLinkSpeed(uint16_t speed) { if (_eth_handle == NULL) { return false; } @@ -1071,6 +1127,22 @@ bool ETHClass::setLinkSpeed(uint16_t speed) { return err == ESP_OK; } +bool ETHClass::setLinkSpeed(uint16_t speed) { + if (speed != 10 && speed != 100) { + log_e("Ethernet currently supports only 10 or 100 Mbps link speed"); + return false; + } + if (_eth_started) { + log_e("This method must be called before ETH.begin()"); + return false; + } + if (_auto_negotiation) { + log_w("Auto Negotiation MUST be OFF for this setting to be applied"); + } + _link_speed = speed; + return true; +} + // void ETHClass::getMac(uint8_t* mac) // { // if(_eth_handle != NULL && mac != NULL){ diff --git a/libraries/Ethernet/src/ETH.h b/libraries/Ethernet/src/ETH.h index 891863e34bf..c52aac6ec6f 100644 --- a/libraries/Ethernet/src/ETH.h +++ b/libraries/Ethernet/src/ETH.h @@ -229,6 +229,10 @@ class ETHClass : public NetworkInterface { esp_eth_netif_glue_handle_t _glue_handle; esp_eth_mac_t *_mac; esp_eth_phy_t *_phy; + bool _eth_started; + uint16_t _link_speed; + bool _full_duplex; + bool _auto_negotiation; #if ETH_SPI_SUPPORTS_CUSTOM SPIClass *_spi; char _cs_str[10]; @@ -247,6 +251,7 @@ class ETHClass : public NetworkInterface { int8_t _pin_rmii_clock; #endif /* CONFIG_ETH_USE_ESP32_EMAC */ size_t _task_stack_size; + network_event_handle_t _eth_connected_event_handle; static bool ethDetachBus(void *bus_pointer); bool beginSPI( @@ -256,6 +261,9 @@ class ETHClass : public NetworkInterface { #endif int sck, int miso, int mosi, spi_host_device_t spi_host, uint8_t spi_freq_mhz ); + bool _setFullDuplex(bool on); + bool _setLinkSpeed(uint16_t speed); + bool _setAutoNegotiation(bool on); friend class EthernetClass; // to access beginSPI }; diff --git a/libraries/NetworkClientSecure/src/NetworkClientSecure.cpp b/libraries/NetworkClientSecure/src/NetworkClientSecure.cpp index 87917e58b8f..b24c9f1adc3 100644 --- a/libraries/NetworkClientSecure/src/NetworkClientSecure.cpp +++ b/libraries/NetworkClientSecure/src/NetworkClientSecure.cpp @@ -315,9 +315,10 @@ int NetworkClientSecure::available() { } uint8_t NetworkClientSecure::connected() { - uint8_t dummy = 0; - read(&dummy, 0); - + if (_connected) { + uint8_t dummy = 0; + read(&dummy, 0); + } return _connected; } diff --git a/libraries/PPP/src/PPP.cpp b/libraries/PPP/src/PPP.cpp index 77b70d3969c..87fee6920c3 100644 --- a/libraries/PPP/src/PPP.cpp +++ b/libraries/PPP/src/PPP.cpp @@ -152,7 +152,8 @@ esp_modem_dce_t *PPPClass::handle() const { PPPClass::PPPClass() : _dce(NULL), _pin_tx(-1), _pin_rx(-1), _pin_rts(-1), _pin_cts(-1), _flow_ctrl(ESP_MODEM_FLOW_CONTROL_NONE), _pin_rst(-1), _pin_rst_act_low(true), - _pin_rst_delay(200), _pin(NULL), _apn(NULL), _rx_buffer_size(4096), _tx_buffer_size(512), _mode(ESP_MODEM_MODE_COMMAND), _uart_num(UART_NUM_1) {} + _pin_rst_delay(200), _pin(NULL), _apn(NULL), _rx_buffer_size(4096), _tx_buffer_size(512), _mode(ESP_MODEM_MODE_COMMAND), _uart_num(UART_NUM_1), + _ppp_event_handle(0) {} PPPClass::~PPPClass() {} @@ -360,7 +361,7 @@ bool PPPClass::begin(ppp_modem_model_t model, uint8_t uart_num, int baud_rate) { } } - Network.onSysEvent(onPppArduinoEvent); + _ppp_event_handle = Network.onSysEvent(onPppArduinoEvent); setStatusBits(ESP_NETIF_STARTED_BIT); arduino_event_t arduino_event; @@ -402,7 +403,8 @@ void PPPClass::end(void) { } _esp_modem = NULL; - Network.removeEvent(onPppArduinoEvent); + Network.removeEvent(_ppp_event_handle); + _ppp_event_handle = 0; if (_dce != NULL) { esp_modem_destroy(_dce); diff --git a/libraries/PPP/src/PPP.h b/libraries/PPP/src/PPP.h index b8e1f7ad56f..b317f52aefc 100644 --- a/libraries/PPP/src/PPP.h +++ b/libraries/PPP/src/PPP.h @@ -108,6 +108,7 @@ class PPPClass : public NetworkInterface { int _tx_buffer_size; esp_modem_dce_mode_t _mode; uint8_t _uart_num; + network_event_handle_t _ppp_event_handle; static bool pppDetachBus(void *bus_pointer); }; diff --git a/libraries/RainMaker/examples/RMakerCustom/ci.json b/libraries/RainMaker/examples/RMakerCustom/ci.json index 1c80eda1d90..ce63fe9ccf0 100644 --- a/libraries/RainMaker/examples/RMakerCustom/ci.json +++ b/libraries/RainMaker/examples/RMakerCustom/ci.json @@ -1,4 +1,7 @@ { + "targets": { + "esp32": false + }, "fqbn_append": "PartitionScheme=rainmaker_4MB", "requires": [ "CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK=[1-9][0-9]*" diff --git a/libraries/RainMaker/examples/RMakerSwitch/ci.json b/libraries/RainMaker/examples/RMakerSwitch/ci.json index 1c80eda1d90..ce63fe9ccf0 100644 --- a/libraries/RainMaker/examples/RMakerSwitch/ci.json +++ b/libraries/RainMaker/examples/RMakerSwitch/ci.json @@ -1,4 +1,7 @@ { + "targets": { + "esp32": false + }, "fqbn_append": "PartitionScheme=rainmaker_4MB", "requires": [ "CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK=[1-9][0-9]*" diff --git a/libraries/SPI/src/SPI.cpp b/libraries/SPI/src/SPI.cpp index 35e52f43e4d..ae207a7ff3c 100644 --- a/libraries/SPI/src/SPI.cpp +++ b/libraries/SPI/src/SPI.cpp @@ -144,6 +144,12 @@ void SPIClass::setHwCs(bool use) { _use_hw_ss = use; } +void SPIClass::setSSInvert(bool invert) { + if (_spi) { + spiSSInvert(_spi, invert); + } +} + void SPIClass::setFrequency(uint32_t freq) { SPI_PARAM_LOCK(); //check if last freq changed diff --git a/libraries/SPI/src/SPI.h b/libraries/SPI/src/SPI.h index adb3d1bc11f..628c2190f50 100644 --- a/libraries/SPI/src/SPI.h +++ b/libraries/SPI/src/SPI.h @@ -65,6 +65,7 @@ class SPIClass { void end(); void setHwCs(bool use); + void setSSInvert(bool invert); //use before setHwCS for change to be used by setHwCs void setBitOrder(uint8_t bitOrder); void setDataMode(uint8_t dataMode); void setFrequency(uint32_t freq); diff --git a/libraries/USB/src/USBHIDConsumerControl.h b/libraries/USB/src/USBHIDConsumerControl.h index e65e529a77b..7a59c70b6b1 100644 --- a/libraries/USB/src/USBHIDConsumerControl.h +++ b/libraries/USB/src/USBHIDConsumerControl.h @@ -37,10 +37,14 @@ #define CONSUMER_CONTROL_WIRELESS_RADIO_SLIDER_SWITCH 0x00C8 // Media Control -#define CONSUMER_CONTROL_PLAY_PAUSE 0x00CD +#define CONSUMER_CONTROL_RECORD 0x00B2 +#define CONSUMER_CONTROL_FAST_FORWARD 0x00B3 +#define CONSUMER_CONTROL_REWIND 0x00B4 #define CONSUMER_CONTROL_SCAN_NEXT 0x00B5 #define CONSUMER_CONTROL_SCAN_PREVIOUS 0x00B6 #define CONSUMER_CONTROL_STOP 0x00B7 +#define CONSUMER_CONTROL_EJECT 0x00B8 +#define CONSUMER_CONTROL_PLAY_PAUSE 0x00CD #define CONSUMER_CONTROL_VOLUME 0x00E0 #define CONSUMER_CONTROL_MUTE 0x00E2 #define CONSUMER_CONTROL_BASS 0x00E3 diff --git a/libraries/USB/src/keyboardLayout/KeyboardLayout.h b/libraries/USB/src/keyboardLayout/KeyboardLayout.h index 0ef69dc7ab9..ee6b6b4e11e 100644 --- a/libraries/USB/src/keyboardLayout/KeyboardLayout.h +++ b/libraries/USB/src/keyboardLayout/KeyboardLayout.h @@ -5,7 +5,7 @@ only in Keyboard.cpp and the keyboard layout files. Layout files map ASCII character codes to keyboard scan codes (technically, to USB HID Usage codes), possibly altered by the SHIFT or ALT_GR modifiers. - Non-ACSII characters (anything outside the 7-bit range NUL..DEL) are + Non-ASCII characters (anything outside the 7-bit range NUL..DEL) are not supported. == Creating your own layout == diff --git a/libraries/WiFi/src/AP.cpp b/libraries/WiFi/src/AP.cpp index b713a6d3901..0e7839764ea 100644 --- a/libraries/WiFi/src/AP.cpp +++ b/libraries/WiFi/src/AP.cpp @@ -148,7 +148,7 @@ void APClass::_onApEvent(int32_t event_id, void *event_data) { } } -APClass::APClass() { +APClass::APClass() : _wifi_ap_event_handle(0) { _ap_network_if = this; } @@ -163,7 +163,7 @@ bool APClass::onEnable() { return false; } if (_esp_netif == NULL) { - Network.onSysEvent(_onApArduinoEvent); + _wifi_ap_event_handle = Network.onSysEvent(_onApArduinoEvent); _esp_netif = get_esp_interface_netif(ESP_IF_WIFI_AP); /* attach to receive events */ initNetif(ESP_NETIF_ID_AP); @@ -172,7 +172,8 @@ bool APClass::onEnable() { } bool APClass::onDisable() { - Network.removeEvent(_onApArduinoEvent); + Network.removeEvent(_wifi_ap_event_handle); + _wifi_ap_event_handle = 0; // we just set _esp_netif to NULL here, so destroyNetif() does not try to destroy it. // That would be done by WiFi.enableAP(false) if STA is not enabled, or when it gets disabled _esp_netif = NULL; diff --git a/libraries/WiFi/src/STA.cpp b/libraries/WiFi/src/STA.cpp index 547a27d1c47..84258589b28 100644 --- a/libraries/WiFi/src/STA.cpp +++ b/libraries/WiFi/src/STA.cpp @@ -228,7 +228,8 @@ void STAClass::_onStaEvent(int32_t event_id, void *event_data) { } STAClass::STAClass() - : _minSecurity(WIFI_AUTH_WPA2_PSK), _scanMethod(WIFI_FAST_SCAN), _sortMethod(WIFI_CONNECT_AP_BY_SIGNAL), _autoReconnect(true), _status(WL_STOPPED) { + : _minSecurity(WIFI_AUTH_WPA2_PSK), _scanMethod(WIFI_FAST_SCAN), _sortMethod(WIFI_CONNECT_AP_BY_SIGNAL), _autoReconnect(true), _status(WL_STOPPED), + _wifi_sta_event_handle(0) { _sta_network_if = this; } @@ -276,14 +277,15 @@ bool STAClass::onEnable() { return false; } /* attach to receive events */ - Network.onSysEvent(_onStaArduinoEvent); + _wifi_sta_event_handle = Network.onSysEvent(_onStaArduinoEvent); initNetif(ESP_NETIF_ID_STA); } return true; } bool STAClass::onDisable() { - Network.removeEvent(_onStaArduinoEvent); + Network.removeEvent(_wifi_sta_event_handle); + _wifi_sta_event_handle = 0; // we just set _esp_netif to NULL here, so destroyNetif() does not try to destroy it. // That would be done by WiFi.enableSTA(false) if AP is not enabled, or when it gets disabled _esp_netif = NULL; diff --git a/libraries/WiFi/src/WiFiAP.h b/libraries/WiFi/src/WiFiAP.h index e80f91fa26c..540ec87f44f 100644 --- a/libraries/WiFi/src/WiFiAP.h +++ b/libraries/WiFi/src/WiFiAP.h @@ -60,6 +60,8 @@ class APClass : public NetworkInterface { void _onApEvent(int32_t event_id, void *event_data); protected: + network_event_handle_t _wifi_ap_event_handle; + size_t printDriverInfo(Print &out) const; friend class WiFiGenericClass; diff --git a/libraries/WiFi/src/WiFiGeneric.cpp b/libraries/WiFi/src/WiFiGeneric.cpp index aa994963514..3faf34fef34 100644 --- a/libraries/WiFi/src/WiFiGeneric.cpp +++ b/libraries/WiFi/src/WiFiGeneric.cpp @@ -602,9 +602,9 @@ bool WiFiGenericClass::mode(wifi_mode_t m) { #else #define WIFI_PROTOCOL_DEFAULT (WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N) #endif - uint8_t current_protocol = 0; + uint32_t current_protocol = 0; if (m & WIFI_MODE_STA) { - err = esp_wifi_get_protocol(WIFI_IF_STA, ¤t_protocol); + err = esp_wifi_get_protocol(WIFI_IF_STA, (uint8_t *)¤t_protocol); if (err == ESP_OK && current_protocol == WIFI_PROTOCOL_LR) { log_v("Disabling long range on STA"); err = esp_wifi_set_protocol(WIFI_IF_STA, WIFI_PROTOCOL_DEFAULT); @@ -614,7 +614,7 @@ bool WiFiGenericClass::mode(wifi_mode_t m) { } } if (m & WIFI_MODE_AP) { - err = esp_wifi_get_protocol(WIFI_IF_AP, ¤t_protocol); + err = esp_wifi_get_protocol(WIFI_IF_AP, (uint8_t *)¤t_protocol); if (err == ESP_OK && current_protocol == WIFI_PROTOCOL_LR) { log_v("Disabling long range on AP"); err = esp_wifi_set_protocol(WIFI_IF_AP, WIFI_PROTOCOL_DEFAULT); diff --git a/libraries/WiFi/src/WiFiSTA.h b/libraries/WiFi/src/WiFiSTA.h index 3c8adbd8502..6063eae7968 100644 --- a/libraries/WiFi/src/WiFiSTA.h +++ b/libraries/WiFi/src/WiFiSTA.h @@ -95,6 +95,7 @@ class STAClass : public NetworkInterface { wifi_sort_method_t _sortMethod; bool _autoReconnect; wl_status_t _status; + network_event_handle_t _wifi_sta_event_handle; size_t printDriverInfo(Print &out) const; diff --git a/libraries/WiFi/src/WiFiScan.cpp b/libraries/WiFi/src/WiFiScan.cpp index 27d9edcc70c..086b875fcb2 100644 --- a/libraries/WiFi/src/WiFiScan.cpp +++ b/libraries/WiFi/src/WiFiScan.cpp @@ -92,9 +92,6 @@ int16_t } if (esp_wifi_scan_start(&config, false) == ESP_OK) { _scanStarted = millis(); - if (!_scanStarted) { //Prevent 0 from millis overflow - ++_scanStarted; - } WiFiGenericClass::clearStatusBits(WIFI_SCAN_DONE_BIT); WiFiGenericClass::setStatusBits(WIFI_SCANNING_BIT); @@ -118,21 +115,20 @@ int16_t void WiFiScanClass::_scanDone() { esp_wifi_scan_get_ap_num(&(WiFiScanClass::_scanCount)); if (WiFiScanClass::_scanResult) { - delete[] reinterpret_cast(WiFiScanClass::_scanResult); - WiFiScanClass::_scanResult = nullptr; + free(WiFiScanClass::_scanResult); + WiFiScanClass::_scanResult = NULL; } if (WiFiScanClass::_scanCount) { - WiFiScanClass::_scanResult = new (std::nothrow) wifi_ap_record_t[WiFiScanClass::_scanCount]; + WiFiScanClass::_scanResult = calloc(WiFiScanClass::_scanCount, sizeof(wifi_ap_record_t)); if (!WiFiScanClass::_scanResult) { WiFiScanClass::_scanCount = 0; } else if (esp_wifi_scan_get_ap_records(&(WiFiScanClass::_scanCount), (wifi_ap_record_t *)_scanResult) != ESP_OK) { - delete[] reinterpret_cast(WiFiScanClass::_scanResult); - WiFiScanClass::_scanResult = nullptr; + free(WiFiScanClass::_scanResult); + WiFiScanClass::_scanResult = NULL; WiFiScanClass::_scanCount = 0; } } - WiFiScanClass::_scanStarted = 0; //Reset after a scan is completed for normal behavior WiFiGenericClass::setStatusBits(WIFI_SCAN_DONE_BIT); WiFiGenericClass::clearStatusBits(WIFI_SCANNING_BIT); } @@ -161,15 +157,13 @@ int16_t WiFiScanClass::scanComplete() { } if (WiFiGenericClass::getStatusBits() & WIFI_SCANNING_BIT) { + // Check if the delay expired, return WIFI_SCAN_FAILED in this case + if ((millis() - WiFiScanClass::_scanStarted) > WiFiScanClass::_scanTimeout) { + WiFiGenericClass::clearStatusBits(WIFI_SCANNING_BIT); + return WIFI_SCAN_FAILED; + } return WIFI_SCAN_RUNNING; } - // last one to avoid time affecting Async mode - if (WiFiScanClass::_scanStarted - && (millis() - WiFiScanClass::_scanStarted) - > WiFiScanClass::_scanTimeout) { //Check is scan was started and if the delay expired, return WIFI_SCAN_FAILED in this case - WiFiGenericClass::clearStatusBits(WIFI_SCANNING_BIT); - return WIFI_SCAN_FAILED; - } return WIFI_SCAN_FAILED; } @@ -179,11 +173,12 @@ int16_t WiFiScanClass::scanComplete() { */ void WiFiScanClass::scanDelete() { WiFiGenericClass::clearStatusBits(WIFI_SCAN_DONE_BIT); + WiFiGenericClass::clearStatusBits(WIFI_SCANNING_BIT); if (WiFiScanClass::_scanResult) { - delete[] reinterpret_cast(WiFiScanClass::_scanResult); - WiFiScanClass::_scanResult = nullptr; - WiFiScanClass::_scanCount = 0; + free(WiFiScanClass::_scanResult); + WiFiScanClass::_scanResult = NULL; } + WiFiScanClass::_scanCount = 0; } /** diff --git a/libraries/Zigbee/examples/Zigbee_Analog_Input_Output/Zigbee_Analog_Input_Output.ino b/libraries/Zigbee/examples/Zigbee_Analog_Input_Output/Zigbee_Analog_Input_Output.ino index e31407cc8be..db8a62b091e 100644 --- a/libraries/Zigbee/examples/Zigbee_Analog_Input_Output/Zigbee_Analog_Input_Output.ino +++ b/libraries/Zigbee/examples/Zigbee_Analog_Input_Output/Zigbee_Analog_Input_Output.ino @@ -39,6 +39,9 @@ uint8_t analogPin = A0; uint8_t button = BOOT_PIN; ZigbeeAnalog zbAnalogDevice = ZigbeeAnalog(ANALOG_DEVICE_ENDPOINT_NUMBER); +ZigbeeAnalog zbAnalogTemp = ZigbeeAnalog(ANALOG_DEVICE_ENDPOINT_NUMBER + 1); +ZigbeeAnalog zbAnalogFan = ZigbeeAnalog(ANALOG_DEVICE_ENDPOINT_NUMBER + 2); +ZigbeeAnalog zbAnalogPercent = ZigbeeAnalog(ANALOG_DEVICE_ENDPOINT_NUMBER + 3); void onAnalogOutputChange(float analog_output) { Serial.printf("Received analog output change: %.1f\r\n", analog_output); @@ -57,15 +60,43 @@ void setup() { // Optional: set Zigbee device name and model zbAnalogDevice.setManufacturerAndModel("Espressif", "ZigbeeAnalogDevice"); - // Add analog clusters to Zigbee Analog according your needs + // Set up analog input zbAnalogDevice.addAnalogInput(); + zbAnalogDevice.setAnalogInputApplication(ESP_ZB_ZCL_AI_POWER_IN_WATTS_CONSUMPTION); + zbAnalogDevice.setAnalogInputDescription("Power Consumption (Watts)"); + zbAnalogDevice.setAnalogInputResolution(0.01); + + // Set up analog output zbAnalogDevice.addAnalogOutput(); + zbAnalogDevice.setAnalogOutputApplication(ESP_ZB_ZCL_AI_RPM_OTHER); + zbAnalogDevice.setAnalogOutputDescription("Fan Speed (RPM)"); // If analog output cluster is added, set callback function for analog output change zbAnalogDevice.onAnalogOutputChange(onAnalogOutputChange); + // Set up analog input + zbAnalogTemp.addAnalogInput(); + zbAnalogTemp.setAnalogInputApplication(ESP_ZB_ZCL_AI_TEMPERATURE_OTHER); + zbAnalogTemp.setAnalogInputDescription("Temperature"); + zbAnalogTemp.setAnalogInputResolution(0.1); + + // Set up analog input + zbAnalogFan.addAnalogInput(); + zbAnalogFan.setAnalogInputApplication(ESP_ZB_ZCL_AI_RPM_OTHER); + zbAnalogFan.setAnalogInputDescription("RPM"); + zbAnalogFan.setAnalogInputResolution(1); + + // Set up analog input + zbAnalogPercent.addAnalogInput(); + zbAnalogPercent.setAnalogInputApplication(ESP_ZB_ZCL_AI_PERCENTAGE_OTHER); + zbAnalogPercent.setAnalogInputDescription("Percentage"); + zbAnalogPercent.setAnalogInputResolution(0.01); + // Add endpoints to Zigbee Core Zigbee.addEndpoint(&zbAnalogDevice); + Zigbee.addEndpoint(&zbAnalogTemp); + Zigbee.addEndpoint(&zbAnalogFan); + Zigbee.addEndpoint(&zbAnalogPercent); Serial.println("Starting Zigbee..."); // When all EPs are registered, start Zigbee in End Device mode @@ -95,9 +126,15 @@ void loop() { float analog = (float)analogRead(analogPin); Serial.printf("Updating analog input to %.1f\r\n", analog); zbAnalogDevice.setAnalogInput(analog); + zbAnalogTemp.setAnalogInput(analog / 100); + zbAnalogFan.setAnalogInput(analog); + zbAnalogPercent.setAnalogInput(analog / 10); // Analog input supports reporting zbAnalogDevice.reportAnalogInput(); + zbAnalogTemp.reportAnalogInput(); + zbAnalogFan.reportAnalogInput(); + zbAnalogPercent.reportAnalogInput(); } // Checking button for factory reset and reporting diff --git a/libraries/Zigbee/examples/Zigbee_Binary_Input/README.md b/libraries/Zigbee/examples/Zigbee_Binary_Input/README.md new file mode 100644 index 00000000000..6ca3aac7119 --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Binary_Input/README.md @@ -0,0 +1,75 @@ +# Arduino-ESP32 Zigbee Binary Input Example + +This example shows how to configure the Zigbee end device and use it as a Home Automation (HA) binary input device with two different applications: HVAC fan status and security zone armed status. + +# Supported Targets + +Currently, this example supports the following targets. + +| Supported Targets | ESP32-C6 | ESP32-H2 | +| ----------------- | -------- | -------- | + +## Binary Input Functions + + * The example implements two binary inputs: + - HVAC Fan Status: Reports the current state of a fan + - Security Zone Armed: Reports the armed state of a security zone + * By clicking the button (BOOT) on this board, it will toggle both binary inputs and immediately send a report of their states to the network. + * Holding the button for more than 3 seconds will trigger a factory reset of the Zigbee device. + +## Hardware Required + +* A USB cable for power supply and programming + +### Configure the Project + +The example uses the following default pins: +* Button: `BOOT_PIN` (BOOT button on ESP32-C6 and ESP32-H2) + +#### Using Arduino IDE + +To get more information about the Espressif boards see [Espressif Development Kits](https://www.espressif.com/en/products/devkits). + +* Before Compile/Verify, select the correct board: `Tools -> Board`. +* Select the End device Zigbee mode: `Tools -> Zigbee mode: Zigbee ED (end device)` +* Select Partition Scheme for Zigbee: `Tools -> Partition Scheme: Zigbee 4MB with spiffs` +* Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port. +* Optional: Set debug level to verbose to see all logs from Zigbee stack: `Tools -> Core Debug Level: Verbose`. + +## Troubleshooting + +If the End device flashed with this example is not connecting to the coordinator, erase the flash of the End device before flashing the example to the board. It is recommended to do this if you re-flash the coordinator. +You can do the following: + +* In the Arduino IDE go to the Tools menu and set `Erase All Flash Before Sketch Upload` to `Enabled`. +* Add to the sketch `Zigbee.factoryReset();` to reset the device and Zigbee stack. + +By default, the coordinator network is closed after rebooting or flashing new firmware. +To open the network you have 2 options: + +* Open network after reboot by setting `Zigbee.setRebootOpenNetwork(time);` before calling `Zigbee.begin();`. +* In application you can anytime call `Zigbee.openNetwork(time);` to open the network for devices to join. + +***Important: Make sure you are using a good quality USB cable and that you have a reliable power source*** + +* **LED not blinking:** Check the wiring connection and the IO selection. +* **Programming Fail:** If the programming/flash procedure fails, try reducing the serial connection speed. +* **COM port not detected:** Check the USB cable and the USB to Serial driver installation. + +If the error persists, you can ask for help at the official [ESP32 forum](https://esp32.com) or see [Contribute](#contribute). + +## Contribute + +To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst) + +If you have any **feedback** or **issue** to report on this example/library, please open an issue or fix it by creating a new PR. Contributions are more than welcome! + +Before creating a new issue, be sure to try Troubleshooting and check if the same issue was already created by someone else. + +## Resources + +* Official ESP32 Forum: [Link](https://esp32.com) +* Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) +* ESP32-C6 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf) +* ESP32-H2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf) +* Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com) diff --git a/libraries/Zigbee/examples/Zigbee_Binary_Input/Zigbee_Binary_Input.ino b/libraries/Zigbee/examples/Zigbee_Binary_Input/Zigbee_Binary_Input.ino new file mode 100644 index 00000000000..de0cf606dcd --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Binary_Input/Zigbee_Binary_Input.ino @@ -0,0 +1,112 @@ +// Copyright 2025 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +/** + * @brief This example demonstrates Zigbee binary input device. + * + * The example demonstrates how to use Zigbee library to create an end device binary sensor device. + * + * Proper Zigbee mode must be selected in Tools->Zigbee mode + * and also the correct partition scheme must be selected in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/) + */ + +#ifndef ZIGBEE_MODE_ED +#error "Zigbee end device mode is not selected in Tools->Zigbee mode" +#endif + +#include "Zigbee.h" + +/* Zigbee binary sensor device configuration */ +#define BINARY_DEVICE_ENDPOINT_NUMBER 1 + +uint8_t binaryPin = A0; +uint8_t button = BOOT_PIN; + +ZigbeeBinary zbBinaryFan = ZigbeeBinary(BINARY_DEVICE_ENDPOINT_NUMBER); +ZigbeeBinary zbBinaryZone = ZigbeeBinary(BINARY_DEVICE_ENDPOINT_NUMBER + 1); + +bool binaryStatus = false; + +void setup() { + Serial.begin(115200); + Serial.println("Starting..."); + + // Init button switch + pinMode(button, INPUT_PULLUP); + + // Set analog resolution to 10 bits + analogReadResolution(10); + + // Optional: set Zigbee device name and model + zbBinaryFan.setManufacturerAndModel("Espressif", "ZigbeeBinarySensor"); + + // Set up binary fan status input (HVAC) + zbBinaryFan.addBinaryInput(); + zbBinaryFan.setBinaryInputApplication(BINARY_INPUT_APPLICATION_TYPE_HVAC_FAN_STATUS); + zbBinaryFan.setBinaryInputDescription("Fan Status"); + + // Set up binary zone armed input (Security) + zbBinaryZone.addBinaryInput(); + zbBinaryZone.setBinaryInputApplication(BINARY_INPUT_APPLICATION_TYPE_SECURITY_ZONE_ARMED); + zbBinaryZone.setBinaryInputDescription("Zone Armed"); + + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbBinaryFan); + Zigbee.addEndpoint(&zbBinaryZone); + + Serial.println("Starting Zigbee..."); + // When all EPs are registered, start Zigbee in End Device mode + if (!Zigbee.begin()) { + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting..."); + ESP.restart(); + } else { + Serial.println("Zigbee started successfully!"); + } + Serial.println("Connecting to network"); + while (!Zigbee.connected()) { + Serial.print("."); + delay(100); + } + Serial.println("Connected"); +} + +void loop() { + // Checking button for factory reset and reporting + if (digitalRead(button) == LOW) { // Push button pressed + // Key debounce handling + delay(100); + int startTime = millis(); + while (digitalRead(button) == LOW) { + delay(50); + if ((millis() - startTime) > 3000) { + // If key pressed for more than 3secs, factory reset Zigbee and reboot + Serial.println("Resetting Zigbee to factory and rebooting in 1s."); + delay(1000); + Zigbee.factoryReset(); + } + } + // Toggle binary input + binaryStatus = !binaryStatus; + zbBinaryFan.setBinaryInput(binaryStatus); + zbBinaryZone.setBinaryInput(binaryStatus); + zbBinaryFan.reportBinaryInput(); + zbBinaryZone.reportBinaryInput(); + } + delay(100); +} diff --git a/libraries/Zigbee/examples/Zigbee_Binary_Input/ci.json b/libraries/Zigbee/examples/Zigbee_Binary_Input/ci.json new file mode 100644 index 00000000000..ceacc367801 --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Binary_Input/ci.json @@ -0,0 +1,7 @@ +{ + "fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed", + "requires": [ + "CONFIG_SOC_IEEE802154_SUPPORTED=y", + "CONFIG_ZB_ENABLED=y" + ] +} diff --git a/libraries/Zigbee/examples/Zigbee_Electrical_AC_Sensor/README.md b/libraries/Zigbee/examples/Zigbee_Electrical_AC_Sensor/README.md new file mode 100644 index 00000000000..fe032049c90 --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Electrical_AC_Sensor/README.md @@ -0,0 +1,87 @@ +# Arduino-ESP32 Zigbee AC Electrical Measurement Example + +This example shows how to configure the Zigbee router device and use it as a Home Automation (HA) AC electrical measurement device that reports voltage, current, power, and frequency measurements. + +# Supported Targets + +Currently, this example supports the following targets. + +| Supported Targets | ESP32-C6 | ESP32-H2 | +| ----------------- | -------- | -------- | + +## AC Electrical Measurement Functions + + * After this board first starts up, it would be configured locally to report AC electrical measurements: + - AC voltage in volts (0-300.00 V) + - AC current in amps (0-10.000 A) + - AC power in watts (0-3200.0 W) + - AC frequency in hertz (0-65.000 Hz) + * Holding the button (BOOT) for more than 3 seconds will trigger a factory reset of the device. + * The device reports measurements every 2 seconds with simulated values. + +## Measurement Precision + +The example demonstrates how to set up proper measurement precision using multiplier and divisor values: + * Voltage: 1/100 = 0.01 V (1 unit = 10 mV) + * Current: 1/1000 = 0.001 A (1 unit = 1 mA) + * Power: 1/10 = 0.1 W (1 unit = 100 mW) + * Frequency: 1/1000 = 0.001 Hz (1 unit = 1 mHz) + +These settings ensure accurate reporting of measurements with proper decimal precision in the Zigbee network. + +## Hardware Required + +* A USB cable for power supply and programming + +### Configure the Project + +Set the ADC GPIO by changing the `analogPin` variable. By default, it's the pin `A0`. +Set the Button GPIO by changing the `button` variable. By default, it's the pin `BOOT_PIN` (BOOT button on ESP32-C6 and ESP32-H2). + +#### Using Arduino IDE + +To get more information about the Espressif boards see [Espressif Development Kits](https://www.espressif.com/en/products/devkits). + +* Before Compile/Verify, select the correct board: `Tools -> Board`. +* Select the Router Zigbee mode: `Tools -> Zigbee mode: Zigbee Router` +* Select Partition Scheme for Zigbee: `Tools -> Partition Scheme: Zigbee 4MB with spiffs` +* Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port. +* Optional: Set debug level to verbose to see all logs from Zigbee stack: `Tools -> Core Debug Level: Verbose`. + +## Troubleshooting + +If the Router device flashed with this example is not connecting to the coordinator, erase the flash of the Router device before flashing the example to the board. It is recommended to do this if you re-flash the coordinator. +You can do the following: + +* In the Arduino IDE go to the Tools menu and set `Erase All Flash Before Sketch Upload` to `Enabled`. +* Add to the sketch `Zigbee.factoryReset();` to reset the device and Zigbee stack. + +By default, the coordinator network is closed after rebooting or flashing new firmware. +To open the network you have 2 options: + +* Open network after reboot by setting `Zigbee.setRebootOpenNetwork(time);` before calling `Zigbee.begin();`. +* In application you can anytime call `Zigbee.openNetwork(time);` to open the network for devices to join. + +***Important: Make sure you are using a good quality USB cable and that you have a reliable power source*** + +* **LED not blinking:** Check the wiring connection and the IO selection. +* **Programming Fail:** If the programming/flash procedure fails, try reducing the serial connection speed. +* **COM port not detected:** Check the USB cable and the USB to Serial driver installation. + +If the error persists, you can ask for help at the official [ESP32 forum](https://esp32.com) or see [Contribute](#contribute). + +## Contribute + +To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst) + +If you have any **feedback** or **issue** to report on this example/library, please open an issue or fix it by creating a new PR. Contributions are more than welcome! + +Before creating a new issue, be sure to try Troubleshooting and check if the same issue was already created by someone else. + +## Resources + +* Official ESP32 Forum: [Link](https://esp32.com) +* Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) +* ESP32-C6 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf) +* ESP32-H2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf) +* Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com) diff --git a/libraries/Zigbee/examples/Zigbee_Electrical_AC_Sensor/Zigbee_Electrical_AC_Sensor.ino b/libraries/Zigbee/examples/Zigbee_Electrical_AC_Sensor/Zigbee_Electrical_AC_Sensor.ino new file mode 100644 index 00000000000..9e8656119d6 --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Electrical_AC_Sensor/Zigbee_Electrical_AC_Sensor.ino @@ -0,0 +1,162 @@ +// Copyright 2025 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +/** + * @brief This example demonstrates Zigbee electrical AC measurement device. + * + * The example demonstrates how to use Zigbee library to create a router device that measures + * AC electrical parameters like voltage, current, power, power factor and frequency. + * + * Proper Zigbee mode must be selected in Tools->Zigbee mode + * and also the correct partition scheme must be selected in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/) + */ + +// Recommended to use Router mode, as this type of device is expected to be mains powered. +#ifndef ZIGBEE_MODE_ZCZR +#error "Zigbee coordinator/router mode is not selected in Tools->Zigbee mode" +#endif + +#include "Zigbee.h" + +/* Zigbee AC measurement device configuration */ +#define AC_ELECTRICAL_MEASUREMENT_ENDPOINT_NUMBER 1 + +uint8_t analogPin = A0; +uint8_t button = BOOT_PIN; + +ZigbeeElectricalMeasurement zbElectricalMeasurement = ZigbeeElectricalMeasurement(AC_ELECTRICAL_MEASUREMENT_ENDPOINT_NUMBER); + +void onAnalogOutputChange(float analog_output) { + Serial.printf("Received analog output change: %.1f\r\n", analog_output); +} + +void setup() { + Serial.begin(115200); + Serial.println("Starting..."); + + // Init button switch + pinMode(button, INPUT_PULLUP); + + // Set analog resolution to 10 bits + analogReadResolution(10); + + // Optional: set Zigbee device name and model + zbElectricalMeasurement.setManufacturerAndModel("Espressif", "ZigbeeElectricalMeasurementAC"); + + // Add analog clusters to Zigbee Analog according your needs + zbElectricalMeasurement.addACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_PHASE_TYPE_A); + zbElectricalMeasurement.addACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_PHASE_TYPE_A); + zbElectricalMeasurement.addACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_PHASE_TYPE_A); + zbElectricalMeasurement.addACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_POWER_FACTOR, ZIGBEE_AC_PHASE_TYPE_A); + zbElectricalMeasurement.addACMeasurement( + ZIGBEE_AC_MEASUREMENT_TYPE_FREQUENCY, ZIGBEE_AC_PHASE_TYPE_NON_SPECIFIC + ); // frequency is not phase specific (shared) + + // Optional: set Multiplier/Divisor for the measurements + zbElectricalMeasurement.setACMultiplierDivisor(ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, 1, 100); // 1/100 = 0.01V (1 unit of measurement = 0.01V = 10mV) + zbElectricalMeasurement.setACMultiplierDivisor(ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, 1, 1000); // 1/1000 = 0.001A (1 unit of measurement = 0.001A = 1mA) + zbElectricalMeasurement.setACMultiplierDivisor(ZIGBEE_AC_MEASUREMENT_TYPE_POWER, 1, 10); // 1/10 = 0.1W (1 unit of measurement = 0.1W = 100mW) + zbElectricalMeasurement.setACMultiplierDivisor(ZIGBEE_AC_MEASUREMENT_TYPE_FREQUENCY, 1, 1000); // 1/1000 = 0.001Hz (1 unit of measurement = 0.001Hz = 1mHz) + + // Optional: set Min/max values for the measurements + zbElectricalMeasurement.setACMinMaxValue(ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_PHASE_TYPE_A, 0, 30000); // 0-300.00V + zbElectricalMeasurement.setACMinMaxValue(ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_PHASE_TYPE_A, 0, 10000); // 0-10.000A + zbElectricalMeasurement.setACMinMaxValue(ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_PHASE_TYPE_A, 0, 32000); // 0-3200.0W + zbElectricalMeasurement.setACMinMaxValue(ZIGBEE_AC_MEASUREMENT_TYPE_FREQUENCY, ZIGBEE_AC_PHASE_TYPE_NON_SPECIFIC, 0, 65000); // 0-65.000Hz + + // Optional: set power factor for the measurements + zbElectricalMeasurement.setACPowerFactor(ZIGBEE_AC_PHASE_TYPE_A, 98); // 100 = 1.00, 0 = 0.00, -100 = -1.00 + + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbElectricalMeasurement); + + Serial.println("Starting Zigbee..."); + // When all EPs are registered, start Zigbee in Router mode + if (!Zigbee.begin(ZIGBEE_ROUTER)) { + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting..."); + ESP.restart(); + } else { + Serial.println("Zigbee started successfully!"); + } + Serial.println("Connecting to network"); + while (!Zigbee.connected()) { + Serial.print("."); + delay(100); + } + Serial.println("Connected"); + + // Optional: Add reporting for AC measurements (this is overridden by HomeAssistant ZHA if used as a Zigbee coordinator) + zbElectricalMeasurement.setACReporting( + ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_PHASE_TYPE_A, 0, 30, 10 + ); // report every 30 seconds if value changes by 10 (0.1V) + zbElectricalMeasurement.setACReporting( + ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_PHASE_TYPE_A, 0, 30, 100 + ); // report every 30 seconds if value changes by 10 (0.1A) + zbElectricalMeasurement.setACReporting( + ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_PHASE_TYPE_A, 0, 30, 10 + ); // report every 30 seconds if value changes by 10 (1W) + zbElectricalMeasurement.setACReporting( + ZIGBEE_AC_MEASUREMENT_TYPE_FREQUENCY, ZIGBEE_AC_PHASE_TYPE_NON_SPECIFIC, 0, 30, 100 + ); // report every 30 seconds if value changes by 100 (0.1Hz) +} + +void loop() { + static uint32_t timeCounter = 0; + + static uint8_t randomizer = 0; + // Read ADC value as current to demonstrate the measurements and update the electrical measurement values every 2s + if (!(timeCounter++ % 20)) { // delaying for 100ms x 20 = 2s + uint16_t voltage = 23000 + randomizer; // 230.00 V + uint16_t current = analogReadMilliVolts(analogPin); // demonstrates 0-3.3A + int16_t power = ((voltage / 100) * (current / 1000) * 10); //calculate power in W + uint16_t frequency = 50135; // 50.000 Hz + Serial.printf("Updating AC voltage to %d (0.01V), current to %d (mA), power to %d (0.1W), frequency to %d (mHz)\r\n", voltage, current, power, frequency); + + // Update the measurements + zbElectricalMeasurement.setACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_PHASE_TYPE_A, voltage); + zbElectricalMeasurement.setACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_PHASE_TYPE_A, current); + zbElectricalMeasurement.setACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_PHASE_TYPE_A, power); + zbElectricalMeasurement.setACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_FREQUENCY, ZIGBEE_AC_PHASE_TYPE_NON_SPECIFIC, frequency); + + // Report the measurements + zbElectricalMeasurement.reportAC(ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_PHASE_TYPE_A); + zbElectricalMeasurement.reportAC(ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_PHASE_TYPE_A); + zbElectricalMeasurement.reportAC(ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_PHASE_TYPE_A); + zbElectricalMeasurement.reportAC(ZIGBEE_AC_MEASUREMENT_TYPE_FREQUENCY, ZIGBEE_AC_PHASE_TYPE_NON_SPECIFIC); + + randomizer += 10; + } + + // Checking button for factory reset and reporting + if (digitalRead(button) == LOW) { // Push button pressed + // Key debounce handling + delay(100); + int startTime = millis(); + while (digitalRead(button) == LOW) { + delay(50); + if ((millis() - startTime) > 3000) { + // If key pressed for more than 3secs, factory reset Zigbee and reboot + Serial.println("Resetting Zigbee to factory and rebooting in 1s."); + delay(1000); + Zigbee.factoryReset(); + } + } + } + delay(100); +} diff --git a/libraries/Zigbee/examples/Zigbee_Electrical_AC_Sensor/ci.json b/libraries/Zigbee/examples/Zigbee_Electrical_AC_Sensor/ci.json new file mode 100644 index 00000000000..15d6190e4ae --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Electrical_AC_Sensor/ci.json @@ -0,0 +1,6 @@ +{ + "fqbn_append": "PartitionScheme=zigbee_zczr,ZigbeeMode=zczr", + "requires": [ + "CONFIG_ZB_ENABLED=y" + ] +} diff --git a/libraries/Zigbee/examples/Zigbee_Electrical_AC_Sensor_MultiPhase/README.md b/libraries/Zigbee/examples/Zigbee_Electrical_AC_Sensor_MultiPhase/README.md new file mode 100644 index 00000000000..3714a05fa4f --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Electrical_AC_Sensor_MultiPhase/README.md @@ -0,0 +1,87 @@ +# Arduino-ESP32 Zigbee AC Electrical MultiPhase Measurement Example + +This example shows how to configure the Zigbee router device and use it as a Home Automation (HA) AC electrical measurement device that reports voltage, current, power, and frequency measurements across three phases. + +# Supported Targets + +Currently, this example supports the following targets. + +| Supported Targets | ESP32-C6 | ESP32-H2 | +| ----------------- | -------- | -------- | + +## AC Electrical Measurement Functions + + * After this board first starts up, it would be configured locally to report AC electrical measurements: + - AC voltage in volts (0-300.00 V) for each phase (A, B, C) + - AC current in amps (0-10.000 A) for each phase (A, B, C) + - AC power in watts (0-3200.0 W) for each phase (A, B, C) + - AC frequency in hertz (0-65.000 Hz) shared across all phases + * Holding the button (BOOT) for more than 3 seconds will trigger a factory reset of the device. + * The device reports measurements every 2 seconds with simulated values. + +## Measurement Precision + +The example demonstrates how to set up proper measurement precision using multiplier and divisor values: + * Voltage: 1/100 = 0.01 V (1 unit = 10 mV) + * Current: 1/1000 = 0.001 A (1 unit = 1 mA) + * Power: 1/10 = 0.1 W (1 unit = 100 mW) + * Frequency: 1/1000 = 0.001 Hz (1 unit = 1 mHz) + +These settings ensure accurate reporting of measurements with proper decimal precision in the Zigbee network. + +## Hardware Required + +* A USB cable for power supply and programming + +### Configure the Project + +Set the ADC GPIO by changing the `analogPin` variable. By default, it's the pin `A0`. +Set the Button GPIO by changing the `button` variable. By default, it's the pin `BOOT_PIN` (BOOT button on ESP32-C6 and ESP32-H2). + +#### Using Arduino IDE + +To get more information about the Espressif boards see [Espressif Development Kits](https://www.espressif.com/en/products/devkits). + +* Before Compile/Verify, select the correct board: `Tools -> Board`. +* Select the Router Zigbee mode: `Tools -> Zigbee mode: Zigbee Router` +* Select Partition Scheme for Zigbee: `Tools -> Partition Scheme: Zigbee 4MB with spiffs` +* Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port. +* Optional: Set debug level to verbose to see all logs from Zigbee stack: `Tools -> Core Debug Level: Verbose`. + +## Troubleshooting + +If the Router device flashed with this example is not connecting to the coordinator, erase the flash of the Router device before flashing the example to the board. It is recommended to do this if you re-flash the coordinator. +You can do the following: + +* In the Arduino IDE go to the Tools menu and set `Erase All Flash Before Sketch Upload` to `Enabled`. +* Add to the sketch `Zigbee.factoryReset();` to reset the device and Zigbee stack. + +By default, the coordinator network is closed after rebooting or flashing new firmware. +To open the network you have 2 options: + +* Open network after reboot by setting `Zigbee.setRebootOpenNetwork(time);` before calling `Zigbee.begin();`. +* In application you can anytime call `Zigbee.openNetwork(time);` to open the network for devices to join. + +***Important: Make sure you are using a good quality USB cable and that you have a reliable power source*** + +* **LED not blinking:** Check the wiring connection and the IO selection. +* **Programming Fail:** If the programming/flash procedure fails, try reducing the serial connection speed. +* **COM port not detected:** Check the USB cable and the USB to Serial driver installation. + +If the error persists, you can ask for help at the official [ESP32 forum](https://esp32.com) or see [Contribute](#contribute). + +## Contribute + +To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst) + +If you have any **feedback** or **issue** to report on this example/library, please open an issue or fix it by creating a new PR. Contributions are more than welcome! + +Before creating a new issue, be sure to try Troubleshooting and check if the same issue was already created by someone else. + +## Resources + +* Official ESP32 Forum: [Link](https://esp32.com) +* Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) +* ESP32-C6 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf) +* ESP32-H2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf) +* Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com) diff --git a/libraries/Zigbee/examples/Zigbee_Electrical_AC_Sensor_MultiPhase/Zigbee_Electrical_AC_Sensor_MultiPhase.ino b/libraries/Zigbee/examples/Zigbee_Electrical_AC_Sensor_MultiPhase/Zigbee_Electrical_AC_Sensor_MultiPhase.ino new file mode 100644 index 00000000000..e219113468e --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Electrical_AC_Sensor_MultiPhase/Zigbee_Electrical_AC_Sensor_MultiPhase.ino @@ -0,0 +1,192 @@ +// Copyright 2025 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +/** + * @brief This example demonstrates Zigbee electrical AC measurement device with multi-phase support. + * + * The example demonstrates how to use Zigbee library to create a router device that measures + * AC electrical parameters like voltage, current, power, power factor and frequency across + * three phases (A, B, C). This allows monitoring of three-phase power systems commonly used + * in industrial and commercial applications. + * + * The device measures: + * - Per phase: voltage, current, power, power factor + * - Shared: frequency (common across all phases) + * + * Proper Zigbee mode must be selected in Tools->Zigbee mode + * and also the correct partition scheme must be selected in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/) + */ + +// Recommended to use Router mode, as this type of device is expected to be mains powered. +#ifndef ZIGBEE_MODE_ZCZR +#error "Zigbee coordinator/router mode is not selected in Tools->Zigbee mode" +#endif + +#include "Zigbee.h" + +/* Zigbee AC measurement device configuration */ +#define AC_ELECTRICAL_MEASUREMENT_ENDPOINT_NUMBER 1 + +uint8_t analogPin = A0; +uint8_t button = BOOT_PIN; + +ZigbeeElectricalMeasurement zbElectricalMeasurement = ZigbeeElectricalMeasurement(AC_ELECTRICAL_MEASUREMENT_ENDPOINT_NUMBER); + +void onAnalogOutputChange(float analog_output) { + Serial.printf("Received analog output change: %.1f\r\n", analog_output); +} + +void setup() { + Serial.begin(115200); + Serial.println("Starting..."); + + // Init button switch + pinMode(button, INPUT_PULLUP); + + // Set analog resolution to 10 bits + analogReadResolution(10); + + // Optional: set Zigbee device name and model + zbElectricalMeasurement.setManufacturerAndModel("Espressif", "ZigbeeElectricalMeasurementAC"); + + // Add analog clusters to Zigbee Analog according your needs + zbElectricalMeasurement.addACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_PHASE_TYPE_A); + zbElectricalMeasurement.addACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_PHASE_TYPE_A); + zbElectricalMeasurement.addACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_PHASE_TYPE_A); + + zbElectricalMeasurement.addACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_PHASE_TYPE_B); + zbElectricalMeasurement.addACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_PHASE_TYPE_B); + zbElectricalMeasurement.addACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_PHASE_TYPE_B); + + zbElectricalMeasurement.addACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_PHASE_TYPE_C); + zbElectricalMeasurement.addACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_PHASE_TYPE_C); + zbElectricalMeasurement.addACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_PHASE_TYPE_C); + + zbElectricalMeasurement.addACMeasurement( + ZIGBEE_AC_MEASUREMENT_TYPE_FREQUENCY, ZIGBEE_AC_PHASE_TYPE_NON_SPECIFIC + ); // frequency is not phase specific (shared) + + // Recommended: set Multiplier/Divisor for the measurements (common for all phases) + zbElectricalMeasurement.setACMultiplierDivisor(ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, 1, 100); // 1/100 = 0.01V (1 unit of measurement = 0.01V = 10mV) + zbElectricalMeasurement.setACMultiplierDivisor(ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, 1, 1000); // 1/1000 = 0.001A (1 unit of measurement = 0.001A = 1mA) + zbElectricalMeasurement.setACMultiplierDivisor(ZIGBEE_AC_MEASUREMENT_TYPE_POWER, 1, 10); // 1/10 = 0.1W (1 unit of measurement = 0.1W = 100mW) + zbElectricalMeasurement.setACMultiplierDivisor(ZIGBEE_AC_MEASUREMENT_TYPE_FREQUENCY, 1, 1000); // 1/1000 = 0.001Hz (1 unit of measurement = 0.001Hz = 1mHz) + + // Optional: set Min/max values for the measurements + zbElectricalMeasurement.setACMinMaxValue(ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_PHASE_TYPE_A, 0, 30000); // 0-300.00V + zbElectricalMeasurement.setACMinMaxValue(ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_PHASE_TYPE_A, 0, 10000); // 0-10.000A + zbElectricalMeasurement.setACMinMaxValue(ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_PHASE_TYPE_A, 0, 32000); // 0-3200.0W + + zbElectricalMeasurement.setACMinMaxValue(ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_PHASE_TYPE_B, 0, 30000); // 0-300.00V + zbElectricalMeasurement.setACMinMaxValue(ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_PHASE_TYPE_B, 0, 10000); // 0-10.000A + zbElectricalMeasurement.setACMinMaxValue(ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_PHASE_TYPE_B, 0, 32000); // 0-3200.0W + + zbElectricalMeasurement.setACMinMaxValue(ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_PHASE_TYPE_C, 0, 30000); // 0-300.00V + zbElectricalMeasurement.setACMinMaxValue(ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_PHASE_TYPE_C, 0, 10000); // 0-10.000A + zbElectricalMeasurement.setACMinMaxValue(ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_PHASE_TYPE_C, 0, 32000); // 0-3200.0W + + zbElectricalMeasurement.setACMinMaxValue(ZIGBEE_AC_MEASUREMENT_TYPE_FREQUENCY, ZIGBEE_AC_PHASE_TYPE_NON_SPECIFIC, 0, 65000); // 0-65.000Hz + + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbElectricalMeasurement); + + Serial.println("Starting Zigbee..."); + // When all EPs are registered, start Zigbee in Router mode + if (!Zigbee.begin(ZIGBEE_ROUTER)) { + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting..."); + ESP.restart(); + } else { + Serial.println("Zigbee started successfully!"); + } + Serial.println("Connecting to network"); + while (!Zigbee.connected()) { + Serial.print("."); + delay(100); + } + Serial.println("Connected"); +} + +void loop() { + static uint32_t timeCounter = 0; + static uint8_t randomizer = 0; + // Read ADC value and update the analog value every 2s + if (!(timeCounter++ % 20)) { // delaying for 100ms x 20 = 2s + uint16_t voltage = 23000 + randomizer; // 230.00 V + uint16_t current = analogReadMilliVolts(analogPin); // demonstrates approx 0-3.3A + int16_t power = ((voltage / 100) * (current / 1000) * 10); //calculate power in W + uint16_t frequency = 50135; // 50.000 Hz + Serial.printf("Updating AC voltage to %d (0.01V), current to %d (mA), power to %d (0.1W), frequency to %d (mHz)\r\n", voltage, current, power, frequency); + zbElectricalMeasurement.setACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_PHASE_TYPE_A, voltage); + zbElectricalMeasurement.setACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_PHASE_TYPE_A, current); + zbElectricalMeasurement.setACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_PHASE_TYPE_A, power); + + // Phase B demonstrates phase shift + current += 500; + voltage += 500; + power = ((voltage / 100) * (current / 1000) * 10); //calculate power in W + + zbElectricalMeasurement.setACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_PHASE_TYPE_B, voltage); + zbElectricalMeasurement.setACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_PHASE_TYPE_B, current); + zbElectricalMeasurement.setACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_PHASE_TYPE_B, power); + + // Phase C demonstrates phase shift + current += 500; + voltage += 500; + power = ((voltage / 100) * (current / 1000) * 10); //calculate power in W + + zbElectricalMeasurement.setACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_PHASE_TYPE_C, voltage); + zbElectricalMeasurement.setACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_PHASE_TYPE_C, current); + zbElectricalMeasurement.setACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_PHASE_TYPE_C, power); + + zbElectricalMeasurement.setACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_FREQUENCY, ZIGBEE_AC_PHASE_TYPE_NON_SPECIFIC, frequency); + + zbElectricalMeasurement.reportAC(ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_PHASE_TYPE_A); + zbElectricalMeasurement.reportAC(ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_PHASE_TYPE_A); + zbElectricalMeasurement.reportAC(ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_PHASE_TYPE_A); + + zbElectricalMeasurement.reportAC(ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_PHASE_TYPE_B); + zbElectricalMeasurement.reportAC(ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_PHASE_TYPE_B); + zbElectricalMeasurement.reportAC(ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_PHASE_TYPE_B); + + zbElectricalMeasurement.reportAC(ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_PHASE_TYPE_C); + zbElectricalMeasurement.reportAC(ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_PHASE_TYPE_C); + zbElectricalMeasurement.reportAC(ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_PHASE_TYPE_C); + + zbElectricalMeasurement.reportAC(ZIGBEE_AC_MEASUREMENT_TYPE_FREQUENCY, ZIGBEE_AC_PHASE_TYPE_NON_SPECIFIC); + + randomizer += 10; + } + + // Checking button for factory reset and reporting + if (digitalRead(button) == LOW) { // Push button pressed + // Key debounce handling + delay(100); + int startTime = millis(); + while (digitalRead(button) == LOW) { + delay(50); + if ((millis() - startTime) > 3000) { + // If key pressed for more than 3secs, factory reset Zigbee and reboot + Serial.println("Resetting Zigbee to factory and rebooting in 1s."); + delay(1000); + Zigbee.factoryReset(); + } + } + } + delay(100); +} diff --git a/libraries/Zigbee/examples/Zigbee_Electrical_AC_Sensor_MultiPhase/ci.json b/libraries/Zigbee/examples/Zigbee_Electrical_AC_Sensor_MultiPhase/ci.json new file mode 100644 index 00000000000..15d6190e4ae --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Electrical_AC_Sensor_MultiPhase/ci.json @@ -0,0 +1,6 @@ +{ + "fqbn_append": "PartitionScheme=zigbee_zczr,ZigbeeMode=zczr", + "requires": [ + "CONFIG_ZB_ENABLED=y" + ] +} diff --git a/libraries/Zigbee/examples/Zigbee_Electrical_DC_Sensor/README.md b/libraries/Zigbee/examples/Zigbee_Electrical_DC_Sensor/README.md new file mode 100644 index 00000000000..e8922fc1a79 --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Electrical_DC_Sensor/README.md @@ -0,0 +1,85 @@ +# Arduino-ESP32 Zigbee DC Electrical Measurement Example + +This example shows how to configure the Zigbee end device and use it as a Home Automation (HA) DC electrical measurement device that reports voltage, current, and power measurements. + +# Supported Targets + +Currently, this example supports the following targets. + +| Supported Targets | ESP32-C6 | ESP32-H2 | +| ----------------- | -------- | -------- | + +## DC Electrical Measurement Functions + + * After this board first starts up, it would be configured locally to report DC electrical measurements: + - DC voltage in millivolts (0-5000 mV) + - DC current in milliamps (0-1000 mA) + - DC power in milliwatts (0-5000 mW) + * Holding the button (BOOT) for more than 3 seconds will trigger a factory reset of the device. + * The device reports measurements every 30 seconds if the value changes by more than the configured delta. + +## Measurement Precision + +The example demonstrates how to set up proper measurement precision using multiplier and divisor values: + * Voltage: 1/1000 = 0.001 V (1 unit = 1 mV) + * Current: 1/1000 = 0.001 A (1 unit = 1 mA) + * Power: 1/1000 = 0.001 W (1 unit = 1 mW) + +These settings ensure accurate reporting of measurements with proper decimal precision in the Zigbee network. + +## Hardware Required + +* A USB cable for power supply and programming + +### Configure the Project + +Set the ADC GPIO by changing the `analogPin` variable. By default, it's the pin `A0`. +Set the Button GPIO by changing the `button` variable. By default, it's the pin `BOOT_PIN` (BOOT button on ESP32-C6 and ESP32-H2). + +#### Using Arduino IDE + +To get more information about the Espressif boards see [Espressif Development Kits](https://www.espressif.com/en/products/devkits). + +* Before Compile/Verify, select the correct board: `Tools -> Board`. +* Select the End device Zigbee mode: `Tools -> Zigbee mode: Zigbee ED (end device)` +* Select Partition Scheme for Zigbee: `Tools -> Partition Scheme: Zigbee 4MB with spiffs` +* Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port. +* Optional: Set debug level to verbose to see all logs from Zigbee stack: `Tools -> Core Debug Level: Verbose`. + +## Troubleshooting + +If the End device flashed with this example is not connecting to the coordinator, erase the flash of the End device before flashing the example to the board. It is recommended to do this if you re-flash the coordinator. +You can do the following: + +* In the Arduino IDE go to the Tools menu and set `Erase All Flash Before Sketch Upload` to `Enabled`. +* Add to the sketch `Zigbee.factoryReset();` to reset the device and Zigbee stack. + +By default, the coordinator network is closed after rebooting or flashing new firmware. +To open the network you have 2 options: + +* Open network after reboot by setting `Zigbee.setRebootOpenNetwork(time);` before calling `Zigbee.begin();`. +* In application you can anytime call `Zigbee.openNetwork(time);` to open the network for devices to join. + +***Important: Make sure you are using a good quality USB cable and that you have a reliable power source*** + +* **LED not blinking:** Check the wiring connection and the IO selection. +* **Programming Fail:** If the programming/flash procedure fails, try reducing the serial connection speed. +* **COM port not detected:** Check the USB cable and the USB to Serial driver installation. + +If the error persists, you can ask for help at the official [ESP32 forum](https://esp32.com) or see [Contribute](#contribute). + +## Contribute + +To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst) + +If you have any **feedback** or **issue** to report on this example/library, please open an issue or fix it by creating a new PR. Contributions are more than welcome! + +Before creating a new issue, be sure to try Troubleshooting and check if the same issue was already created by someone else. + +## Resources + +* Official ESP32 Forum: [Link](https://esp32.com) +* Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) +* ESP32-C6 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf) +* ESP32-H2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf) +* Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com) diff --git a/libraries/Zigbee/examples/Zigbee_Electrical_DC_Sensor/Zigbee_Electrical_DC_Sensor.ino b/libraries/Zigbee/examples/Zigbee_Electrical_DC_Sensor/Zigbee_Electrical_DC_Sensor.ino new file mode 100644 index 00000000000..4324a7b3ce5 --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Electrical_DC_Sensor/Zigbee_Electrical_DC_Sensor.ino @@ -0,0 +1,137 @@ +// Copyright 2025 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +/** + * @brief This example demonstrates a Zigbee DC electrical measurement sensor. + * + * The example shows how to use the Zigbee library to create an end device that measures + * DC voltage, current and power using the Electrical Measurement cluster. + * + * The device reports: + * - DC voltage in millivolts (0-5000mV) + * - DC current in milliamps (0-1000mA) + * - DC power in milliwatts (0-5000mW) + * + * Proper Zigbee mode must be selected in Tools->Zigbee mode + * and also the correct partition scheme must be selected in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/) + */ + +#ifndef ZIGBEE_MODE_ED +#error "Zigbee end device mode is not selected in Tools->Zigbee mode" +#endif + +#include "Zigbee.h" + +/* Zigbee DC measurement device configuration */ +#define DC_ELECTRICAL_MEASUREMENT_ENDPOINT_NUMBER 1 + +uint8_t analogPin = A0; +uint8_t button = BOOT_PIN; + +ZigbeeElectricalMeasurement zbElectricalMeasurement = ZigbeeElectricalMeasurement(DC_ELECTRICAL_MEASUREMENT_ENDPOINT_NUMBER); + +void setup() { + Serial.begin(115200); + Serial.println("Starting..."); + + // Init button switch + pinMode(button, INPUT_PULLUP); + + // Set analog resolution to 10 bits + analogReadResolution(10); + + // Optional: set Zigbee device name and model + zbElectricalMeasurement.setManufacturerAndModel("Espressif", "ZigbeeElectricalMeasurementDC"); + + // Add analog clusters to Zigbee Analog according your needs + zbElectricalMeasurement.addDCMeasurement(ZIGBEE_DC_MEASUREMENT_TYPE_VOLTAGE); + zbElectricalMeasurement.addDCMeasurement(ZIGBEE_DC_MEASUREMENT_TYPE_CURRENT); + zbElectricalMeasurement.addDCMeasurement(ZIGBEE_DC_MEASUREMENT_TYPE_POWER); + + // // Optional: set Min/max values for the measurements + zbElectricalMeasurement.setDCMinMaxValue(ZIGBEE_DC_MEASUREMENT_TYPE_VOLTAGE, 0, 5000); // 0-5.000V + zbElectricalMeasurement.setDCMinMaxValue(ZIGBEE_DC_MEASUREMENT_TYPE_CURRENT, 0, 1000); // 0-1.000A + zbElectricalMeasurement.setDCMinMaxValue(ZIGBEE_DC_MEASUREMENT_TYPE_POWER, 0, 5000); // 0-5.000W + + // // Optional: set Multiplier/Divisor for the measurements + zbElectricalMeasurement.setDCMultiplierDivisor(ZIGBEE_DC_MEASUREMENT_TYPE_VOLTAGE, 1, 1000); // 1/1000 = 0.001V (1 unit of measurement = 0.001V = 1mV) + zbElectricalMeasurement.setDCMultiplierDivisor(ZIGBEE_DC_MEASUREMENT_TYPE_CURRENT, 1, 1000); // 1/1000 = 0.001A (1 unit of measurement = 0.001A = 1mA) + zbElectricalMeasurement.setDCMultiplierDivisor(ZIGBEE_DC_MEASUREMENT_TYPE_POWER, 1, 1000); // 1/1000 = 0.001W (1 unit of measurement = 0.001W = 1mW) + + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbElectricalMeasurement); + + Serial.println("Starting Zigbee..."); + // When all EPs are registered, start Zigbee in End Device mode + if (!Zigbee.begin()) { + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting..."); + ESP.restart(); + } else { + Serial.println("Zigbee started successfully!"); + } + Serial.println("Connecting to network"); + while (!Zigbee.connected()) { + Serial.print("."); + delay(100); + } + Serial.println("Connected"); + + // Optional: Add reporting for DC measurements (this is overridden by HomeAssistant ZHA if connected to its network) + zbElectricalMeasurement.setDCReporting(ZIGBEE_DC_MEASUREMENT_TYPE_VOLTAGE, 0, 30, 10); // report every 30 seconds if value changes by 10 (0.1V) + zbElectricalMeasurement.setDCReporting(ZIGBEE_DC_MEASUREMENT_TYPE_CURRENT, 0, 30, 10); // report every 30 seconds if value changes by 10 (0.1A) + zbElectricalMeasurement.setDCReporting(ZIGBEE_DC_MEASUREMENT_TYPE_POWER, 0, 30, 10); // report every 30 seconds if value changes by 10 (0.1W) +} + +void loop() { + static uint32_t timeCounter = 0; + static uint8_t randomizer = 0; + // Read ADC value and update the analog value every 2s + if (!(timeCounter++ % 20)) { // delaying for 100ms x 20 = 2s + int16_t voltage_mv = (int16_t)(analogReadMilliVolts(analogPin)); + int16_t current_ma = randomizer; //0-255mA + int16_t power_mw = voltage_mv * current_ma / 1000; //calculate power in mW + Serial.printf("Updating DC voltage to %d mV, current to %d mA, power to %d mW\r\n", voltage_mv, current_ma, power_mw); + zbElectricalMeasurement.setDCMeasurement(ZIGBEE_DC_MEASUREMENT_TYPE_VOLTAGE, voltage_mv); + zbElectricalMeasurement.setDCMeasurement(ZIGBEE_DC_MEASUREMENT_TYPE_CURRENT, current_ma); + zbElectricalMeasurement.setDCMeasurement(ZIGBEE_DC_MEASUREMENT_TYPE_POWER, power_mw); + // Analog input supports reporting + zbElectricalMeasurement.reportDC(ZIGBEE_DC_MEASUREMENT_TYPE_VOLTAGE); + zbElectricalMeasurement.reportDC(ZIGBEE_DC_MEASUREMENT_TYPE_CURRENT); + zbElectricalMeasurement.reportDC(ZIGBEE_DC_MEASUREMENT_TYPE_POWER); + + randomizer += 10; + } + + // Checking button for factory reset and reporting + if (digitalRead(button) == LOW) { // Push button pressed + // Key debounce handling + delay(100); + int startTime = millis(); + while (digitalRead(button) == LOW) { + delay(50); + if ((millis() - startTime) > 3000) { + // If key pressed for more than 3secs, factory reset Zigbee and reboot + Serial.println("Resetting Zigbee to factory and rebooting in 1s."); + delay(1000); + Zigbee.factoryReset(); + } + } + } + delay(100); +} diff --git a/libraries/Zigbee/examples/Zigbee_Electrical_DC_Sensor/ci.json b/libraries/Zigbee/examples/Zigbee_Electrical_DC_Sensor/ci.json new file mode 100644 index 00000000000..ceacc367801 --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Electrical_DC_Sensor/ci.json @@ -0,0 +1,7 @@ +{ + "fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed", + "requires": [ + "CONFIG_SOC_IEEE802154_SUPPORTED=y", + "CONFIG_ZB_ENABLED=y" + ] +} diff --git a/libraries/Zigbee/examples/Zigbee_Illuminance_Sensor/README.md b/libraries/Zigbee/examples/Zigbee_Illuminance_Sensor/README.md new file mode 100644 index 00000000000..fe723696d5a --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Illuminance_Sensor/README.md @@ -0,0 +1,78 @@ +# Arduino-ESP32 Zigbee Illuminance Sensor Example + +This example demonstrates how to use the Zigbee library to create an end device illuminance sensor and use it as a Home Automation (HA) extended illuminance sensor. + +# Supported Targets + +Currently, this example supports the following targets. + +| Supported Targets | ESP32-C6 | ESP32-H2 | +| ----------------- | -------- | -------- | + +## Illuminance Sensor Functions + +1. Initialize a Zigbee illuminance sensor. +2. Measure illuminance value. +3. Report the measured value to the Zigbee network. + +## Hardware Required + +* ESP32-H2 or ESP32-C6 development board +* A USB cable for power supply and programming +* Some kind of light sensor, such as a photoresistor + +### Configure the Project + +In this example the raw analog value of a light sensor is used to calculate illuminance. +Alter the calculation according to your use case and calibrate it to receive correct lux values. +Set the illuminance sensor GPIO by changing the `illuminance_sensor_pin` variable to the pin to the pin to which your sensor is connected. +Set the button GPIO by changing the `button` variable. By default, it's the pin `BOOT_PIN` (BOOT button on ESP32-C6 and ESP32-H2). + +#### Using Arduino IDE + +To get more information about the Espressif boards see [Espressif Development Kits](https://www.espressif.com/en/products/devkits). + +* Before Compile/Verify, select the correct board: `Tools -> Board`. +* Select the End device Zigbee mode: `Tools -> Zigbee mode: Zigbee ED (end device)` +* Select Partition Scheme for Zigbee: `Tools -> Partition Scheme: Zigbee 4MB with spiffs` +* Enable USB CDC to be able to use the serial monitor: `Tools -> USB CDC On Boot: Enabled` +* Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port. +* Optional: Set debug level to verbose to see all logs from Zigbee stack: `Tools -> Core Debug Level: Verbose`. + +## Troubleshooting + +If the End device flashed with this example is not connecting to the coordinator, erase the flash of the End device before flashing the example to the board. It is recommended to do this if you re-flash the coordinator. +You can do the following: + +* In the Arduino IDE go to the Tools menu and set `Erase All Flash Before Sketch Upload` to `Enabled`. +* Add to the sketch `Zigbee.factoryReset();` to reset the device and Zigbee stack. + +By default, the coordinator network is closed after rebooting or flashing new firmware. +To open the network you have 2 options: + +* Open network after reboot by setting `Zigbee.setRebootOpenNetwork(time);` before calling `Zigbee.begin();`. +* In application you can anytime call `Zigbee.openNetwork(time);` to open the network for devices to join. + +***Important: Make sure that you are using a good quality USB cable with data lines and that you have a reliable power source*** + +* **LED not blinking:** Check the wiring connection and the IO selection. +* **Programming Fail:** If the programming/flash procedure fails, try reducing the serial connection speed. +* **COM port not detected:** Check the USB cable and the USB to Serial driver installation. + +If the error persists, you can ask for help at the official [ESP32 forum](https://esp32.com) or see [Contribute](#contribute). + +## Contribute + +To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst) + +If you have any **feedback** or **issue** to report on this example/library, please open an issue or fix it by creating a new PR. Contributions are more than welcome! + +Before creating a new issue, be sure to try Troubleshooting and check if the same issue was already created by someone else. + +## Resources + +* Official ESP32 Forum: [Link](https://esp32.com) +* Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) +* ESP32-C6 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf) +* ESP32-H2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf) +* Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com) diff --git a/libraries/Zigbee/examples/Zigbee_Illuminance_Sensor/Zigbee_Illuminance_Sensor.ino b/libraries/Zigbee/examples/Zigbee_Illuminance_Sensor/Zigbee_Illuminance_Sensor.ino new file mode 100644 index 00000000000..bbb2cba569f --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Illuminance_Sensor/Zigbee_Illuminance_Sensor.ino @@ -0,0 +1,141 @@ +// Copyright 2025 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +/** + * @brief This example demonstrates Zigbee illuminance sensor. + * + * The example demonstrates how to use Zigbee library to create a end device illuminance sensor. + * The illuminance sensor is a Zigbee end device, which is controlled by a Zigbee coordinator. + * + * Proper Zigbee mode must be selected in Tools->Zigbee mode + * and also the correct partition scheme must be selected in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by MikaFromTheRoof (https://github.com/MikaFromTheRoof) + */ + +#ifndef ZIGBEE_MODE_ED +#error "Zigbee end device mode is not selected in Tools->Zigbee mode" +#endif + +#include "Zigbee.h" + +#define ZIGBEE_ILLUMINANCE_SENSOR_ENDPOINT 9 +uint8_t button = BOOT_PIN; +uint8_t illuminance_sensor_pin = 6; // Insert the analog pin to which the sensor (e.g. photoresistor) is connected + +ZigbeeIlluminanceSensor zbIlluminanceSensor = ZigbeeIlluminanceSensor(ZIGBEE_ILLUMINANCE_SENSOR_ENDPOINT); + +/********************* Illuminance sensor **************************/ +static void illuminance_sensor_value_update(void *arg) { + for (;;) { + // read the raw analog value from the sensor + int lsens_analog_raw = analogRead(illuminance_sensor_pin); + Serial.printf("[Illuminance Sensor] raw analog value: %d\r\n", lsens_analog_raw); + + // conversion into zigbee raw illuminance value (typically between 0 in darkness and 50000 in direct sunlight) + // depends on the value range of the raw analog sensor values and will need calibration for correct lux values + // for demonstration purpose map the 12-bit ADC value (0-4095) to Zigbee illuminance range (0-50000) + int lsens_illuminance_raw = map(lsens_analog_raw, 0, 4095, 0, 50000); + Serial.printf("[Illuminance Sensor] raw illuminance value: %d\r\n", lsens_illuminance_raw); + + // according to zigbee documentation the formular 10^(lsens_illuminance_raw/10000)-1 can be used to calculate lux value from raw illuminance value + // Note: Zigbee2MQTT seems to be using the formular 10^(lsens_illuminance_raw/10000) instead (without -1) + int lsens_illuminance_lux = round(pow(10, (lsens_illuminance_raw / 10000.0)) - 1); + Serial.printf("[Illuminance Sensor] lux value: %d lux\r\n", lsens_illuminance_lux); + + // Update illuminance in illuminance sensor EP + zbIlluminanceSensor.setIlluminance(lsens_illuminance_raw); // use raw illuminance here! + + delay(1000); // reduce delay (in ms), if you want your device to react more quickly to changes in illuminance + } +} + +/********************* Arduino functions **************************/ +void setup() { + Serial.begin(115200); + + // Optional: configure analog input + analogSetAttenuation(ADC_11db); // set analog to digital converter (ADC) attenuation to 11 dB (up to ~3.3V input) + analogReadResolution(12); // set analog read resolution to 12 bits (value range from 0 to 4095), 12 is default + + // Init button for factory reset + pinMode(button, INPUT_PULLUP); + + // Optional: Set Zigbee device name and model + zbIlluminanceSensor.setManufacturerAndModel("Espressif", "ZigbeeIlluminanceSensor"); + + // Optional: Set power source (choose between ZB_POWER_SOURCE_MAINS and ZB_POWER_SOURCE_BATTERY), defaults to unknown + zbIlluminanceSensor.setPowerSource(ZB_POWER_SOURCE_MAINS); + + // Set minimum and maximum for raw illuminance value (0 min and 50000 max equals to 0 lux - 100,000 lux) + zbIlluminanceSensor.setMinMaxValue(0, 50000); + + // Optional: Set tolerance for raw illuminance value + zbIlluminanceSensor.setTolerance(1); + + // Add endpoint to Zigbee Core + Serial.println("Adding Zigbee illuminance sensor endpoint to Zigbee Core"); + Zigbee.addEndpoint(&zbIlluminanceSensor); + + Serial.println("Starting Zigbee..."); + // When all EPs are registered, start Zigbee in End Device mode + if (!Zigbee.begin()) { + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting..."); + ESP.restart(); + } else { + Serial.println("Zigbee started successfully!"); + } + Serial.println("Connecting to network"); + while (!Zigbee.connected()) { + Serial.print("."); + delay(100); + } + Serial.println(); + + // Start illuminance sensor reading task + xTaskCreate(illuminance_sensor_value_update, "illuminance_sensor_update", 2048, NULL, 10, NULL); + + // Set reporting schedule for illuminance value measurement in seconds, must be called after Zigbee.begin() + // min_interval and max_interval in seconds, delta + // if min = 1 and max = 0, delta = 1000, reporting is sent when raw illuminance value changes by 1000, but at most once per second + // if min = 0 and max = 10, delta = 1000, reporting is sent every 10 seconds or if raw illuminance value changes by 1000 + // if min = 0, max = 10 and delta = 0, reporting is sent every 10 seconds regardless of illuminance change + // Note: On pairing with Zigbee Home Automation or Zigbee2MQTT the reporting schedule will most likely be overwritten with their default settings + zbIlluminanceSensor.setReporting(1, 0, 1000); +} + +/********************* Main loop **************************/ +void loop() { + // Checking button for factory reset + if (digitalRead(button) == LOW) { // Push button pressed + // Key debounce handling + delay(100); + int startTime = millis(); + while (digitalRead(button) == LOW) { + delay(50); + if ((millis() - startTime) > 3000) { + // If key pressed for more than 3 secs, factory reset Zigbee and reboot + Serial.println("Resetting Zigbee to factory and rebooting in 1s"); + delay(1000); + Zigbee.factoryReset(); + } + } + // force report of illuminance when button is pressed + zbIlluminanceSensor.report(); + } + delay(100); +} diff --git a/libraries/Zigbee/examples/Zigbee_Illuminance_Sensor/ci.json b/libraries/Zigbee/examples/Zigbee_Illuminance_Sensor/ci.json new file mode 100644 index 00000000000..ceacc367801 --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Illuminance_Sensor/ci.json @@ -0,0 +1,7 @@ +{ + "fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed", + "requires": [ + "CONFIG_SOC_IEEE802154_SUPPORTED=y", + "CONFIG_ZB_ENABLED=y" + ] +} diff --git a/libraries/Zigbee/examples/Zigbee_On_Off_MultiSwitch/README.md b/libraries/Zigbee/examples/Zigbee_On_Off_MultiSwitch/README.md new file mode 100644 index 00000000000..7ec806a5a62 --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_On_Off_MultiSwitch/README.md @@ -0,0 +1,110 @@ +# Arduino-ESP32 Zigbee Multi-Switch Example + +This example demonstrates how to configure a Zigbee device as a multi-switch controller that can control up to three different Zigbee lights independently. The switch can operate in either coordinator or router mode, making it compatible with Home Assistant integration. + +# Supported Targets + +Currently, this example supports the following targets. + +| Supported Targets | ESP32-C6 | ESP32-H2 | +| ----------------- | -------- | -------- | + +## Hardware Required + +* One development board (ESP32-H2 or ESP32-C6) acting as Zigbee multi-switch controller +* One or more Zigbee light devices (loaded with Zigbee_On_Off_Light example) +* A USB cable for power supply and programming + +### Configure the Project + +The example uses the BOOT button (pin 9) on ESP32-C6 and ESP32-H2 as the physical switch input. The switch can be configured to operate in two modes: + +1. **Coordinator Mode**: For running your own Zigbee network +2. **Router Mode**: For Home Assistant integration + +#### Using Arduino IDE + +To get more information about the Espressif boards see [Espressif Development Kits](https://www.espressif.com/en/products/devkits). + +* Before Compile/Verify, select the correct board: `Tools -> Board` +* Select the Zigbee mode: `Tools -> Zigbee mode: Zigbee ZCZR (coordinator/router)` +* Select Partition Scheme for Zigbee: `Tools -> Partition Scheme: Zigbee 4MB with spiffs` +* Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port +* Optional: Set debug level to verbose to see all logs from Zigbee stack: `Tools -> Core Debug Level: Verbose` + +## Features + +The multi-switch example provides the following functionality: + +1. **Light Configuration** + - Configure up to 3 different lights using their endpoint and IEEE address + - Configuration is stored in NVS (Non-Volatile Storage) and persists after power loss + - Remove configured lights when needed + +2. **Control Commands** + - Control all bound lights simultaneously: + - Turn all bound lights ON + - Turn all bound lights OFF + - Toggle all bound lights + - Control individual lights (1-3): + - Turn light ON + - Turn light OFF + - Toggle light + +3. **Network Management** + - Factory reset capability + - Open network for device joining + - View bound devices and current light configurations + +## Serial Commands + +The example accepts the following commands through the serial interface: + +* `config` - Configure a new light (requires light number, endpoint, and IEEE address) +* `remove` - Remove a configured light +* `on` - Turn all bound lights ON +* `off` - Turn all bound lights OFF +* `toggle` - Toggle all bound lights +* `1on`, `2on`, `3on` - Turn individual light ON +* `1off`, `2off`, `3off` - Turn individual light OFF +* `1toggle`, `2toggle`, `3toggle` - Toggle individual light +* `freset` - Perform factory reset +* `open_network` - Open network for device joining (only for coordinator role) + +## Troubleshooting + +If the End device flashed with the example `Zigbee_On_Off_Light` is not connecting to the coordinator, erase the flash of the End device before flashing the example to the board. It is recommended to do this if you re-flash the coordinator. +You can do the following: + +* In the Arduino IDE go to the Tools menu and set `Erase All Flash Before Sketch Upload` to `Enabled` +* In the `Zigbee_On_Off_Light` example sketch call `Zigbee.factoryReset()` + +By default, the coordinator network is closed after rebooting or flashing new firmware. +To open the network you have 2 options: + +* Open network after reboot by setting `Zigbee.setRebootOpenNetwork(time)` before calling `Zigbee.begin()` +* In application you can anytime call `Zigbee.openNetwork(time)` to open the network for devices to join + +***Important: Make sure you are using a good quality USB cable and that you have a reliable power source*** + +* **LED not blinking:** Check the wiring connection and the IO selection +* **Programming Fail:** If the programming/flash procedure fails, try reducing the serial connection speed +* **COM port not detected:** Check the USB cable and the USB to Serial driver installation + +If the error persists, you can ask for help at the official [ESP32 forum](https://esp32.com) or see [Contribute](#contribute). + +## Contribute + +To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst) + +If you have any **feedback** or **issue** to report on this example/library, please open an issue or fix it by creating a new PR. Contributions are more than welcome! + +Before creating a new issue, be sure to try Troubleshooting and check if the same issue was already created by someone else. + +## Resources + +* Official ESP32 Forum: [Link](https://esp32.com) +* Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) +* ESP32-C6 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf) +* ESP32-H2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf) +* Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com) diff --git a/libraries/Zigbee/examples/Zigbee_On_Off_MultiSwitch/Zigbee_On_Off_MultiSwitch.ino b/libraries/Zigbee/examples/Zigbee_On_Off_MultiSwitch/Zigbee_On_Off_MultiSwitch.ino new file mode 100644 index 00000000000..63e342b2cd0 --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_On_Off_MultiSwitch/Zigbee_On_Off_MultiSwitch.ino @@ -0,0 +1,274 @@ +// Copyright 2025 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +/** + * @brief This example demonstrates simple Zigbee multi-light switch. + * + * The example demonstrates how to use Zigbee library to control multiple light bulbs. + * The light bulbs are Zigbee devices, which are controlled by a Zigbee coordinator/router (Multi-Switch). + * Settings are stored in NVS to not be lost after power loss. + * Configuring and controlling the lights is done via serial input. + * + * Proper Zigbee mode must be selected in Tools->Zigbee mode + * and also the correct partition scheme must be selected in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/) + */ + +#ifndef ZIGBEE_MODE_ZCZR +#error "Zigbee coordinator mode is not selected in Tools->Zigbee mode" +#endif + +#include "Zigbee.h" +#include + +#define ZIGBEE_ROLE ZIGBEE_ROUTER // ZIGBEE_ROUTER for HomeAssistant integration, ZIGBEE_COORDINATOR for running own network + +/* Zigbee switch configuration */ +#define SWITCH_ENDPOINT_NUMBER 1 + +uint8_t button = BOOT_PIN; + +ZigbeeSwitch zbSwitch = ZigbeeSwitch(SWITCH_ENDPOINT_NUMBER); + +int buttonState; +int lastButtonState = LOW; +unsigned long lastDebounceTime = 0; // the last time the output pin was toggled +unsigned long debounceDelay = 50; // the debounce time; increase if the output flickers + +// To be stored in NVS to not be lost after power loss +Preferences prefs; + +zb_device_params_t light_1; +zb_device_params_t light_2; +zb_device_params_t light_3; + +void storeLightParams(zb_device_params_t *light, int light_number) { + char key[10]; + snprintf(key, sizeof(key), "light_%d", light_number); + prefs.putBytes(key, light, sizeof(zb_device_params_t)); +} + +void loadLightParams(zb_device_params_t *light, int light_number) { + char key[10]; + snprintf(key, sizeof(key), "light_%d", light_number); + prefs.getBytes(key, light, sizeof(zb_device_params_t)); +} + +/********************* Arduino functions **************************/ +void setup() { + Serial.begin(115200); + + // Initialize Preferences + prefs.begin("lights", false); // false means read/write mode + + // Load saved light parameters + loadLightParams(&light_1, 1); + loadLightParams(&light_2, 2); + loadLightParams(&light_3, 3); + + // Init button switch + pinMode(button, INPUT_PULLUP); + + // Set Zigbee device name and model + zbSwitch.setManufacturerAndModel("Espressif", "ZBMultiSwitch"); + + // Set binding settings depending on the role + if (ZIGBEE_ROLE == ZIGBEE_COORDINATOR) { + zbSwitch.allowMultipleBinding(true); // To allow binding multiple lights to the switch + } else { + zbSwitch.setManualBinding(true); //Set manual binding to true, so binding is done on Home Assistant side + } + + // Add endpoint to Zigbee Core + Serial.println("Adding ZigbeeSwitch endpoint to Zigbee Core"); + Zigbee.addEndpoint(&zbSwitch); + + // When all EPs are registered, start Zigbee with given role + if (!Zigbee.begin(ZIGBEE_ROLE)) { + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting..."); + ESP.restart(); + } + + Serial.println("Connecting to network"); + while (!Zigbee.connected()) { + Serial.print("."); + delay(100); + } + Serial.println(); +} + +void loop() { + // Handle button switch in loop() + if (digitalRead(button) == LOW) { // Push button pressed + // Key debounce handling + while (digitalRead(button) == LOW) { + delay(50); + } + // Print bound devices + Serial.println("Bound devices:"); + zbSwitch.printBoundDevices(Serial); + Serial.println("Lights configured:"); + Serial.printf("Light 1: %d %s\n", light_1.endpoint, Zigbee.formatIEEEAddress(light_1.ieee_addr)); + Serial.printf("Light 2: %d %s\n", light_2.endpoint, Zigbee.formatIEEEAddress(light_2.ieee_addr)); + Serial.printf("Light 3: %d %s\n", light_3.endpoint, Zigbee.formatIEEEAddress(light_3.ieee_addr)); + } + // Handle serial input to configure and control the lights + if (Serial.available()) { + String command = Serial.readString(); + Serial.println("Command: " + command); + + if (command == "config") { + //wait for light number, endpoint and ieee address + Serial.println("Enter light number (1-3):"); + while (!Serial.available()) { + delay(100); + } + int light_number = Serial.parseInt(); + Serial.println("Enter endpoint:"); + while (!Serial.available()) { + delay(100); + } + int endpoint = Serial.parseInt(); + Serial.println("Enter ieee address:"); + while (!Serial.available()) { + delay(100); + } + String ieee_address = Serial.readStringUntil('\n'); + ieee_address.trim(); + //convert ieee address to uint8_t array (format in string is 00:00:00:00:00:00:00:00) + uint8_t ieee_address_array[8]; + int index = 0; + bool valid = true; + + // Check if the string has the correct format (8 hex pairs with colons) + if (ieee_address.length() != 23) { // 8 pairs * 2 + 7 colons + Serial.println("Invalid IEEE address format. Expected format: 00:00:00:00:00:00:00:00"); + valid = false; + } else { + for (int i = 0; i < ieee_address.length() && index < 8 && valid; i += 3) { + // Check for colon at expected positions + if (i > 0 && ieee_address.charAt(i - 1) != ':') { + valid = false; + break; + } + // Convert two hex characters to a byte + char hex[3] = {ieee_address.charAt(i), ieee_address.charAt(i + 1), '\0'}; + char *endptr; + long value = strtol(hex, &endptr, 16); + if (*endptr != '\0' || value < 0 || value > 255) { + valid = false; + break; + } + // Store bytes in reverse order to match Zigbee standard + ieee_address_array[7 - index++] = (uint8_t)value; + } + } + + if (!valid || index != 8) { + Serial.println("Invalid IEEE address. Please enter a valid address in format: 00:00:00:00:00:00:00:00"); + return; + } + //set the light parameters + if (light_number == 1) { + light_1.endpoint = endpoint; + memcpy(light_1.ieee_addr, ieee_address_array, 8); + storeLightParams(&light_1, 1); + } else if (light_number == 2) { + light_2.endpoint = endpoint; + memcpy(light_2.ieee_addr, ieee_address_array, 8); + storeLightParams(&light_2, 2); + } else if (light_number == 3) { + light_3.endpoint = endpoint; + memcpy(light_3.ieee_addr, ieee_address_array, 8); + storeLightParams(&light_3, 3); + } + Serial.printf("Light %d configured\n", light_number); + } else if (command == "remove") { + //wait for light number + Serial.println("Enter light number (1-3):"); + while (!Serial.available()) { + delay(100); + } + int light_number = Serial.parseInt(); + uint8_t ieee_address_empty[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + if (light_number == 1) { + light_1.endpoint = 0; + memcpy(light_1.ieee_addr, ieee_address_empty, 8); + storeLightParams(&light_1, 1); + } else if (light_number == 2) { + light_2.endpoint = 0; + memcpy(light_2.ieee_addr, ieee_address_empty, 8); + storeLightParams(&light_2, 2); + } else if (light_number == 3) { + light_3.endpoint = 0; + memcpy(light_3.ieee_addr, ieee_address_empty, 8); + storeLightParams(&light_3, 3); + } + Serial.printf("Light %d removed\n", light_number); + } else if (command == "on") { + Serial.println(" --> SIG Input : All Lights ON"); + zbSwitch.lightOn(); + } else if (command == "off") { + Serial.println(" --> SIG Input : All Lights OFF"); + zbSwitch.lightOff(); + } else if (command == "toggle") { + Serial.println(" --> SIG Input : All Lights Toggle"); + zbSwitch.lightToggle(); + } else if (command == "1on") { + Serial.println(" --> SIG Input : Light 1 ON"); + zbSwitch.lightOn(light_1.endpoint, light_1.ieee_addr); + } else if (command == "1off") { + Serial.println(" --> SIG Input : Light 1 OFF"); + zbSwitch.lightOff(light_1.endpoint, light_1.ieee_addr); + } else if (command == "1toggle") { + Serial.println(" --> SIG Input : Light 1 Toggle"); + zbSwitch.lightToggle(light_1.endpoint, light_1.ieee_addr); + } else if (command == "2on") { + Serial.println(" --> SIG Input : Light 2 ON"); + zbSwitch.lightOn(light_2.endpoint, light_2.ieee_addr); + } else if (command == "2off") { + Serial.println(" --> SIG Input : Light 2 OFF"); + zbSwitch.lightOff(light_2.endpoint, light_2.ieee_addr); + } else if (command == "2toggle") { + Serial.println(" --> SIG Input : Light 2 Toggle"); + zbSwitch.lightToggle(light_2.endpoint, light_2.ieee_addr); + } else if (command == "3on") { + Serial.println(" --> SIG Input : Light 3 ON"); + zbSwitch.lightOn(light_3.endpoint, light_3.ieee_addr); + } else if (command == "3off") { + Serial.println(" --> SIG Input : Light 3 OFF"); + zbSwitch.lightOff(light_3.endpoint, light_3.ieee_addr); + } else if (command == "3toggle") { + Serial.println(" --> SIG Input : Light 3 Toggle"); + zbSwitch.lightToggle(light_3.endpoint, light_3.ieee_addr); + } else if (command == "freset") { + Serial.println(" --> SIG Input : Factory Reset!"); + delay(1500); + Zigbee.factoryReset(); + } else if (command == "open_network") { + Serial.println(" --> SIG Input : Open Network"); + if (ZIGBEE_ROLE == ZIGBEE_COORDINATOR) { + Zigbee.openNetwork(180); + } else { + Serial.println("Open network is only available for coordinator role"); + } + } else { + Serial.println("Unknown command"); + } + } +} diff --git a/libraries/Zigbee/examples/Zigbee_On_Off_MultiSwitch/ci.json b/libraries/Zigbee/examples/Zigbee_On_Off_MultiSwitch/ci.json new file mode 100644 index 00000000000..e79a477da11 --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_On_Off_MultiSwitch/ci.json @@ -0,0 +1,6 @@ +{ + "fqbn_append": "PartitionScheme=zigbee_zczr,ZigbeeMode=zczr", + "requires": [ + "CONFIG_SOC_IEEE802154_SUPPORTED=y" + ] +} diff --git a/libraries/Zigbee/examples/Zigbee_PM25_Sensor/README.md b/libraries/Zigbee/examples/Zigbee_PM25_Sensor/README.md new file mode 100644 index 00000000000..51bf11459b7 --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_PM25_Sensor/README.md @@ -0,0 +1,72 @@ +# Arduino-ESP32 PM2.5 Sensor + +This example shows how to configure the Zigbee end device and use it as a Home Automation (HA) simple sensor device type with particulate matter (PM2.5) measuring + +# Supported Targets + +Currently, this example supports the following targets. + +| Supported Targets | ESP32-C6 | ESP32-H2 | +| ----------------- | -------- | -------- | + +## Pressure + Flow Sensor Functions + + * After this board first starts up, it would be configured locally to report the PM2.5 on every 30 seconds. + * By clicking the button (BOOT) on this board, this board will immediately send a report of the current PM2.5 to the network. + +## Hardware Required + +* A USB cable for power supply and programming + +### Configure the Project + +In this example, the internal temperature sensor is used to demonstrate reading of the PM2.5 sensors. +Set the Button GPIO by changing the `button` variable. By default, it's the pin `BOOT_PIN` (BOOT button on ESP32-C6 and ESP32-H2). + +#### Using Arduino IDE + +To get more information about the Espressif boards see [Espressif Development Kits](https://www.espressif.com/en/products/devkits). + +* Before Compile/Verify, select the correct board: `Tools -> Board`. +* Select the End device Zigbee mode: `Tools -> Zigbee mode: Zigbee ED (end device)` +* Select Partition Scheme for Zigbee: `Tools -> Partition Scheme: Zigbee 4MB with spiffs` +* Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port. +* Optional: Set debug level to verbose to see all logs from Zigbee stack: `Tools -> Core Debug Level: Verbose`. + +## Troubleshooting + +If the End device flashed with this example is not connecting to the coordinator, erase the flash of the End device before flashing the example to the board. It is recommended to do this if you re-flash the coordinator. +You can do the following: + +* In the Arduino IDE go to the Tools menu and set `Erase All Flash Before Sketch Upload` to `Enabled`. +* Add to the sketch `Zigbee.factoryReset();` to reset the device and Zigbee stack. + +By default, the coordinator network is closed after rebooting or flashing new firmware. +To open the network you have 2 options: + +* Open network after reboot by setting `Zigbee.setRebootOpenNetwork(time);` before calling `Zigbee.begin();`. +* In application you can anytime call `Zigbee.openNetwork(time);` to open the network for devices to join. + +***Important: Make sure you are using a good quality USB cable and that you have a reliable power source*** + +* **LED not blinking:** Check the wiring connection and the IO selection. +* **Programming Fail:** If the programming/flash procedure fails, try reducing the serial connection speed. +* **COM port not detected:** Check the USB cable and the USB to Serial driver installation. + +If the error persists, you can ask for help at the official [ESP32 forum](https://esp32.com) or see [Contribute](#contribute). + +## Contribute + +To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst) + +If you have any **feedback** or **issue** to report on this example/library, please open an issue or fix it by creating a new PR. Contributions are more than welcome! + +Before creating a new issue, be sure to try Troubleshooting and check if the same issue was already created by someone else. + +## Resources + +* Official ESP32 Forum: [Link](https://esp32.com) +* Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) +* ESP32-C6 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf) +* ESP32-H2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf) +* Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com) diff --git a/libraries/Zigbee/examples/Zigbee_PM25_Sensor/Zigbee_PM25_Sensor.ino b/libraries/Zigbee/examples/Zigbee_PM25_Sensor/Zigbee_PM25_Sensor.ino new file mode 100644 index 00000000000..a98d697f700 --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_PM25_Sensor/Zigbee_PM25_Sensor.ino @@ -0,0 +1,109 @@ +// Copyright 2024 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +/** + * @brief This example demonstrates Zigbee PM2.5 sensor. + * + * The example demonstrates how to use Zigbee library to create a end device PM2.5 sensor. + * + * Proper Zigbee mode must be selected in Tools->Zigbee mode + * and also the correct partition scheme must be selected in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/) + */ + +#ifndef ZIGBEE_MODE_ED +#error "Zigbee end device mode is not selected in Tools->Zigbee mode" +#endif + +#include "Zigbee.h" + +/* Zigbee PM2.5 sensor configuration */ +#define PM2_5_SENSOR_ENDPOINT_NUMBER 1 +uint8_t button = BOOT_PIN; + +ZigbeePM25Sensor zbPM25Sensor = ZigbeePM25Sensor(PM2_5_SENSOR_ENDPOINT_NUMBER); + +void setup() { + Serial.begin(115200); + + // Init button switch + pinMode(button, INPUT_PULLUP); + + // Optional: set Zigbee device name and model + zbPM25Sensor.setManufacturerAndModel("Espressif", "ZigbeePM25Sensor"); + + // Set minimum and maximum PM2.5 measurement value in µg/m³ + zbPM25Sensor.setMinMaxValue(0, 350); + + // Set tolerance for PM2.5 measurement in µg/m³ + zbPM25Sensor.setTolerance(0.1); + + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbPM25Sensor); + + Serial.println("Starting Zigbee..."); + // When all EPs are registered, start Zigbee in End Device mode + if (!Zigbee.begin()) { + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting..."); + ESP.restart(); + } else { + Serial.println("Zigbee started successfully!"); + } + Serial.println("Connecting to network"); + while (!Zigbee.connected()) { + Serial.print("."); + delay(100); + } + Serial.println(); + + // Set reporting interval for PM2.5 measurement to be done every 30 seconds, must be called after Zigbee.begin() + // min_interval and max_interval in seconds, delta (PM2.5 change in µg/m³) + // if min = 1 and max = 0, reporting is sent only when PM2.5 changes by delta + // if min = 0 and max = 10, reporting is sent every 10 seconds or when PM2.5 changes by delta + // if min = 0, max = 10 and delta = 0, reporting is sent every 10 seconds regardless of delta change + zbPM25Sensor.setReporting(0, 30, 0); +} + +void loop() { + static uint32_t timeCounter = 0; + // Read PM2.5 sensor every 2s + if (!(timeCounter++ % 20)) { // delaying for 100ms x 20 = 2s + // Read sensor value - here is chip temperature used + 50 as a dummy value for demonstration + float pm25_value = 50.5 + temperatureRead(); + Serial.printf("Updating PM2.5 sensor value to %0.1f µg/m³\r\n", pm25_value); + zbPM25Sensor.setPM25(pm25_value); + } + + // Checking button for factory reset and reporting + if (digitalRead(button) == LOW) { // Push button pressed + // Key debounce handling + delay(100); + int startTime = millis(); + while (digitalRead(button) == LOW) { + delay(50); + if ((millis() - startTime) > 3000) { + // If key pressed for more than 3secs, factory reset Zigbee and reboot + Serial.println("Resetting Zigbee to factory and rebooting in 1s."); + delay(1000); + Zigbee.factoryReset(); + } + } + zbPM25Sensor.report(); + } + delay(100); +} diff --git a/libraries/Zigbee/examples/Zigbee_PM25_Sensor/ci.json b/libraries/Zigbee/examples/Zigbee_PM25_Sensor/ci.json new file mode 100644 index 00000000000..ceacc367801 --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_PM25_Sensor/ci.json @@ -0,0 +1,7 @@ +{ + "fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed", + "requires": [ + "CONFIG_SOC_IEEE802154_SUPPORTED=y", + "CONFIG_ZB_ENABLED=y" + ] +} diff --git a/libraries/Zigbee/examples/Zigbee_Power_Outlet/README.md b/libraries/Zigbee/examples/Zigbee_Power_Outlet/README.md new file mode 100644 index 00000000000..996aa36d1a3 --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Power_Outlet/README.md @@ -0,0 +1,61 @@ +@ -0,0 +1,68 @@ +# Arduino-ESP32 Zigbee On/Off Power Outlet Example + +This example shows how to configure Zigbee Router device and use it as a Home Automation (HA) on/off power outlet. + +# Supported Targets + +Currently, this example supports the following targets. + +| Supported Targets | ESP32-C6 | ESP32-H2 | +| ----------------- | -------- | -------- | + +## Hardware Required + +* A USB cable for power supply and programming. + +### Configure the Project + +Set the Button GPIO by changing the `button` definition. By default, it's the pin `9` (BOOT button on ESP32-C6 and ESP32-H2). + +#### Using Arduino IDE + +To get more information about the Espressif boards see [Espressif Development Kits](https://www.espressif.com/en/products/devkits). + +* Before Compile/Verify, select the correct board: `Tools -> Board`. +* Select the Coordinator Zigbee mode: `Tools -> Zigbee mode: Zigbee ZCZR (coordinator/router)`. +* Select Partition Scheme for Zigbee: `Tools -> Partition Scheme: Zigbee ZCZR 4MB with spiffs`. +* Select the COM port: `Tools -> Port: xxx where the `xxx` is the detected COM port. +* Optional: Set debug level to verbose to see all logs from Zigbee stack: `Tools -> Core Debug Level: Verbose`. + +## Troubleshooting + +If the device flashed with the example `Zigbee_Power_Outlet` is not connecting to the coordinator, erase the flash of the device before flashing the example to the board. It is recommended to do this if you re-flash the coordinator or do some big changes in the application code. +You can do the following: + +* In the Arduino IDE go to the Tools menu and set `Erase All Flash Before Sketch Upload` to `Enabled`. +* In the `Zigbee_Power_Outlet` example sketch call `Zigbee.factoryReset();`. + +***Important: Make sure you are using a good quality USB cable and that you have a reliable power source*** + +* **LED not blinking:** Check the wiring connection and the IO selection. +* **Programming Fail:** If the programming/flash procedure fails, try reducing the serial connection speed. +* **COM port not detected:** Check the USB cable and the USB to Serial driver installation. + +If the error persists, you can ask for help at the official [ESP32 forum](https://esp32.com) or see [Contribute](#contribute). + +## Contribute + +To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst) + +If you have any **feedback** or **issue** to report on this example/library, please open an issue or fix it by creating a new PR. Contributions are more than welcome! + +Before creating a new issue, be sure to try Troubleshooting and check if the same issue was already created by someone else. + +## Resources + +* Official ESP32 Forum: [Link](https://esp32.com) +* Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) +* ESP32-C6 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf) +* ESP32-H2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf) +* Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com) diff --git a/libraries/Zigbee/examples/Zigbee_Power_Outlet/Zigbee_Power_Outlet.ino b/libraries/Zigbee/examples/Zigbee_Power_Outlet/Zigbee_Power_Outlet.ino new file mode 100644 index 00000000000..d9fe1b7aefe --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Power_Outlet/Zigbee_Power_Outlet.ino @@ -0,0 +1,101 @@ +// Copyright 2025 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +/** + * @brief This example demonstrates simple Zigbee power outlet. + * + * The example demonstrates how to use Zigbee library to create a end device power outlet. + * The power outlet is a Zigbee end device, which is controlled by a Zigbee coordinator. + * + * Proper Zigbee mode must be selected in Tools->Zigbee mode + * and also the correct partition scheme must be selected in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by Ludovic Boué (https://github.com/lboue) + */ + +#ifndef ZIGBEE_MODE_ZCZR +#error "Zigbee router mode is not selected in Tools->Zigbee mode" +#endif + +#include "Zigbee.h" + +/* Zigbee power outlet configuration */ +#define ZIGBEE_OUTLET_ENDPOINT 1 +uint8_t led = RGB_BUILTIN; +uint8_t button = BOOT_PIN; + +ZigbeePowerOutlet zbOutlet = ZigbeePowerOutlet(ZIGBEE_OUTLET_ENDPOINT); + +/********************* RGB LED functions **************************/ +void setLED(bool value) { + digitalWrite(led, value); +} + +/********************* Arduino functions **************************/ +void setup() { + Serial.begin(115200); + + // Init LED and turn it OFF (if LED_PIN == RGB_BUILTIN, the rgbLedWrite() will be used under the hood) + pinMode(led, OUTPUT); + digitalWrite(led, LOW); + + // Init button for factory reset + pinMode(button, INPUT_PULLUP); + + //Optional: set Zigbee device name and model + zbOutlet.setManufacturerAndModel("Espressif", "ZBPowerOutlet"); + + // Set callback function for power outlet change + zbOutlet.onPowerOutletChange(setLED); + + //Add endpoint to Zigbee Core + Serial.println("Adding ZigbeePowerOutlet endpoint to Zigbee Core"); + Zigbee.addEndpoint(&zbOutlet); + + // When all EPs are registered, start Zigbee. By default acts as ZIGBEE_END_DEVICE + if (!Zigbee.begin(ZIGBEE_ROUTER)) { + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting..."); + ESP.restart(); + } + Serial.println("Connecting to network"); + while (!Zigbee.connected()) { + Serial.print("."); + delay(100); + } + Serial.println(); +} + +void loop() { + // Checking button for factory reset + if (digitalRead(button) == LOW) { // Push button pressed + // Key debounce handling + delay(100); + int startTime = millis(); + while (digitalRead(button) == LOW) { + delay(50); + if ((millis() - startTime) > 3000) { + // If key pressed for more than 3secs, factory reset Zigbee and reboot + Serial.println("Resetting Zigbee to factory and rebooting in 1s."); + delay(1000); + Zigbee.factoryReset(); + } + } + // Toggle state by pressing the button + zbOutlet.setState(!zbOutlet.getPowerOutletState()); + } + delay(100); +} diff --git a/libraries/Zigbee/examples/Zigbee_Power_Outlet/ci.json b/libraries/Zigbee/examples/Zigbee_Power_Outlet/ci.json new file mode 100644 index 00000000000..23decd7127c --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Power_Outlet/ci.json @@ -0,0 +1,7 @@ +{ + "fqbn_append": "PartitionScheme=zigbee_zczr,ZigbeeMode=zczr", + "requires": [ + "CONFIG_SOC_IEEE802154_SUPPORTED=y", + "CONFIG_ZB_ENABLED=y" + ] +} diff --git a/libraries/Zigbee/examples/Zigbee_Temp_Hum_Sensor_Sleepy/Zigbee_Temp_Hum_Sensor_Sleepy.ino b/libraries/Zigbee/examples/Zigbee_Temp_Hum_Sensor_Sleepy/Zigbee_Temp_Hum_Sensor_Sleepy.ino index 65df4b02957..e9d08d32175 100644 --- a/libraries/Zigbee/examples/Zigbee_Temp_Hum_Sensor_Sleepy/Zigbee_Temp_Hum_Sensor_Sleepy.ino +++ b/libraries/Zigbee/examples/Zigbee_Temp_Hum_Sensor_Sleepy/Zigbee_Temp_Hum_Sensor_Sleepy.ino @@ -77,7 +77,7 @@ void setup() { esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR); // Optional: set Zigbee device name and model - zbTempSensor.setManufacturerAndModel("Espressif", "SleepyZigbeeTempSensorTest"); + zbTempSensor.setManufacturerAndModel("Espressif", "SleepyZigbeeTempSensor"); // Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement) zbTempSensor.setMinMaxValue(10, 50); @@ -85,9 +85,9 @@ void setup() { // Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) zbTempSensor.setTolerance(1); - // Set power source to battery and set battery percentage to measured value (now 100% for demonstration) - // The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) anytime - zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100); + // Set power source to battery, battery percentage and battery voltage (now 100% and 3.5V for demonstration) + // The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) or zbTempSensor.setBatteryVoltage(voltage) anytime after Zigbee.begin() + zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100, 35); // Add humidity cluster to the temperature sensor device with min, max and tolerance values zbTempSensor.addHumiditySensor(0, 100, 1); @@ -99,11 +99,15 @@ void setup() { esp_zb_cfg_t zigbeeConfig = ZIGBEE_DEFAULT_ED_CONFIG(); zigbeeConfig.nwk_cfg.zed_cfg.keep_alive = 10000; + // For battery powered devices, it can be better to set timeout for Zigbee Begin to lower value to save battery + // If the timeout has been reached, the network channel mask will be reset and the device will try to connect again after reset (scanning all channels) + Zigbee.setTimeout(10000); // Set timeout for Zigbee Begin to 10s (default is 30s) + // When all EPs are registered, start Zigbee in End Device mode if (!Zigbee.begin(&zigbeeConfig, false)) { Serial.println("Zigbee failed to start!"); Serial.println("Rebooting..."); - ESP.restart(); + ESP.restart(); // If Zigbee failed to start, reboot the device and try again } Serial.println("Connecting to network"); while (!Zigbee.connected()) { @@ -129,7 +133,11 @@ void loop() { // If key pressed for more than 10secs, factory reset Zigbee and reboot Serial.println("Resetting Zigbee to factory and rebooting in 1s."); delay(1000); - Zigbee.factoryReset(); + // Optional set reset in factoryReset to false, to not restart device after erasing nvram, but set it to endless sleep manually instead + Zigbee.factoryReset(false); + Serial.println("Going to endless sleep, press RESET button or power off/on the device to wake up"); + esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_TIMER); + esp_deep_sleep_start(); } } } diff --git a/libraries/Zigbee/keywords.txt b/libraries/Zigbee/keywords.txt index 2eeed5878a7..4d4cd7d0606 100644 --- a/libraries/Zigbee/keywords.txt +++ b/libraries/Zigbee/keywords.txt @@ -29,6 +29,8 @@ ZigbeeGateway KEYWORD1 ZigbeeRangeExtender KEYWORD1 ZigbeeVibrationSensor KEYWORD1 ZigbeeWindowCovering KEYWORD1 +ZigbeeIlluminanceSensor KEYWORD1 +ZigbeePowerOutlet KEYWORD1 # Other zigbee_role_t KEYWORD1 @@ -123,6 +125,9 @@ setHumidity KEYWORD2 setHumidityReporting KEYWORD2 reportHumidity KEYWORD2 +# ZigbeeIlluminanceSensor +setIlluminance KEYWORD2 + # ZigbeeFlowSensor setFlow KEYWORD2 diff --git a/libraries/Zigbee/src/Zigbee.h b/libraries/Zigbee/src/Zigbee.h index e5f669ba899..b2e2e5dd027 100644 --- a/libraries/Zigbee/src/Zigbee.h +++ b/libraries/Zigbee/src/Zigbee.h @@ -7,22 +7,33 @@ #include "ZigbeeEP.h" // Endpoints -#include "ep/ZigbeeLight.h" +//// Switches +#include "ep/ZigbeeColorDimmerSwitch.h" #include "ep/ZigbeeSwitch.h" -#include "ep/ZigbeeDimmableLight.h" +//// Lights #include "ep/ZigbeeColorDimmableLight.h" -#include "ep/ZigbeeColorDimmerSwitch.h" -#include "ep/ZigbeeTempSensor.h" +#include "ep/ZigbeeDimmableLight.h" +#include "ep/ZigbeeLight.h" +//// Controllers #include "ep/ZigbeeThermostat.h" -#include "ep/ZigbeePressureSensor.h" +////Outlets +#include "ep/ZigbeePowerOutlet.h" +//// Sensors #include "ep/ZigbeeAnalog.h" -#include "ep/ZigbeeFlowSensor.h" -#include "ep/ZigbeeOccupancySensor.h" +#include "ep/ZigbeeBinary.h" #include "ep/ZigbeeCarbonDioxideSensor.h" #include "ep/ZigbeeContactSwitch.h" #include "ep/ZigbeeDoorWindowHandle.h" -#include "ep/ZigbeeWindowCovering.h" +#include "ep/ZigbeeElectricalMeasurement.h" +#include "ep/ZigbeeFlowSensor.h" +#include "ep/ZigbeeIlluminanceSensor.h" +#include "ep/ZigbeeOccupancySensor.h" +#include "ep/ZigbeePM25Sensor.h" +#include "ep/ZigbeePressureSensor.h" +#include "ep/ZigbeeTempSensor.h" #include "ep/ZigbeeVibrationSensor.h" -#include "ep/ZigbeeRangeExtender.h" -#include "ep/ZigbeeGateway.h" #include "ep/ZigbeeWindSpeedSensor.h" +#include "ep/ZigbeeWindowCovering.h" +//// Other +#include "ep/ZigbeeGateway.h" +#include "ep/ZigbeeRangeExtender.h" diff --git a/libraries/Zigbee/src/ZigbeeCore.cpp b/libraries/Zigbee/src/ZigbeeCore.cpp index bd5849bb4b8..c49dedb221f 100644 --- a/libraries/Zigbee/src/ZigbeeCore.cpp +++ b/libraries/Zigbee/src/ZigbeeCore.cpp @@ -5,10 +5,18 @@ #include "ZigbeeHandlers.cpp" #include "Arduino.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif +#include "zboss_api.h" +extern zb_ret_t zb_nvram_write_dataset(zb_nvram_dataset_types_t t); // rejoin scanning workaround +extern void zb_set_ed_node_descriptor(bool power_src, bool rx_on_when_idle, bool alloc_addr); // sleepy device power mode workaround +#ifdef __cplusplus +} +#endif -#define ZB_INIT_TIMEOUT 30000 // 30 seconds - -extern "C" void zb_set_ed_node_descriptor(bool power_src, bool rx_on_when_idle, bool alloc_addr); static bool edBatteryPowered = false; ZigbeeCore::ZigbeeCore() { @@ -18,10 +26,12 @@ ZigbeeCore::ZigbeeCore() { _primary_channel_mask = ESP_ZB_TRANSCEIVER_ALL_CHANNELS_MASK; _open_network = 0; _scan_status = ZB_SCAN_FAILED; + _begin_timeout = ZB_BEGIN_TIMEOUT_DEFAULT; _started = false; _connected = false; _scan_duration = 3; // default scan duration _rx_on_when_idle = true; + _debug = false; if (!lock) { lock = xSemaphoreCreateBinary(); if (lock == NULL) { @@ -32,6 +42,7 @@ ZigbeeCore::ZigbeeCore() { //forward declaration static esp_err_t zb_action_handler(esp_zb_core_action_callback_id_t callback_id, const void *message); +bool zb_apsde_data_indication_handler(esp_zb_apsde_data_ind_t ind); bool ZigbeeCore::begin(esp_zb_cfg_t *role_cfg, bool erase_nvs) { if (!zigbeeInit(role_cfg, erase_nvs)) { @@ -39,8 +50,11 @@ bool ZigbeeCore::begin(esp_zb_cfg_t *role_cfg, bool erase_nvs) { return false; } _role = (zigbee_role_t)role_cfg->esp_zb_role; - if (xSemaphoreTake(lock, ZB_INIT_TIMEOUT) != pdTRUE) { - log_e("ZigbeeCore begin timeout"); + if (xSemaphoreTake(lock, _begin_timeout) != pdTRUE) { + log_e("ZigbeeCore begin failed or timeout"); + if (_role != ZIGBEE_COORDINATOR) { // Only End Device and Router can rejoin + resetNVRAMChannelMask(); + } } return started(); } @@ -71,27 +85,35 @@ bool ZigbeeCore::begin(zigbee_role_t role, bool erase_nvs) { } default: log_e("Invalid Zigbee Role"); return false; } - if (!status || xSemaphoreTake(lock, ZB_INIT_TIMEOUT) != pdTRUE) { + if (!status || xSemaphoreTake(lock, _begin_timeout) != pdTRUE) { log_e("ZigbeeCore begin failed or timeout"); + if (_role != ZIGBEE_COORDINATOR) { // Only End Device and Router can rejoin + resetNVRAMChannelMask(); + } } return started(); } -void ZigbeeCore::addEndpoint(ZigbeeEP *ep) { +bool ZigbeeCore::addEndpoint(ZigbeeEP *ep) { ep_objects.push_back(ep); log_d("Endpoint: %d, Device ID: 0x%04x", ep->_endpoint, ep->_device_id); //Register clusters and ep_list to the ZigbeeCore class's ep_list if (ep->_ep_config.endpoint == 0 || ep->_cluster_list == nullptr) { log_e("Endpoint config or Cluster list is not initialized, EP not added to ZigbeeCore's EP list"); - return; + return false; } - + esp_err_t ret = ESP_OK; if (ep->_device_id == ESP_ZB_HA_HOME_GATEWAY_DEVICE_ID) { - esp_zb_ep_list_add_gateway_ep(_zb_ep_list, ep->_cluster_list, ep->_ep_config); + ret = esp_zb_ep_list_add_gateway_ep(_zb_ep_list, ep->_cluster_list, ep->_ep_config); } else { - esp_zb_ep_list_add_ep(_zb_ep_list, ep->_cluster_list, ep->_ep_config); + ret = esp_zb_ep_list_add_ep(_zb_ep_list, ep->_cluster_list, ep->_ep_config); + } + if (ret != ESP_OK) { + log_e("Failed to add endpoint: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; } + return true; } static void esp_zb_task(void *pvParameters) { @@ -154,6 +176,9 @@ bool ZigbeeCore::zigbeeInit(esp_zb_cfg_t *zb_cfg, bool erase_nvs) { return false; } + // Register APSDATA INDICATION handler to catch bind/unbind requests + esp_zb_aps_data_indication_handler_register(zb_apsde_data_indication_handler); + //Erase NVRAM before creating connection to new Coordinator if (erase_nvs) { esp_zb_nvram_erase_at_start(true); @@ -204,6 +229,13 @@ void ZigbeeCore::openNetwork(uint8_t time) { } } +void ZigbeeCore::closeNetwork() { + if (started()) { + log_v("Closing network"); + esp_zb_bdb_close_network(); + } +} + static void bdb_start_top_level_commissioning_cb(uint8_t mode_mask) { ESP_ERROR_CHECK(esp_zb_bdb_start_top_level_commissioning(mode_mask)); } @@ -215,11 +247,15 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) { esp_zb_app_signal_type_t sig_type = (esp_zb_app_signal_type_t)*p_sg_p; //coordinator variables esp_zb_zdo_signal_device_annce_params_t *dev_annce_params = NULL; + esp_zb_zdo_signal_leave_params_t *leave_params = NULL; + //router variables + esp_zb_zdo_signal_device_update_params_t *dev_update_params = NULL; //main switch switch (sig_type) { case ESP_ZB_ZDO_SIGNAL_SKIP_STARTUP: // Common log_i("Zigbee stack initialized"); + log_d("Zigbee channel mask: 0x%08x", esp_zb_get_channel_mask()); esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_INITIALIZATION); break; case ESP_ZB_BDB_SIGNAL_DEVICE_FIRST_START: // Common @@ -245,7 +281,9 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) { log_i("Opening network for joining for %d seconds", Zigbee._open_network); esp_zb_bdb_open_network(Zigbee._open_network); } else { - Zigbee._connected = true; + // Save the channel mask to NVRAM in case of reboot which may be on a different channel after a change in the network + Zigbee.setNVRAMChannelMask(1 << esp_zb_get_current_channel()); + Zigbee._connected = true; // Coordinator is always connected } Zigbee.searchBindings(); } @@ -265,6 +303,7 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) { extended_pan_id[7], extended_pan_id[6], extended_pan_id[5], extended_pan_id[4], extended_pan_id[3], extended_pan_id[2], extended_pan_id[1], extended_pan_id[0], esp_zb_get_pan_id(), esp_zb_get_current_channel(), esp_zb_get_short_address() ); + Zigbee._connected = true; esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_STEERING); } else { log_i("Restart network formation (status: %s)", esp_err_to_name(err_status)); @@ -289,6 +328,8 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) { extended_pan_id[0], esp_zb_get_pan_id(), esp_zb_get_current_channel(), esp_zb_get_short_address() ); Zigbee._connected = true; + // Set channel mask and write to NVRAM, so that the device will re-join the network faster after reboot (scan only on the current channel) + Zigbee.setNVRAMChannelMask(1 << esp_zb_get_current_channel()); } else { log_i("Network steering was not successful (status: %s)", esp_err_to_name(err_status)); esp_zb_scheduler_alarm((esp_zb_callback_t)bdb_start_top_level_commissioning_cb, ESP_ZB_BDB_MODE_NETWORK_STEERING, 1000); @@ -316,20 +357,60 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) { */ // for each endpoint in the list call the findEndpoint function if not bounded or allowed to bind multiple devices for (std::list::iterator it = Zigbee.ep_objects.begin(); it != Zigbee.ep_objects.end(); ++it) { - if (!(*it)->bound() || (*it)->epAllowMultipleBinding()) { - // Check if the device is already bound - bool found = false; - // Get the list of devices bound to the EP - std::list bound_devices = (*it)->getBoundDevices(); - for (std::list::iterator device = bound_devices.begin(); device != bound_devices.end(); ++device) { - if (((*device)->short_addr == dev_annce_params->device_short_addr) || (memcmp((*device)->ieee_addr, dev_annce_params->ieee_addr, 8) == 0)) { - found = true; - log_d("Device already bound to endpoint %d", (*it)->getEndpoint()); - break; + log_d("Checking endpoint %d", (*it)->getEndpoint()); + if (!(*it)->epUseManualBinding()) { + if (!(*it)->bound() || (*it)->epAllowMultipleBinding()) { + // Check if the device is already bound + bool found = false; + // Get the list of devices bound to the EP + std::list bound_devices = (*it)->getBoundDevices(); + for (std::list::iterator device = bound_devices.begin(); device != bound_devices.end(); ++device) { + if (((*device)->short_addr == dev_annce_params->device_short_addr) || (memcmp((*device)->ieee_addr, dev_annce_params->ieee_addr, 8) == 0)) { + found = true; + log_d("Device already bound to endpoint %d", (*it)->getEndpoint()); + break; + } + } + if (!found) { + log_d("Device not bound to endpoint %d and it is free to bound!", (*it)->getEndpoint()); + (*it)->findEndpoint(&cmd_req); + log_d("Endpoint %d is searching for device", (*it)->getEndpoint()); + break; // Only one endpoint per device } } - if (!found) { - (*it)->findEndpoint(&cmd_req); + } + } + } + break; + case ESP_ZB_ZDO_SIGNAL_DEVICE_UPDATE: // Router + if ((zigbee_role_t)Zigbee.getRole() == ZIGBEE_ROUTER) { + dev_update_params = (esp_zb_zdo_signal_device_update_params_t *)esp_zb_app_signal_get_params(p_sg_p); + log_i("New device commissioned or rejoined (short: 0x%04hx)", dev_update_params->short_addr); + esp_zb_zdo_match_desc_req_param_t cmd_req; + cmd_req.dst_nwk_addr = dev_update_params->short_addr; + cmd_req.addr_of_interest = dev_update_params->short_addr; + // for each endpoint in the list call the findEndpoint function if not bounded or allowed to bind multiple devices + for (std::list::iterator it = Zigbee.ep_objects.begin(); it != Zigbee.ep_objects.end(); ++it) { + log_d("Checking endpoint %d", (*it)->getEndpoint()); + if (!(*it)->epUseManualBinding()) { + if (!(*it)->bound() || (*it)->epAllowMultipleBinding()) { + // Check if the device is already bound + bool found = false; + // Get the list of devices bound to the EP + std::list bound_devices = (*it)->getBoundDevices(); + for (std::list::iterator device = bound_devices.begin(); device != bound_devices.end(); ++device) { + if (((*device)->short_addr == dev_update_params->short_addr) || (memcmp((*device)->ieee_addr, dev_update_params->long_addr, 8) == 0)) { + found = true; + log_d("Device already bound to endpoint %d", (*it)->getEndpoint()); + break; + } + } + log_d("Device not bound to endpoint %d and it is free to bound!", (*it)->getEndpoint()); + if (!found) { + (*it)->findEndpoint(&cmd_req); + log_d("Endpoint %d is searching for device", (*it)->getEndpoint()); + break; // Only one endpoint per device + } } } } @@ -347,18 +428,56 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) { } break; case ESP_ZB_ZDO_SIGNAL_LEAVE: // End Device + Router - // Device was removed from the network, factory reset the device + // Received signal to leave the network if ((zigbee_role_t)Zigbee.getRole() != ZIGBEE_COORDINATOR) { - Zigbee.factoryReset(); + leave_params = (esp_zb_zdo_signal_leave_params_t *)esp_zb_app_signal_get_params(p_sg_p); + log_v("Signal to leave the network, leave type: %d", leave_params->leave_type); + if (leave_params->leave_type == ESP_ZB_NWK_LEAVE_TYPE_RESET) { // Leave without rejoin -> Factory reset + log_i("Leave without rejoin, factory reset the device"); + Zigbee.factoryReset(true); + } else { // Leave with rejoin -> Rejoin the network, only reboot the device + log_i("Leave with rejoin, only reboot the device"); + ESP.restart(); + } } break; default: log_v("ZDO signal: %s (0x%x), status: %s", esp_zb_zdo_signal_to_string(sig_type), sig_type, esp_err_to_name(err_status)); break; } } -void ZigbeeCore::factoryReset() { - log_v("Factory resetting Zigbee stack, device will reboot"); - esp_zb_factory_reset(); +// APS DATA INDICATION HANDLER to catch bind/unbind requests +bool zb_apsde_data_indication_handler(esp_zb_apsde_data_ind_t ind) { + if (Zigbee.getDebugMode()) { + log_d("APSDE INDICATION - Received APSDE-DATA indication, status: %d", ind.status); + log_d( + "APSDE INDICATION - dst_endpoint: %d, src_endpoint: %d, dst_addr_mode: %d, src_addr_mode: %d, cluster_id: 0x%04x, asdu_length: %d", ind.dst_endpoint, + ind.src_endpoint, ind.dst_addr_mode, ind.src_addr_mode, ind.cluster_id, ind.asdu_length + ); + log_d( + "APSDE INDICATION - dst_short_addr: 0x%04x, src_short_addr: 0x%04x, profile_id: 0x%04x, security_status: %d, lqi: %d, rx_time: %d", ind.dst_short_addr, + ind.src_short_addr, ind.profile_id, ind.security_status, ind.lqi, ind.rx_time + ); + } + if (ind.status == 0x00) { + // Catch bind/unbind requests to update the bound devices list + if (ind.cluster_id == 0x21 || ind.cluster_id == 0x22) { + Zigbee.searchBindings(); + } + } else { + log_e("APSDE INDICATION - Invalid status of APSDE-DATA indication, error code: %d", ind.status); + } + return false; //False to let the stack process the message as usual +} + +void ZigbeeCore::factoryReset(bool restart) { + if (restart) { + log_v("Factory resetting Zigbee stack, device will reboot"); + esp_zb_factory_reset(); + } else { + log_v("Factory resetting Zigbee NVRAM to factory default"); + log_w("The device will not reboot, to take effect please reboot the device manually"); + esp_zb_zcl_reset_nvram_to_factory_default(); + } } void ZigbeeCore::scanCompleteCallback(esp_zb_zdp_status_t zdo_status, uint8_t count, esp_zb_network_descriptor_t *nwk_descriptor) { @@ -414,63 +533,194 @@ void ZigbeeCore::scanDelete() { _scan_status = ZB_SCAN_FAILED; } -// Recall bounded devices from the binding table after reboot +// Recall bounded devices from the binding table after reboot or when requested void ZigbeeCore::bindingTableCb(const esp_zb_zdo_binding_table_info_t *table_info, void *user_ctx) { - bool done = true; esp_zb_zdo_mgmt_bind_param_t *req = (esp_zb_zdo_mgmt_bind_param_t *)user_ctx; esp_zb_zdp_status_t zdo_status = (esp_zb_zdp_status_t)table_info->status; log_d("Binding table callback for address 0x%04x with status %d", req->dst_addr, zdo_status); + if (zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) { // Print binding table log simple log_d("Binding table info: total %d, index %d, count %d", table_info->total, table_info->index, table_info->count); if (table_info->total == 0) { log_d("No binding table entries found"); + // Clear all bound devices since there are no entries + for (std::list::iterator it = Zigbee.ep_objects.begin(); it != Zigbee.ep_objects.end(); ++it) { + log_d("Clearing bound devices for EP %d", (*it)->getEndpoint()); + (*it)->clearBoundDevices(); + } free(req); return; } + // Create a set to track found devices using both short and IEEE addresses + struct DeviceIdentifier { + uint8_t endpoint; + uint16_t short_addr; + esp_zb_ieee_addr_t ieee_addr; + bool is_ieee; + + bool operator<(const DeviceIdentifier &other) const { + if (endpoint != other.endpoint) { + return endpoint < other.endpoint; + } + if (is_ieee != other.is_ieee) { + return is_ieee < other.is_ieee; + } + if (is_ieee) { + return memcmp(ieee_addr, other.ieee_addr, sizeof(esp_zb_ieee_addr_t)) < 0; + } + return short_addr < other.short_addr; + } + }; + static std::set found_devices; + static std::vector all_records; + + // If this is the first chunk (index 0), clear the previous data + if (table_info->index == 0) { + found_devices.clear(); + all_records.clear(); + } + + // Add current records to our collection esp_zb_zdo_binding_table_record_t *record = table_info->record; for (int i = 0; i < table_info->count; i++) { log_d( - "Binding table record: src_endp %d, dst_endp %d, cluster_id 0x%04x, dst_addr_mode %d", record->src_endp, record->dst_endp, record->cluster_id, + "Processing record %d: src_endp %d, dst_endp %d, cluster_id 0x%04x, dst_addr_mode %d", i, record->src_endp, record->dst_endp, record->cluster_id, record->dst_addr_mode ); + all_records.push_back(*record); + record = record->next; + } - zb_device_params_t *device = (zb_device_params_t *)calloc(1, sizeof(zb_device_params_t)); - device->endpoint = record->dst_endp; - if (record->dst_addr_mode == ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT || record->dst_addr_mode == ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT) { - device->short_addr = record->dst_address.addr_short; - } else { //ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT - memcpy(device->ieee_addr, record->dst_address.addr_long, sizeof(esp_zb_ieee_addr_t)); + // If this is not the last chunk, request the next one + if (table_info->index + table_info->count < table_info->total) { + log_d("Requesting next chunk of binding table (current index: %d, count: %d, total: %d)", table_info->index, table_info->count, table_info->total); + req->start_index = table_info->index + table_info->count; + esp_zb_zdo_binding_table_req(req, bindingTableCb, req); + } else { + // This is the last chunk, process all records + log_d("Processing final chunk of binding table, total records: %d", all_records.size()); + for (const auto &record : all_records) { + + DeviceIdentifier dev_id; + dev_id.endpoint = record.src_endp; + dev_id.is_ieee = (record.dst_addr_mode == ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT); + + if (dev_id.is_ieee) { + memcpy(dev_id.ieee_addr, record.dst_address.addr_long, sizeof(esp_zb_ieee_addr_t)); + dev_id.short_addr = 0xFFFF; // Invalid short address + } else { + dev_id.short_addr = record.dst_address.addr_short; + memset(dev_id.ieee_addr, 0, sizeof(esp_zb_ieee_addr_t)); + } + + // Track this device as found + found_devices.insert(dev_id); } - // Add to list of bound devices of proper endpoint + // Now process each endpoint and update its bound devices for (std::list::iterator it = Zigbee.ep_objects.begin(); it != Zigbee.ep_objects.end(); ++it) { - if ((*it)->getEndpoint() == record->src_endp) { - (*it)->addBoundDevice(device); - log_d( - "Device bound to EP %d -> device endpoint: %d, short addr: 0x%04x, ieee addr: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", record->src_endp, - device->endpoint, device->short_addr, device->ieee_addr[7], device->ieee_addr[6], device->ieee_addr[5], device->ieee_addr[4], device->ieee_addr[3], - device->ieee_addr[2], device->ieee_addr[1], device->ieee_addr[0] - ); + log_d("Processing endpoint %d", (*it)->getEndpoint()); + std::list bound_devices = (*it)->getBoundDevices(); + std::list devices_to_remove; + + // First, identify devices that need to be removed + for (std::list::iterator dev_it = bound_devices.begin(); dev_it != bound_devices.end(); ++dev_it) { + DeviceIdentifier dev_id; + dev_id.endpoint = (*it)->getEndpoint(); + + // Create both short and IEEE address identifiers for the device + bool found = false; + + // Check if device exists with short address + if ((*dev_it)->short_addr != 0xFFFF) { + dev_id.is_ieee = false; + dev_id.short_addr = (*dev_it)->short_addr; + memset(dev_id.ieee_addr, 0, sizeof(esp_zb_ieee_addr_t)); + if (found_devices.find(dev_id) != found_devices.end()) { + found = true; + } + } + + // Check if device exists with IEEE address + if (!found) { + dev_id.is_ieee = true; + memcpy(dev_id.ieee_addr, (*dev_it)->ieee_addr, sizeof(esp_zb_ieee_addr_t)); + dev_id.short_addr = 0xFFFF; + if (found_devices.find(dev_id) != found_devices.end()) { + found = true; + } + } + + if (!found) { + devices_to_remove.push_back(*dev_it); + } + } + + // Remove devices that are no longer in the binding table + for (std::list::iterator dev_it = devices_to_remove.begin(); dev_it != devices_to_remove.end(); ++dev_it) { + (*it)->removeBoundDevice(*dev_it); + free(*dev_it); + } + + // Now add new devices from the binding table + for (const auto &record : all_records) { + if (record.src_endp == (*it)->getEndpoint()) { + log_d("Processing binding record for EP %d", record.src_endp); + zb_device_params_t *device = (zb_device_params_t *)calloc(1, sizeof(zb_device_params_t)); + if (!device) { + log_e("Failed to allocate memory for device params"); + continue; + } + device->endpoint = record.dst_endp; + + bool is_ieee = (record.dst_addr_mode == ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT); + if (is_ieee) { + memcpy(device->ieee_addr, record.dst_address.addr_long, sizeof(esp_zb_ieee_addr_t)); + device->short_addr = 0xFFFF; + } else { + device->short_addr = record.dst_address.addr_short; + memset(device->ieee_addr, 0, sizeof(esp_zb_ieee_addr_t)); + } + + // Check if device already exists + bool device_exists = false; + for (std::list::iterator dev_it = bound_devices.begin(); dev_it != bound_devices.end(); ++dev_it) { + if (is_ieee) { + if (memcmp((*dev_it)->ieee_addr, device->ieee_addr, sizeof(esp_zb_ieee_addr_t)) == 0) { + device_exists = true; + break; + } + } else { + if ((*dev_it)->short_addr == device->short_addr) { + device_exists = true; + break; + } + } + } + + if (!device_exists) { + (*it)->addBoundDevice(device); + log_d( + "Device bound to EP %d -> device endpoint: %d, %s: %s", record.src_endp, device->endpoint, is_ieee ? "ieee addr" : "short addr", + is_ieee ? formatIEEEAddress(device->ieee_addr) : formatShortAddress(device->short_addr) + ); + } else { + log_d("Device already exists, freeing allocated memory"); + free(device); // Free the device if it already exists + } + } } } - record = record->next; - } - // Continue reading the binding table - if (table_info->index + table_info->count < table_info->total) { - /* There are unreported binding table entries, request for them. */ - req->start_index = table_info->index + table_info->count; - esp_zb_zdo_binding_table_req(req, bindingTableCb, req); - done = false; + // Print bound devices + log_d("Filling bounded devices finished"); + free(req); } - } - - if (done) { - // Print bound devices - log_d("Filling bounded devices finished"); + } else { + log_e("Binding table request failed with status: %d", zdo_status); free(req); } } @@ -483,6 +733,20 @@ void ZigbeeCore::searchBindings() { esp_zb_zdo_binding_table_req(mb_req, bindingTableCb, (void *)mb_req); } +void ZigbeeCore::resetNVRAMChannelMask() { + _primary_channel_mask = ESP_ZB_TRANSCEIVER_ALL_CHANNELS_MASK; + esp_zb_set_channel_mask(_primary_channel_mask); + zb_nvram_write_dataset(ZB_NVRAM_COMMON_DATA); + log_v("Channel mask reset to all channels"); +} + +void ZigbeeCore::setNVRAMChannelMask(uint32_t mask) { + _primary_channel_mask = mask; + esp_zb_set_channel_mask(_primary_channel_mask); + zb_nvram_write_dataset(ZB_NVRAM_COMMON_DATA); + log_v("Channel mask set to 0x%08x", mask); +} + // Function to convert enum value to string const char *ZigbeeCore::getDeviceTypeString(esp_zb_ha_standard_devices_t deviceId) { switch (deviceId) { diff --git a/libraries/Zigbee/src/ZigbeeCore.h b/libraries/Zigbee/src/ZigbeeCore.h index a26e17e58a7..69c91c63ac4 100644 --- a/libraries/Zigbee/src/ZigbeeCore.h +++ b/libraries/Zigbee/src/ZigbeeCore.h @@ -8,6 +8,7 @@ #include "esp_zigbee_core.h" #include "zdo/esp_zigbee_zdo_common.h" +#include "aps/esp_zigbee_aps.h" #include #include #include "ZigbeeEP.h" @@ -28,6 +29,8 @@ typedef enum { #define ZB_SCAN_RUNNING (-1) #define ZB_SCAN_FAILED (-2) +#define ZB_BEGIN_TIMEOUT_DEFAULT 30000 // 30 seconds + #define ZIGBEE_DEFAULT_ED_CONFIG() \ { \ .esp_zb_role = ESP_ZB_DEVICE_TYPE_ED, .install_code_policy = false, \ @@ -85,6 +88,7 @@ class ZigbeeCore { esp_zb_radio_config_t _radio_config; esp_zb_host_config_t _host_config; uint32_t _primary_channel_mask; + uint32_t _begin_timeout; int16_t _scan_status; uint8_t _scan_duration; bool _rx_on_when_idle; @@ -97,12 +101,15 @@ class ZigbeeCore { uint8_t _open_network; zigbee_scan_result_t *_scan_result; SemaphoreHandle_t lock; + bool _debug; bool zigbeeInit(esp_zb_cfg_t *zb_cfg, bool erase_nvs); static void scanCompleteCallback(esp_zb_zdp_status_t zdo_status, uint8_t count, esp_zb_network_descriptor_t *nwk_descriptor); const char *getDeviceTypeString(esp_zb_ha_standard_devices_t deviceId); void searchBindings(); static void bindingTableCb(const esp_zb_zdo_binding_table_info_t *table_info, void *user_ctx); + void resetNVRAMChannelMask(); // Reset to default mask also in NVRAM + void setNVRAMChannelMask(uint32_t mask); // Set channel mask in NVRAM public: ZigbeeCore(); @@ -124,7 +131,7 @@ class ZigbeeCore { return _role; } - void addEndpoint(ZigbeeEP *ep); + bool addEndpoint(ZigbeeEP *ep); //void removeEndpoint(ZigbeeEP *ep); void setRadioConfig(esp_zb_radio_config_t config); @@ -134,7 +141,8 @@ class ZigbeeCore { esp_zb_host_config_t getHostConfig(); void setPrimaryChannelMask(uint32_t mask); // By default all channels are scanned (11-26) -> mask 0x07FFF800 - void setScanDuration(uint8_t duration); // Can be set from 1 - 4. 1 is fastest, 4 is slowest + + void setScanDuration(uint8_t duration); // Can be set from 1 - 4. 1 is fastest, 4 is slowest uint8_t getScanDuration() { return _scan_duration; } @@ -145,9 +153,12 @@ class ZigbeeCore { bool getRxOnWhenIdle() { return _rx_on_when_idle; } - + void setTimeout(uint32_t timeout) { + _begin_timeout = timeout; + } void setRebootOpenNetwork(uint8_t time); void openNetwork(uint8_t time); + void closeNetwork(); //scan_duration Time spent scanning each channel, in units of ((1 << scan_duration) + 1) * a beacon time. (15.36 microseconds) void scanNetworks(uint32_t channel_mask = ESP_ZB_TRANSCEIVER_ALL_CHANNELS_MASK, uint8_t scan_duration = 5); @@ -156,10 +167,31 @@ class ZigbeeCore { zigbee_scan_result_t *getScanResult(); void scanDelete(); - void factoryReset(); + void factoryReset(bool restart = true); + + void setDebugMode(bool debug) { + _debug = debug; + } + bool getDebugMode() { + return _debug; + } // Friend function declaration to allow access to private members friend void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct); + friend bool zb_apsde_data_indication_handler(esp_zb_apsde_data_ind_t ind); + + // Helper functions for formatting addresses + static inline const char *formatIEEEAddress(const esp_zb_ieee_addr_t addr) { + static char buf[24]; + snprintf(buf, sizeof(buf), "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", addr[7], addr[6], addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]); + return buf; + } + + static inline const char *formatShortAddress(uint16_t addr) { + static char buf[7]; + snprintf(buf, sizeof(buf), "0x%04X", addr); + return buf; + } }; extern ZigbeeCore Zigbee; diff --git a/libraries/Zigbee/src/ZigbeeEP.cpp b/libraries/Zigbee/src/ZigbeeEP.cpp index 6774e9111f1..1d3df126ce8 100644 --- a/libraries/Zigbee/src/ZigbeeEP.cpp +++ b/libraries/Zigbee/src/ZigbeeEP.cpp @@ -7,11 +7,6 @@ #include "esp_zigbee_cluster.h" #include "zcl/esp_zigbee_zcl_power_config.h" -bool ZigbeeEP::_is_bound = false; -bool ZigbeeEP::_allow_multiple_binding = false; - -//TODO: is_bound and allow_multiple_binding to make not static - /* Zigbee End Device Class */ ZigbeeEP::ZigbeeEP(uint8_t endpoint) { _endpoint = endpoint; @@ -19,7 +14,12 @@ ZigbeeEP::ZigbeeEP(uint8_t endpoint) { _ep_config.endpoint = 0; _cluster_list = nullptr; _on_identify = nullptr; + _read_model = NULL; + _read_manufacturer = NULL; _time_status = 0; + _is_bound = false; + _use_manual_binding = false; + _allow_multiple_binding = false; if (!lock) { lock = xSemaphoreCreateBinary(); if (lock == NULL) { @@ -32,71 +32,118 @@ void ZigbeeEP::setVersion(uint8_t version) { _ep_config.app_device_version = version; } -void ZigbeeEP::setManufacturerAndModel(const char *name, const char *model) { +bool ZigbeeEP::setManufacturerAndModel(const char *name, const char *model) { + // Allocate a new array of size length + 2 (1 for the length, 1 for null terminator) + char zb_name[ZB_MAX_NAME_LENGTH + 2]; + char zb_model[ZB_MAX_NAME_LENGTH + 2]; + // Convert manufacturer to ZCL string - size_t length = strlen(name); - if (length > 32) { - log_e("Manufacturer name is too long"); - return; + size_t name_length = strlen(name); + size_t model_length = strlen(model); + if (name_length > ZB_MAX_NAME_LENGTH || model_length > ZB_MAX_NAME_LENGTH) { + log_e("Manufacturer or model name is too long"); + return false; + } + // Get and check the basic cluster + esp_zb_attribute_list_t *basic_cluster = esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_BASIC, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + if (basic_cluster == nullptr) { + log_e("Failed to get basic cluster"); + return false; } - // Allocate a new array of size length + 2 (1 for the length, 1 for null terminator) - char *zb_name = new char[length + 2]; // Store the length as the first element - zb_name[0] = static_cast(length); // Cast size_t to char + zb_name[0] = static_cast(name_length); // Cast size_t to char + zb_model[0] = static_cast(model_length); // Use memcpy to copy the characters to the result array - memcpy(zb_name + 1, name, length); + memcpy(zb_name + 1, name, name_length); + memcpy(zb_model + 1, model, model_length); // Null-terminate the array - zb_name[length + 1] = '\0'; - - // Convert model to ZCL string - length = strlen(model); - if (length > 32) { - log_e("Model name is too long"); - delete[] zb_name; - return; + zb_name[name_length + 1] = '\0'; + zb_model[model_length + 1] = '\0'; + // Update the manufacturer and model attributes + esp_err_t ret_name = esp_zb_basic_cluster_add_attr(basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID, (void *)zb_name); + if (ret_name != ESP_OK) { + log_e("Failed to set manufacturer: 0x%x: %s", ret_name, esp_err_to_name(ret_name)); } - char *zb_model = new char[length + 2]; - zb_model[0] = static_cast(length); - memcpy(zb_model + 1, model, length); - zb_model[length + 1] = '\0'; - - // Get the basic cluster and update the manufacturer and model attributes - esp_zb_attribute_list_t *basic_cluster = esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_BASIC, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); - esp_zb_basic_cluster_add_attr(basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID, (void *)zb_name); - esp_zb_basic_cluster_add_attr(basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID, (void *)zb_model); + esp_err_t ret_model = esp_zb_basic_cluster_add_attr(basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID, (void *)zb_model); + if (ret_model != ESP_OK) { + log_e("Failed to set model: 0x%x: %s", ret_model, esp_err_to_name(ret_model)); + } + return ret_name == ESP_OK && ret_model == ESP_OK; } -void ZigbeeEP::setPowerSource(zb_power_source_t power_source, uint8_t battery_percentage) { +bool ZigbeeEP::setPowerSource(zb_power_source_t power_source, uint8_t battery_percentage, uint8_t battery_voltage) { esp_zb_attribute_list_t *basic_cluster = esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_BASIC, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); - esp_zb_cluster_update_attr(basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_POWER_SOURCE_ID, (void *)&power_source); + esp_err_t ret = esp_zb_cluster_update_attr(basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_POWER_SOURCE_ID, (void *)&power_source); + if (ret != ESP_OK) { + log_e("Failed to set power source: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } if (power_source == ZB_POWER_SOURCE_BATTERY) { // Add power config cluster and battery percentage attribute + if (battery_percentage > 100) { + battery_percentage = 100; + } battery_percentage = battery_percentage * 2; esp_zb_attribute_list_t *power_config_cluster = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_POWER_CONFIG); - esp_zb_power_config_cluster_add_attr(power_config_cluster, ESP_ZB_ZCL_ATTR_POWER_CONFIG_BATTERY_PERCENTAGE_REMAINING_ID, (void *)&battery_percentage); - esp_zb_cluster_list_add_power_config_cluster(_cluster_list, power_config_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + ret = esp_zb_power_config_cluster_add_attr(power_config_cluster, ESP_ZB_ZCL_ATTR_POWER_CONFIG_BATTERY_PERCENTAGE_REMAINING_ID, (void *)&battery_percentage); + if (ret != ESP_OK) { + log_e("Failed to add battery percentage attribute: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_power_config_cluster_add_attr(power_config_cluster, ESP_ZB_ZCL_ATTR_POWER_CONFIG_BATTERY_VOLTAGE_ID, (void *)&battery_voltage); + if (ret != ESP_OK) { + log_e("Failed to add battery voltage attribute: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_cluster_list_add_power_config_cluster(_cluster_list, power_config_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + if (ret != ESP_OK) { + log_e("Failed to add power config cluster: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } } _power_source = power_source; + return true; } -void ZigbeeEP::setBatteryPercentage(uint8_t percentage) { +bool ZigbeeEP::setBatteryPercentage(uint8_t percentage) { // 100% = 200 in decimal, 0% = 0 // Convert percentage to 0-200 range + esp_zb_zcl_status_t ret = ESP_ZB_ZCL_STATUS_SUCCESS; if (percentage > 100) { percentage = 100; } percentage = percentage * 2; esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_set_attribute_val( + ret = esp_zb_zcl_set_attribute_val( _endpoint, ESP_ZB_ZCL_CLUSTER_ID_POWER_CONFIG, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_POWER_CONFIG_BATTERY_PERCENTAGE_REMAINING_ID, &percentage, false ); esp_zb_lock_release(); + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set battery percentage: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + return false; + } log_v("Battery percentage updated"); + return true; } -void ZigbeeEP::reportBatteryPercentage() { +bool ZigbeeEP::setBatteryVoltage(uint8_t voltage) { + esp_zb_zcl_status_t ret = ESP_ZB_ZCL_STATUS_SUCCESS; + esp_zb_lock_acquire(portMAX_DELAY); + ret = esp_zb_zcl_set_attribute_val( + _endpoint, ESP_ZB_ZCL_CLUSTER_ID_POWER_CONFIG, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_POWER_CONFIG_BATTERY_VOLTAGE_ID, &voltage, false + ); + esp_zb_lock_release(); + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set battery voltage: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + return false; + } + log_v("Battery voltage updated"); + return true; +} + +bool ZigbeeEP::reportBatteryPercentage() { /* Send report attributes command */ esp_zb_zcl_report_attr_cmd_t report_attr_cmd; report_attr_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; @@ -104,11 +151,17 @@ void ZigbeeEP::reportBatteryPercentage() { report_attr_cmd.direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_CLI; report_attr_cmd.clusterID = ESP_ZB_ZCL_CLUSTER_ID_POWER_CONFIG; report_attr_cmd.zcl_basic_cmd.src_endpoint = _endpoint; + report_attr_cmd.manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC; esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_report_attr_cmd_req(&report_attr_cmd); + esp_err_t ret = esp_zb_zcl_report_attr_cmd_req(&report_attr_cmd); esp_zb_lock_release(); + if (ret != ESP_OK) { + log_e("Failed to report battery percentage: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } log_v("Battery percentage reported"); + return true; } char *ZigbeeEP::readManufacturer(uint8_t endpoint, uint16_t short_addr, esp_zb_ieee_addr_t ieee_addr) { @@ -133,8 +186,10 @@ char *ZigbeeEP::readManufacturer(uint8_t endpoint, uint16_t short_addr, esp_zb_i read_req.attr_number = ZB_ARRAY_LENTH(attributes); read_req.attr_field = attributes; - // clear read manufacturer - _read_manufacturer = nullptr; + if (_read_manufacturer != NULL) { + free(_read_manufacturer); + } + _read_manufacturer = NULL; esp_zb_lock_acquire(portMAX_DELAY); esp_zb_zcl_read_attr_cmd_req(&read_req); @@ -169,8 +224,10 @@ char *ZigbeeEP::readModel(uint8_t endpoint, uint16_t short_addr, esp_zb_ieee_add read_req.attr_number = ZB_ARRAY_LENTH(attributes); read_req.attr_field = attributes; - // clear read model - _read_model = nullptr; + if (_read_model != NULL) { + free(_read_model); + } + _read_model = NULL; esp_zb_lock_acquire(portMAX_DELAY); esp_zb_zcl_read_attr_cmd_req(&read_req); @@ -211,20 +268,28 @@ void ZigbeeEP::zbReadBasicCluster(const esp_zb_zcl_attribute_t *attribute) { /* Basic cluster attributes */ if (attribute->id == ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID && attribute->data.type == ESP_ZB_ZCL_ATTR_TYPE_CHAR_STRING && attribute->data.value) { zbstring_t *zbstr = (zbstring_t *)attribute->data.value; - char *string = (char *)malloc(zbstr->len + 1); - memcpy(string, zbstr->data, zbstr->len); - string[zbstr->len] = '\0'; - log_i("Peer Manufacturer is \"%s\"", string); - _read_manufacturer = string; + _read_manufacturer = (char *)malloc(zbstr->len + 1); + if (_read_manufacturer == NULL) { + log_e("Failed to allocate memory for manufacturer data"); + xSemaphoreGive(lock); + return; + } + memcpy(_read_manufacturer, zbstr->data, zbstr->len); + _read_manufacturer[zbstr->len] = '\0'; + log_i("Peer Manufacturer is \"%s\"", _read_manufacturer); xSemaphoreGive(lock); } if (attribute->id == ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID && attribute->data.type == ESP_ZB_ZCL_ATTR_TYPE_CHAR_STRING && attribute->data.value) { zbstring_t *zbstr = (zbstring_t *)attribute->data.value; - char *string = (char *)malloc(zbstr->len + 1); - memcpy(string, zbstr->data, zbstr->len); - string[zbstr->len] = '\0'; - log_i("Peer Model is \"%s\"", string); - _read_model = string; + _read_model = (char *)malloc(zbstr->len + 1); + if (_read_model == NULL) { + log_e("Failed to allocate memory for model data"); + xSemaphoreGive(lock); + return; + } + memcpy(_read_model, zbstr->data, zbstr->len); + _read_model[zbstr->len] = '\0'; + log_i("Peer Model is \"%s\"", _read_model); xSemaphoreGive(lock); } } @@ -239,7 +304,7 @@ void ZigbeeEP::zbIdentify(const esp_zb_zcl_set_attr_value_message_t *message) { } } -void ZigbeeEP::addTimeCluster(tm time, int32_t gmt_offset) { +bool ZigbeeEP::addTimeCluster(tm time, int32_t gmt_offset) { time_t utc_time = 0; // Check if time is set if (time.tm_year > 0) { @@ -249,28 +314,63 @@ void ZigbeeEP::addTimeCluster(tm time, int32_t gmt_offset) { // Create time cluster server attributes esp_zb_attribute_list_t *time_cluster_server = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_TIME); - esp_zb_time_cluster_add_attr(time_cluster_server, ESP_ZB_ZCL_ATTR_TIME_TIME_ZONE_ID, (void *)&gmt_offset); - esp_zb_time_cluster_add_attr(time_cluster_server, ESP_ZB_ZCL_ATTR_TIME_TIME_ID, (void *)&utc_time); - esp_zb_time_cluster_add_attr(time_cluster_server, ESP_ZB_ZCL_ATTR_TIME_TIME_STATUS_ID, (void *)&_time_status); + esp_err_t ret = esp_zb_time_cluster_add_attr(time_cluster_server, ESP_ZB_ZCL_ATTR_TIME_TIME_ZONE_ID, (void *)&gmt_offset); + if (ret != ESP_OK) { + log_e("Failed to add time zone attribute: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_time_cluster_add_attr(time_cluster_server, ESP_ZB_ZCL_ATTR_TIME_TIME_ID, (void *)&utc_time); + if (ret != ESP_OK) { + log_e("Failed to add time attribute: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_time_cluster_add_attr(time_cluster_server, ESP_ZB_ZCL_ATTR_TIME_TIME_STATUS_ID, (void *)&_time_status); + if (ret != ESP_OK) { + log_e("Failed to add time status attribute: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } // Create time cluster client attributes esp_zb_attribute_list_t *time_cluster_client = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_TIME); // Add time clusters to cluster list - esp_zb_cluster_list_add_time_cluster(_cluster_list, time_cluster_server, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); - esp_zb_cluster_list_add_time_cluster(_cluster_list, time_cluster_client, ESP_ZB_ZCL_CLUSTER_CLIENT_ROLE); + ret = esp_zb_cluster_list_add_time_cluster(_cluster_list, time_cluster_server, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + if (ret != ESP_OK) { + log_e("Failed to add time cluster (server role): 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_cluster_list_add_time_cluster(_cluster_list, time_cluster_client, ESP_ZB_ZCL_CLUSTER_CLIENT_ROLE); + if (ret != ESP_OK) { + log_e("Failed to add time cluster (client role): 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; } -void ZigbeeEP::setTime(tm time) { +bool ZigbeeEP::setTime(tm time) { + esp_zb_zcl_status_t ret = ESP_ZB_ZCL_STATUS_SUCCESS; time_t utc_time = mktime(&time); log_d("Setting time to %lld", utc_time); esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_set_attribute_val(_endpoint, ESP_ZB_ZCL_CLUSTER_ID_TIME, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_TIME_TIME_ID, &utc_time, false); + ret = esp_zb_zcl_set_attribute_val(_endpoint, ESP_ZB_ZCL_CLUSTER_ID_TIME, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_TIME_TIME_ID, &utc_time, false); esp_zb_lock_release(); + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set time: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + return false; + } + return true; } -void ZigbeeEP::setTimezone(int32_t gmt_offset) { +bool ZigbeeEP::setTimezone(int32_t gmt_offset) { + esp_zb_zcl_status_t ret = ESP_ZB_ZCL_STATUS_SUCCESS; + log_d("Setting timezone to %d", gmt_offset); esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_set_attribute_val(_endpoint, ESP_ZB_ZCL_CLUSTER_ID_TIME, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_TIME_TIME_ZONE_ID, &gmt_offset, false); + ret = + esp_zb_zcl_set_attribute_val(_endpoint, ESP_ZB_ZCL_CLUSTER_ID_TIME, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_TIME_TIME_ZONE_ID, &gmt_offset, false); esp_zb_lock_release(); + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set timezone: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + return false; + } + return true; } tm ZigbeeEP::getTime(uint8_t endpoint, int32_t short_addr, esp_zb_ieee_addr_t ieee_addr) { @@ -389,7 +489,7 @@ void ZigbeeEP::zbReadTimeCluster(const esp_zb_zcl_attribute_t *attribute) { // uint8_t max_data_size; /*!< The maximum size of OTA data */ // } esp_zb_zcl_ota_upgrade_client_variable_t; -void ZigbeeEP::addOTAClient( +bool ZigbeeEP::addOTAClient( uint32_t file_version, uint32_t downloaded_file_ver, uint16_t hw_version, uint16_t manufacturer, uint16_t image_type, uint8_t max_data_size ) { @@ -409,11 +509,27 @@ void ZigbeeEP::addOTAClient( uint16_t ota_upgrade_server_addr = 0xffff; uint8_t ota_upgrade_server_ep = 0xff; - ESP_ERROR_CHECK(esp_zb_ota_cluster_add_attr(ota_cluster, ESP_ZB_ZCL_ATTR_OTA_UPGRADE_CLIENT_DATA_ID, (void *)&variable_config)); - ESP_ERROR_CHECK(esp_zb_ota_cluster_add_attr(ota_cluster, ESP_ZB_ZCL_ATTR_OTA_UPGRADE_SERVER_ADDR_ID, (void *)&ota_upgrade_server_addr)); - ESP_ERROR_CHECK(esp_zb_ota_cluster_add_attr(ota_cluster, ESP_ZB_ZCL_ATTR_OTA_UPGRADE_SERVER_ENDPOINT_ID, (void *)&ota_upgrade_server_ep)); - - ESP_ERROR_CHECK(esp_zb_cluster_list_add_ota_cluster(_cluster_list, ota_cluster, ESP_ZB_ZCL_CLUSTER_CLIENT_ROLE)); + esp_err_t ret = esp_zb_ota_cluster_add_attr(ota_cluster, ESP_ZB_ZCL_ATTR_OTA_UPGRADE_CLIENT_DATA_ID, (void *)&variable_config); + if (ret != ESP_OK) { + log_e("Failed to add OTA client data: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_ota_cluster_add_attr(ota_cluster, ESP_ZB_ZCL_ATTR_OTA_UPGRADE_SERVER_ADDR_ID, (void *)&ota_upgrade_server_addr); + if (ret != ESP_OK) { + log_e("Failed to add OTA server address: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_ota_cluster_add_attr(ota_cluster, ESP_ZB_ZCL_ATTR_OTA_UPGRADE_SERVER_ENDPOINT_ID, (void *)&ota_upgrade_server_ep); + if (ret != ESP_OK) { + log_e("Failed to add OTA server endpoint: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_cluster_list_add_ota_cluster(_cluster_list, ota_cluster, ESP_ZB_ZCL_CLUSTER_CLIENT_ROLE); + if (ret != ESP_OK) { + log_e("Failed to add OTA cluster: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; } static void findOTAServer(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx) { @@ -444,4 +560,90 @@ void ZigbeeEP::requestOTAUpdate() { esp_zb_lock_release(); } +void ZigbeeEP::removeBoundDevice(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr) { + log_d( + "Attempting to remove device with endpoint %d and IEEE address %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", endpoint, ieee_addr[7], ieee_addr[6], ieee_addr[5], + ieee_addr[4], ieee_addr[3], ieee_addr[2], ieee_addr[1], ieee_addr[0] + ); + + for (std::list::iterator it = _bound_devices.begin(); it != _bound_devices.end(); ++it) { + if ((*it)->endpoint == endpoint && memcmp((*it)->ieee_addr, ieee_addr, sizeof(esp_zb_ieee_addr_t)) == 0) { + log_d("Found matching device, removing it"); + _bound_devices.erase(it); + if (_bound_devices.empty()) { + _is_bound = false; + } + return; + } + } + log_w("No matching device found for removal"); +} + +void ZigbeeEP::removeBoundDevice(zb_device_params_t *device) { + if (!device) { + log_e("Invalid device parameters provided"); + return; + } + + log_d( + "Attempting to remove device with endpoint %d, short address 0x%04x, IEEE address %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", device->endpoint, + device->short_addr, device->ieee_addr[7], device->ieee_addr[6], device->ieee_addr[5], device->ieee_addr[4], device->ieee_addr[3], device->ieee_addr[2], + device->ieee_addr[1], device->ieee_addr[0] + ); + + for (std::list::iterator it = _bound_devices.begin(); it != _bound_devices.end(); ++it) { + bool endpoint_matches = ((*it)->endpoint == device->endpoint); + bool short_addr_matches = (device->short_addr != 0xFFFF && (*it)->short_addr == device->short_addr); + bool ieee_addr_matches = (memcmp((*it)->ieee_addr, device->ieee_addr, sizeof(esp_zb_ieee_addr_t)) == 0); + + if (endpoint_matches && (short_addr_matches || ieee_addr_matches)) { + log_d("Found matching device by %s, removing it", short_addr_matches ? "short address" : "IEEE address"); + _bound_devices.erase(it); + if (_bound_devices.empty()) { + _is_bound = false; + } + return; + } + } + log_w("No matching device found for removal"); +} + +const char *ZigbeeEP::esp_zb_zcl_status_to_name(esp_zb_zcl_status_t status) { + switch (status) { + case ESP_ZB_ZCL_STATUS_SUCCESS: return "Success"; + case ESP_ZB_ZCL_STATUS_FAIL: return "Fail"; + case ESP_ZB_ZCL_STATUS_NOT_AUTHORIZED: return "Not authorized"; + case ESP_ZB_ZCL_STATUS_MALFORMED_CMD: return "Malformed command"; + case ESP_ZB_ZCL_STATUS_UNSUP_CLUST_CMD: return "Unsupported cluster command"; + case ESP_ZB_ZCL_STATUS_UNSUP_GEN_CMD: return "Unsupported general command"; + case ESP_ZB_ZCL_STATUS_UNSUP_MANUF_CLUST_CMD: return "Unsupported manufacturer cluster command"; + case ESP_ZB_ZCL_STATUS_UNSUP_MANUF_GEN_CMD: return "Unsupported manufacturer general command"; + case ESP_ZB_ZCL_STATUS_INVALID_FIELD: return "Invalid field"; + case ESP_ZB_ZCL_STATUS_UNSUP_ATTRIB: return "Unsupported attribute"; + case ESP_ZB_ZCL_STATUS_INVALID_VALUE: return "Invalid value"; + case ESP_ZB_ZCL_STATUS_READ_ONLY: return "Read only"; + case ESP_ZB_ZCL_STATUS_INSUFF_SPACE: return "Insufficient space"; + case ESP_ZB_ZCL_STATUS_DUPE_EXISTS: return "Duplicate exists"; + case ESP_ZB_ZCL_STATUS_NOT_FOUND: return "Not found"; + case ESP_ZB_ZCL_STATUS_UNREPORTABLE_ATTRIB: return "Unreportable attribute"; + case ESP_ZB_ZCL_STATUS_INVALID_TYPE: return "Invalid type"; + case ESP_ZB_ZCL_STATUS_WRITE_ONLY: return "Write only"; + case ESP_ZB_ZCL_STATUS_INCONSISTENT: return "Inconsistent"; + case ESP_ZB_ZCL_STATUS_ACTION_DENIED: return "Action denied"; + case ESP_ZB_ZCL_STATUS_TIMEOUT: return "Timeout"; + case ESP_ZB_ZCL_STATUS_ABORT: return "Abort"; + case ESP_ZB_ZCL_STATUS_INVALID_IMAGE: return "Invalid OTA upgrade image"; + case ESP_ZB_ZCL_STATUS_WAIT_FOR_DATA: return "Server does not have data block available yet"; + case ESP_ZB_ZCL_STATUS_NO_IMAGE_AVAILABLE: return "No image available"; + case ESP_ZB_ZCL_STATUS_REQUIRE_MORE_IMAGE: return "Require more image"; + case ESP_ZB_ZCL_STATUS_NOTIFICATION_PENDING: return "Notification pending"; + case ESP_ZB_ZCL_STATUS_HW_FAIL: return "Hardware failure"; + case ESP_ZB_ZCL_STATUS_SW_FAIL: return "Software failure"; + case ESP_ZB_ZCL_STATUS_CALIB_ERR: return "Calibration error"; + case ESP_ZB_ZCL_STATUS_UNSUP_CLUST: return "Cluster is not found on the target endpoint"; + case ESP_ZB_ZCL_STATUS_LIMIT_REACHED: return "Limit reached"; + default: return "Unknown status"; + } +} + #endif // CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ZigbeeEP.h b/libraries/Zigbee/src/ZigbeeEP.h index 0a4e3e9d252..fe22f31faaf 100644 --- a/libraries/Zigbee/src/ZigbeeEP.h +++ b/libraries/Zigbee/src/ZigbeeEP.h @@ -41,6 +41,10 @@ typedef enum { /* Zigbee End Device Class */ class ZigbeeEP { public: + // constants and limits + static constexpr size_t ZB_MAX_NAME_LENGTH = 32; + + // constructors and destructor ZigbeeEP(uint8_t endpoint = 10); ~ZigbeeEP() {} @@ -62,29 +66,33 @@ class ZigbeeEP { return _bound_devices; } - static bool bound() { + bool bound() { return _is_bound; } - static void allowMultipleBinding(bool bind) { + void allowMultipleBinding(bool bind) { _allow_multiple_binding = bind; } + void setManualBinding(bool bind) { + _use_manual_binding = bind; + } // Set Manufacturer name and model - void setManufacturerAndModel(const char *name, const char *model); + bool setManufacturerAndModel(const char *name, const char *model); // Methods to read manufacturer and model name from selected endpoint and short address char *readManufacturer(uint8_t endpoint, uint16_t short_addr, esp_zb_ieee_addr_t ieee_addr); char *readModel(uint8_t endpoint, uint16_t short_addr, esp_zb_ieee_addr_t ieee_addr); // Set Power source and battery percentage for battery powered devices - void setPowerSource(zb_power_source_t power_source, uint8_t percentage = 255); - void setBatteryPercentage(uint8_t percentage); - void reportBatteryPercentage(); + bool setPowerSource(zb_power_source_t power_source, uint8_t percentage = 0xff, uint8_t voltage = 0xff); // voltage in 100mV + bool setBatteryPercentage(uint8_t percentage); // 0-100 % + bool setBatteryVoltage(uint8_t voltage); // voltage in 100mV (example value 35 for 3.5V) + bool reportBatteryPercentage(); // battery voltage is not reportable attribute // Set time - void addTimeCluster(tm time = {}, int32_t gmt_offset = 0); // gmt offset in seconds - void setTime(tm time); - void setTimezone(int32_t gmt_offset); + bool addTimeCluster(tm time = {}, int32_t gmt_offset = 0); // gmt offset in seconds + bool setTime(tm time); + bool setTimezone(int32_t gmt_offset); // Get time from Coordinator or specific endpoint (blocking until response) struct tm getTime(uint8_t endpoint = 1, int32_t short_addr = 0x0000, esp_zb_ieee_addr_t ieee_addr = {0}); @@ -93,6 +101,9 @@ class ZigbeeEP { bool epAllowMultipleBinding() { return _allow_multiple_binding; } + bool epUseManualBinding() { + return _use_manual_binding; + } // OTA methods /** @@ -104,8 +115,9 @@ class ZigbeeEP { * @param manufacturer The manufacturer code (default: 0x1001). * @param image_type The image type code (default: 0x1011). * @param max_data_size The maximum data size for OTA transfer (default and recommended: 223). + * @return true if the OTA client was added successfully, false otherwise. */ - void addOTAClient( + bool addOTAClient( uint32_t file_version, uint32_t downloaded_file_ver, uint16_t hw_version, uint16_t manufacturer = 0x1001, uint16_t image_type = 0x1011, uint8_t max_data_size = 223 ); @@ -114,10 +126,10 @@ class ZigbeeEP { */ void requestOTAUpdate(); - // findEndpoind may be implemented by EPs to find and bind devices + // findEndpoint may be implemented by EPs to find and bind devices virtual void findEndpoint(esp_zb_zdo_match_desc_req_param_t *cmd_req) {}; - //list of all handlers function calls, to be override by EPs implementation + // list of all handlers function calls, to be override by EPs implementation virtual void zbAttributeSet(const esp_zb_zcl_set_attr_value_message_t *message) {}; virtual void zbAttributeRead(uint16_t cluster_id, const esp_zb_zcl_attribute_t *attribute) {}; virtual void zbReadBasicCluster(const esp_zb_zcl_attribute_t *attribute); //already implemented @@ -132,6 +144,14 @@ class ZigbeeEP { _is_bound = true; } + virtual void removeBoundDevice(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr); + virtual void removeBoundDevice(zb_device_params_t *device); + + virtual void clearBoundDevices() { + _bound_devices.clear(); + _is_bound = false; + } + void onIdentify(void (*callback)(uint16_t)) { _on_identify = callback; } @@ -144,12 +164,16 @@ class ZigbeeEP { int32_t _read_timezone; protected: + // Convert ZCL status to name + const char *esp_zb_zcl_status_to_name(esp_zb_zcl_status_t status); + uint8_t _endpoint; esp_zb_ha_standard_devices_t _device_id; esp_zb_endpoint_config_t _ep_config; esp_zb_cluster_list_t *_cluster_list; - static bool _is_bound; - static bool _allow_multiple_binding; + bool _is_bound; + bool _allow_multiple_binding; + bool _use_manual_binding; std::list _bound_devices; SemaphoreHandle_t lock; zb_power_source_t _power_source; diff --git a/libraries/Zigbee/src/ep/ZigbeeAnalog.cpp b/libraries/Zigbee/src/ep/ZigbeeAnalog.cpp index 417eeb6d98c..6e073c345bc 100644 --- a/libraries/Zigbee/src/ep/ZigbeeAnalog.cpp +++ b/libraries/Zigbee/src/ep/ZigbeeAnalog.cpp @@ -1,38 +1,128 @@ #include "ZigbeeAnalog.h" #if CONFIG_ZB_ENABLED -esp_zb_cluster_list_t *zigbee_analog_clusters_create(zigbee_analog_cfg_t *analog_sensor) { - esp_zb_basic_cluster_cfg_t *basic_cfg = analog_sensor ? &(analog_sensor->basic_cfg) : NULL; - esp_zb_identify_cluster_cfg_t *identify_cfg = analog_sensor ? &(analog_sensor->identify_cfg) : NULL; - esp_zb_cluster_list_t *cluster_list = esp_zb_zcl_cluster_list_create(); - esp_zb_cluster_list_add_basic_cluster(cluster_list, esp_zb_basic_cluster_create(basic_cfg), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); - esp_zb_cluster_list_add_identify_cluster(cluster_list, esp_zb_identify_cluster_create(identify_cfg), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); - return cluster_list; -} - ZigbeeAnalog::ZigbeeAnalog(uint8_t endpoint) : ZigbeeEP(endpoint) { _device_id = ESP_ZB_HA_SIMPLE_SENSOR_DEVICE_ID; - //Create custom analog sensor configuration - zigbee_analog_cfg_t analog_cfg = ZIGBEE_DEFAULT_ANALOG_CONFIG(); - _cluster_list = zigbee_analog_clusters_create(&analog_cfg); + //Create basic analog sensor clusters without configuration + _cluster_list = esp_zb_zcl_cluster_list_create(); + esp_zb_cluster_list_add_basic_cluster(_cluster_list, esp_zb_basic_cluster_create(NULL), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_zb_cluster_list_add_identify_cluster(_cluster_list, esp_zb_identify_cluster_create(NULL), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); _ep_config = {.endpoint = _endpoint, .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, .app_device_id = ESP_ZB_HA_SIMPLE_SENSOR_DEVICE_ID, .app_device_version = 0}; } -void ZigbeeAnalog::addAnalogValue() { - esp_zb_cluster_list_add_analog_value_cluster(_cluster_list, esp_zb_analog_value_cluster_create(NULL), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); - _analog_clusters |= ANALOG_VALUE; -} +bool ZigbeeAnalog::addAnalogInput() { + esp_zb_attribute_list_t *esp_zb_analog_input_cluster = esp_zb_analog_input_cluster_create(NULL); + + // Create default description for Analog Input + char default_description[] = "\x0C" + "Analog Input"; + uint32_t application_type = 0x00000000 | (ESP_ZB_ZCL_AI_GROUP_ID << 24); + float resolution = 0.1; // Default resolution of 0.1 + + esp_err_t ret = esp_zb_analog_input_cluster_add_attr(esp_zb_analog_input_cluster, ESP_ZB_ZCL_ATTR_ANALOG_INPUT_DESCRIPTION_ID, (void *)default_description); + if (ret != ESP_OK) { + log_e("Failed to add description attribute: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } -void ZigbeeAnalog::addAnalogInput() { - esp_zb_cluster_list_add_analog_input_cluster(_cluster_list, esp_zb_analog_input_cluster_create(NULL), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + ret = esp_zb_analog_input_cluster_add_attr(esp_zb_analog_input_cluster, ESP_ZB_ZCL_ATTR_ANALOG_INPUT_APPLICATION_TYPE_ID, (void *)&application_type); + if (ret != ESP_OK) { + log_e("Failed to add application type attribute: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + + ret = esp_zb_analog_input_cluster_add_attr(esp_zb_analog_input_cluster, ESP_ZB_ZCL_ATTR_ANALOG_INPUT_RESOLUTION_ID, (void *)&resolution); + if (ret != ESP_OK) { + log_e("Failed to add resolution attribute: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + + ret = esp_zb_cluster_list_add_analog_input_cluster(_cluster_list, esp_zb_analog_input_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + if (ret != ESP_OK) { + log_e("Failed to add Analog Input cluster: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } _analog_clusters |= ANALOG_INPUT; + return true; } -void ZigbeeAnalog::addAnalogOutput() { - esp_zb_cluster_list_add_analog_output_cluster(_cluster_list, esp_zb_analog_output_cluster_create(NULL), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); +// Check esp_zigbee_zcl_analog_input.h for application type values +bool ZigbeeAnalog::setAnalogInputApplication(uint32_t application_type) { + if (!(_analog_clusters & ANALOG_INPUT)) { + log_e("Analog Input cluster not added"); + return false; + } + + // Add the Analog Input group ID (0x00) to the application type + uint32_t application_type_value = (ESP_ZB_ZCL_AI_GROUP_ID << 24) | application_type; + + esp_zb_attribute_list_t *analog_input_cluster = + esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_ANALOG_INPUT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_err_t ret = esp_zb_cluster_update_attr(analog_input_cluster, ESP_ZB_ZCL_ATTR_ANALOG_INPUT_APPLICATION_TYPE_ID, (void *)&application_type_value); + if (ret != ESP_OK) { + log_e("Failed to set AI application type: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; +} + +bool ZigbeeAnalog::addAnalogOutput() { + esp_zb_attribute_list_t *esp_zb_analog_output_cluster = esp_zb_analog_output_cluster_create(NULL); + + // Create default description for Analog Output + char default_description[] = "\x0D" + "Analog Output"; + uint32_t application_type = 0x00000000 | (ESP_ZB_ZCL_AO_GROUP_ID << 24); + float resolution = 1; // Default resolution of 1 + + esp_err_t ret = + esp_zb_analog_output_cluster_add_attr(esp_zb_analog_output_cluster, ESP_ZB_ZCL_ATTR_ANALOG_OUTPUT_DESCRIPTION_ID, (void *)default_description); + if (ret != ESP_OK) { + log_e("Failed to add description attribute: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + + ret = esp_zb_analog_output_cluster_add_attr(esp_zb_analog_output_cluster, ESP_ZB_ZCL_ATTR_ANALOG_OUTPUT_APPLICATION_TYPE_ID, (void *)&application_type); + if (ret != ESP_OK) { + log_e("Failed to add application type attribute: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + + ret = esp_zb_analog_output_cluster_add_attr(esp_zb_analog_output_cluster, ESP_ZB_ZCL_ATTR_ANALOG_OUTPUT_RESOLUTION_ID, (void *)&resolution); + if (ret != ESP_OK) { + log_e("Failed to add resolution attribute: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + + ret = esp_zb_cluster_list_add_analog_output_cluster(_cluster_list, esp_zb_analog_output_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + if (ret != ESP_OK) { + log_e("Failed to add Analog Output cluster: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } _analog_clusters |= ANALOG_OUTPUT; + return true; +} + +// Check esp_zigbee_zcl_analog_output.h for application type values +bool ZigbeeAnalog::setAnalogOutputApplication(uint32_t application_type) { + if (!(_analog_clusters & ANALOG_OUTPUT)) { + log_e("Analog Output cluster not added"); + return false; + } + + // Add the Analog Output group ID (0x00) to the application type + uint32_t application_type_value = (ESP_ZB_ZCL_AO_GROUP_ID << 24) | application_type; + + esp_zb_attribute_list_t *analog_output_cluster = + esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_ANALOG_OUTPUT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_err_t ret = esp_zb_cluster_update_attr(analog_output_cluster, ESP_ZB_ZCL_ATTR_ANALOG_OUTPUT_APPLICATION_TYPE_ID, (void *)&application_type_value); + if (ret != ESP_OK) { + log_e("Failed to set AO application type: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; } //set attribute method -> method overridden in child class @@ -57,35 +147,26 @@ void ZigbeeAnalog::analogOutputChanged(float analog_output) { } } -void ZigbeeAnalog::setAnalogValue(float analog) { - if (!(_analog_clusters & ANALOG_VALUE)) { - log_e("Analog Value cluster not added"); - return; - } - // float zb_analog = analog; - log_d("Setting analog value to %.1f", analog); - esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_set_attribute_val( - _endpoint, ESP_ZB_ZCL_CLUSTER_ID_ANALOG_VALUE, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_ANALOG_VALUE_PRESENT_VALUE_ID, &analog, false - ); - esp_zb_lock_release(); -} - -void ZigbeeAnalog::setAnalogInput(float analog) { +bool ZigbeeAnalog::setAnalogInput(float analog) { + esp_zb_zcl_status_t ret = ESP_ZB_ZCL_STATUS_SUCCESS; if (!(_analog_clusters & ANALOG_INPUT)) { log_e("Analog Input cluster not added"); - return; + return false; } - // float zb_analog = analog; log_d("Setting analog input to %.1f", analog); esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_set_attribute_val( + ret = esp_zb_zcl_set_attribute_val( _endpoint, ESP_ZB_ZCL_CLUSTER_ID_ANALOG_INPUT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_ANALOG_INPUT_PRESENT_VALUE_ID, &analog, false ); esp_zb_lock_release(); + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set analog input: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + return false; + } + return true; } -void ZigbeeAnalog::reportAnalogInput() { +bool ZigbeeAnalog::reportAnalogInput() { /* Send report attributes command */ esp_zb_zcl_report_attr_cmd_t report_attr_cmd; report_attr_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; @@ -96,12 +177,17 @@ void ZigbeeAnalog::reportAnalogInput() { report_attr_cmd.manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC; esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_report_attr_cmd_req(&report_attr_cmd); + esp_err_t ret = esp_zb_zcl_report_attr_cmd_req(&report_attr_cmd); esp_zb_lock_release(); + if (ret != ESP_OK) { + log_e("Failed to send Analog Input report: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } log_v("Analog Input report sent"); + return true; } -void ZigbeeAnalog::setAnalogInputReporting(uint16_t min_interval, uint16_t max_interval, float delta) { +bool ZigbeeAnalog::setAnalogInputReporting(uint16_t min_interval, uint16_t max_interval, float delta) { esp_zb_zcl_reporting_info_t reporting_info; memset(&reporting_info, 0, sizeof(esp_zb_zcl_reporting_info_t)); reporting_info.direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_SRV; @@ -118,8 +204,135 @@ void ZigbeeAnalog::setAnalogInputReporting(uint16_t min_interval, uint16_t max_i reporting_info.manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC; esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_update_reporting_info(&reporting_info); + esp_err_t ret = esp_zb_zcl_update_reporting_info(&reporting_info); esp_zb_lock_release(); + if (ret != ESP_OK) { + log_e("Failed to set Analog Input reporting: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; +} + +bool ZigbeeAnalog::setAnalogInputDescription(const char *description) { + if (!(_analog_clusters & ANALOG_INPUT)) { + log_e("Analog Input cluster not added"); + return false; + } + + // Allocate a new array of size length + 2 (1 for the length, 1 for null terminator) + char zb_description[ZB_MAX_NAME_LENGTH + 2]; + + // Convert description to ZCL string + size_t description_length = strlen(description); + if (description_length > ZB_MAX_NAME_LENGTH) { + log_e("Description is too long"); + return false; + } + + // Get and check the analog input cluster + esp_zb_attribute_list_t *analog_input_cluster = + esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_ANALOG_INPUT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + if (analog_input_cluster == nullptr) { + log_e("Failed to get analog input cluster"); + return false; + } + + // Store the length as the first element + zb_description[0] = static_cast(description_length); // Cast size_t to char + // Use memcpy to copy the characters to the result array + memcpy(zb_description + 1, description, description_length); + // Null-terminate the array + zb_description[description_length + 1] = '\0'; + + // Update the description attribute + esp_err_t ret = esp_zb_cluster_update_attr(analog_input_cluster, ESP_ZB_ZCL_ATTR_ANALOG_INPUT_DESCRIPTION_ID, (void *)zb_description); + if (ret != ESP_OK) { + log_e("Failed to set description: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; +} + +bool ZigbeeAnalog::setAnalogOutputDescription(const char *description) { + if (!(_analog_clusters & ANALOG_OUTPUT)) { + log_e("Analog Output cluster not added"); + return false; + } + + // Allocate a new array of size length + 2 (1 for the length, 1 for null terminator) + char zb_description[ZB_MAX_NAME_LENGTH + 2]; + + // Convert description to ZCL string + size_t description_length = strlen(description); + if (description_length > ZB_MAX_NAME_LENGTH) { + log_e("Description is too long"); + return false; + } + + // Get and check the analog output cluster + esp_zb_attribute_list_t *analog_output_cluster = + esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_ANALOG_OUTPUT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + if (analog_output_cluster == nullptr) { + log_e("Failed to get analog output cluster"); + return false; + } + + // Store the length as the first element + zb_description[0] = static_cast(description_length); // Cast size_t to char + // Use memcpy to copy the characters to the result array + memcpy(zb_description + 1, description, description_length); + // Null-terminate the array + zb_description[description_length + 1] = '\0'; + + // Update the description attribute + esp_err_t ret = esp_zb_cluster_update_attr(analog_output_cluster, ESP_ZB_ZCL_ATTR_ANALOG_OUTPUT_DESCRIPTION_ID, (void *)zb_description); + if (ret != ESP_OK) { + log_e("Failed to set description: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; +} + +bool ZigbeeAnalog::setAnalogInputResolution(float resolution) { + if (!(_analog_clusters & ANALOG_INPUT)) { + log_e("Analog Input cluster not added"); + return false; + } + + esp_zb_attribute_list_t *analog_input_cluster = + esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_ANALOG_INPUT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + if (analog_input_cluster == nullptr) { + log_e("Failed to get analog input cluster"); + return false; + } + + esp_err_t ret = esp_zb_cluster_update_attr(analog_input_cluster, ESP_ZB_ZCL_ATTR_ANALOG_INPUT_RESOLUTION_ID, (void *)&resolution); + if (ret != ESP_OK) { + log_e("Failed to set resolution: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; +} + +bool ZigbeeAnalog::setAnalogOutputResolution(float resolution) { + if (!(_analog_clusters & ANALOG_OUTPUT)) { + log_e("Analog Output cluster not added"); + return false; + } + + esp_zb_attribute_list_t *analog_output_cluster = + esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_ANALOG_OUTPUT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + if (analog_output_cluster == nullptr) { + log_e("Failed to get analog output cluster"); + return false; + } + + esp_err_t ret = esp_zb_cluster_update_attr(analog_output_cluster, ESP_ZB_ZCL_ATTR_ANALOG_OUTPUT_RESOLUTION_ID, (void *)&resolution); + if (ret != ESP_OK) { + log_e("Failed to set resolution: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; } #endif // CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeAnalog.h b/libraries/Zigbee/src/ep/ZigbeeAnalog.h index 8993c6ea1a4..e0c3fc11c5a 100644 --- a/libraries/Zigbee/src/ep/ZigbeeAnalog.h +++ b/libraries/Zigbee/src/ep/ZigbeeAnalog.h @@ -9,32 +9,15 @@ #include "ZigbeeEP.h" #include "ha/esp_zigbee_ha_standard.h" -// clang-format off -#define ZIGBEE_DEFAULT_ANALOG_CONFIG() \ - { \ - .basic_cfg = \ - { \ - .zcl_version = ESP_ZB_ZCL_BASIC_ZCL_VERSION_DEFAULT_VALUE, \ - .power_source = ESP_ZB_ZCL_BASIC_POWER_SOURCE_DEFAULT_VALUE, \ - }, \ - .identify_cfg = \ - { \ - .identify_time = ESP_ZB_ZCL_IDENTIFY_IDENTIFY_TIME_DEFAULT_VALUE, \ - }, \ - } -// clang-format on - //enum for bits set to check what analog cluster were added enum zigbee_analog_clusters { - ANALOG_VALUE = 1, - ANALOG_INPUT = 2, - ANALOG_OUTPUT = 4 + ANALOG_INPUT = 1, + ANALOG_OUTPUT = 2 }; typedef struct zigbee_analog_cfg_s { esp_zb_basic_cluster_cfg_t basic_cfg; esp_zb_identify_cluster_cfg_t identify_cfg; - esp_zb_analog_value_cluster_cfg_t analog_value_cfg; esp_zb_analog_output_cluster_cfg_t analog_output_cfg; esp_zb_analog_input_cluster_cfg_t analog_input_cfg; } zigbee_analog_cfg_t; @@ -45,24 +28,32 @@ class ZigbeeAnalog : public ZigbeeEP { ~ZigbeeAnalog() {} // Add analog clusters - void addAnalogValue(); - void addAnalogInput(); - void addAnalogOutput(); + bool addAnalogInput(); + bool addAnalogOutput(); + + // Set the application type and description for the analog input + bool setAnalogInputApplication(uint32_t application_type); // Check esp_zigbee_zcl_analog_input.h for application type values + bool setAnalogInputDescription(const char *description); + bool setAnalogInputResolution(float resolution); + + // Set the application type and description for the analog output + bool setAnalogOutputApplication(uint32_t application_type); // Check esp_zigbee_zcl_analog_output.h for application type values + bool setAnalogOutputDescription(const char *description); + bool setAnalogOutputResolution(float resolution); // Use to set a cb function to be called on analog output change void onAnalogOutputChange(void (*callback)(float analog)) { _on_analog_output_change = callback; } - // Set the analog value / input - void setAnalogValue(float analog); - void setAnalogInput(float analog); + // Set the analog input value + bool setAnalogInput(float analog); - // Report Analog Input - void reportAnalogInput(); + // Report Analog Input value + bool reportAnalogInput(); // Set reporting for Analog Input - void setAnalogInputReporting(uint16_t min_interval, uint16_t max_interval, float delta); + bool setAnalogInputReporting(uint16_t min_interval, uint16_t max_interval, float delta); private: void zbAttributeSet(const esp_zb_zcl_set_attr_value_message_t *message) override; diff --git a/libraries/Zigbee/src/ep/ZigbeeBinary.cpp b/libraries/Zigbee/src/ep/ZigbeeBinary.cpp new file mode 100644 index 00000000000..aa37ceb3020 --- /dev/null +++ b/libraries/Zigbee/src/ep/ZigbeeBinary.cpp @@ -0,0 +1,144 @@ +#include "ZigbeeBinary.h" +#if CONFIG_ZB_ENABLED + +ZigbeeBinary::ZigbeeBinary(uint8_t endpoint) : ZigbeeEP(endpoint) { + _device_id = ESP_ZB_HA_SIMPLE_SENSOR_DEVICE_ID; + + //Create basic binary sensor clusters without configuration + _cluster_list = esp_zb_zcl_cluster_list_create(); + esp_zb_cluster_list_add_basic_cluster(_cluster_list, esp_zb_basic_cluster_create(NULL), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_zb_cluster_list_add_identify_cluster(_cluster_list, esp_zb_identify_cluster_create(NULL), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + + _ep_config = {.endpoint = _endpoint, .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, .app_device_id = ESP_ZB_HA_SIMPLE_SENSOR_DEVICE_ID, .app_device_version = 0}; +} + +bool ZigbeeBinary::addBinaryInput() { + esp_zb_attribute_list_t *esp_zb_binary_input_cluster = esp_zb_binary_input_cluster_create(NULL); + + // Create default description for Binary Input + char default_description[] = "\x0C" + "Binary Input"; + uint32_t application_type = 0x00000000 | (0x03 << 24); // Group ID 0x03 + + esp_err_t ret = esp_zb_binary_input_cluster_add_attr(esp_zb_binary_input_cluster, ESP_ZB_ZCL_ATTR_BINARY_INPUT_DESCRIPTION_ID, (void *)default_description); + if (ret != ESP_OK) { + log_e("Failed to add description attribute: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + + ret = esp_zb_binary_input_cluster_add_attr(esp_zb_binary_input_cluster, ESP_ZB_ZCL_ATTR_BINARY_INPUT_APPLICATION_TYPE_ID, (void *)&application_type); + if (ret != ESP_OK) { + log_e("Failed to add application type attribute: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + + ret = esp_zb_cluster_list_add_binary_input_cluster(_cluster_list, esp_zb_binary_input_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + if (ret != ESP_OK) { + log_e("Failed to add Binary Input cluster: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + _binary_clusters |= BINARY_INPUT; + return true; +} + +// Check Zigbee Cluster Specification 3.14.11.19.4 Binary Inputs (BI) Types for application type values +bool ZigbeeBinary::setBinaryInputApplication(uint32_t application_type) { + if (!(_binary_clusters & BINARY_INPUT)) { + log_e("Binary Input cluster not added"); + return false; + } + + // Add the Binary Input group ID (0x03) to the application type + uint32_t application_type_value = (0x03 << 24) | application_type; + + esp_zb_attribute_list_t *binary_input_cluster = + esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_BINARY_INPUT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_err_t ret = esp_zb_cluster_update_attr(binary_input_cluster, ESP_ZB_ZCL_ATTR_BINARY_INPUT_APPLICATION_TYPE_ID, (void *)&application_type_value); + if (ret != ESP_OK) { + log_e("Failed to set Binary Input application type: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; +} + +bool ZigbeeBinary::setBinaryInput(bool input) { + esp_zb_zcl_status_t ret = ESP_ZB_ZCL_STATUS_SUCCESS; + if (!(_binary_clusters & BINARY_INPUT)) { + log_e("Binary Input cluster not added"); + return false; + } + log_d("Setting binary input to %d", input); + esp_zb_lock_acquire(portMAX_DELAY); + ret = esp_zb_zcl_set_attribute_val( + _endpoint, ESP_ZB_ZCL_CLUSTER_ID_BINARY_INPUT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_BINARY_INPUT_PRESENT_VALUE_ID, &input, false + ); + esp_zb_lock_release(); + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set binary input: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + return false; + } + return true; +} + +bool ZigbeeBinary::reportBinaryInput() { + /* Send report attributes command */ + esp_zb_zcl_report_attr_cmd_t report_attr_cmd; + report_attr_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; + report_attr_cmd.attributeID = ESP_ZB_ZCL_ATTR_BINARY_INPUT_PRESENT_VALUE_ID; + report_attr_cmd.direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_CLI; + report_attr_cmd.clusterID = ESP_ZB_ZCL_CLUSTER_ID_BINARY_INPUT; + report_attr_cmd.zcl_basic_cmd.src_endpoint = _endpoint; + report_attr_cmd.manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC; + + esp_zb_lock_acquire(portMAX_DELAY); + esp_err_t ret = esp_zb_zcl_report_attr_cmd_req(&report_attr_cmd); + esp_zb_lock_release(); + if (ret != ESP_OK) { + log_e("Failed to send Binary Input report: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + log_v("Binary Input report sent"); + return true; +} + +bool ZigbeeBinary::setBinaryInputDescription(const char *description) { + if (!(_binary_clusters & BINARY_INPUT)) { + log_e("Binary Input cluster not added"); + return false; + } + + // Allocate a new array of size length + 2 (1 for the length, 1 for null terminator) + char zb_description[ZB_MAX_NAME_LENGTH + 2]; + + // Convert description to ZCL string + size_t description_length = strlen(description); + if (description_length > ZB_MAX_NAME_LENGTH) { + log_e("Description is too long"); + return false; + } + + // Get and check the binary input cluster + esp_zb_attribute_list_t *binary_input_cluster = + esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_BINARY_INPUT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + if (binary_input_cluster == nullptr) { + log_e("Failed to get binary input cluster"); + return false; + } + + // Store the length as the first element + zb_description[0] = static_cast(description_length); // Cast size_t to char + // Use memcpy to copy the characters to the result array + memcpy(zb_description + 1, description, description_length); + // Null-terminate the array + zb_description[description_length + 1] = '\0'; + + // Update the description attribute + esp_err_t ret = esp_zb_cluster_update_attr(binary_input_cluster, ESP_ZB_ZCL_ATTR_BINARY_INPUT_DESCRIPTION_ID, (void *)zb_description); + if (ret != ESP_OK) { + log_e("Failed to set description: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; +} + +#endif // CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeBinary.h b/libraries/Zigbee/src/ep/ZigbeeBinary.h new file mode 100644 index 00000000000..5a543604970 --- /dev/null +++ b/libraries/Zigbee/src/ep/ZigbeeBinary.h @@ -0,0 +1,85 @@ +/* Class of Zigbee Binary sensor endpoint inherited from common EP class */ + +#pragma once + +#include "soc/soc_caps.h" +#include "sdkconfig.h" +#if CONFIG_ZB_ENABLED + +#include "ZigbeeEP.h" +#include "ha/esp_zigbee_ha_standard.h" + +//enum for bits set to check what analog cluster were added +enum zigbee_binary_clusters { + BINARY_INPUT = 1, + BINARY_OUTPUT = 2 +}; + +// HVAC application types for Binary Input (more can be found in Zigbee Cluster Specification 3.14.11.19.4 Binary Inputs (BI) Types) +#define BINARY_INPUT_APPLICATION_TYPE_HVAC_BOILER_STATUS 0x00000003 // Type 0x00, Index 0x0003 +#define BINARY_INPUT_APPLICATION_TYPE_HVAC_CHILLER_STATUS 0x00000013 // Type 0x00, Index 0x0013 +#define BINARY_INPUT_APPLICATION_TYPE_HVAC_OCCUPANCY 0x00000031 // Type 0x00, Index 0x0031 +#define BINARY_INPUT_APPLICATION_TYPE_HVAC_FAN_STATUS 0x00000035 // Type 0x00, Index 0x0035 +#define BINARY_INPUT_APPLICATION_TYPE_HVAC_FILTER_STATUS 0x00000036 // Type 0x00, Index 0x0036 +#define BINARY_INPUT_APPLICATION_TYPE_HVAC_HEATING_ALARM 0x0000003E // Type 0x00, Index 0x003E +#define BINARY_INPUT_APPLICATION_TYPE_HVAC_COOLING_ALARM 0x0000001D // Type 0x00, Index 0x001D +#define BINARY_INPUT_APPLICATION_TYPE_HVAC_UNIT_ENABLE 0x00000090 // Type 0x00, Index 0x0090 +#define BINARY_INPUT_APPLICATION_TYPE_HVAC_OTHER 0x0000FFFF // Type 0x00, Index 0xFFFF + +// Security application types for Binary Input +#define BINARY_INPUT_APPLICATION_TYPE_SECURITY_GLASS_BREAKAGE_DETECTION_0 0x01000000 // Type 0x01, Index 0x0000 +#define BINARY_INPUT_APPLICATION_TYPE_SECURITY_INTRUSION_DETECTION 0x01000001 // Type 0x01, Index 0x0001 +#define BINARY_INPUT_APPLICATION_TYPE_SECURITY_MOTION_DETECTION 0x01000002 // Type 0x01, Index 0x0002 +#define BINARY_INPUT_APPLICATION_TYPE_SECURITY_GLASS_BREAKAGE_DETECTION_1 0x01000003 // Type 0x01, Index 0x0003 +#define BINARY_INPUT_APPLICATION_TYPE_SECURITY_ZONE_ARMED 0x01000004 // Type 0x01, Index 0x0004 +#define BINARY_INPUT_APPLICATION_TYPE_SECURITY_GLASS_BREAKAGE_DETECTION_2 0x01000005 // Type 0x01, Index 0x0005 +#define BINARY_INPUT_APPLICATION_TYPE_SECURITY_SMOKE_DETECTION 0x01000006 // Type 0x01, Index 0x0006 +#define BINARY_INPUT_APPLICATION_TYPE_SECURITY_CARBON_DIOXIDE_DETECTION 0x01000007 // Type 0x01, Index 0x0007 +#define BINARY_INPUT_APPLICATION_TYPE_SECURITY_HEAT_DETECTION 0x01000008 // Type 0x01, Index 0x0008 +#define BINARY_INPUT_APPLICATION_TYPE_SECURITY_OTHER 0x0100FFFF // Type 0x01, Index 0xFFFF + +typedef struct zigbee_binary_cfg_s { + esp_zb_basic_cluster_cfg_t basic_cfg; + esp_zb_identify_cluster_cfg_t identify_cfg; + // esp_zb_binary_output_cluster_cfg_t binary_output_cfg; + esp_zb_binary_input_cluster_cfg_t binary_input_cfg; +} zigbee_binary_cfg_t; + +class ZigbeeBinary : public ZigbeeEP { +public: + ZigbeeBinary(uint8_t endpoint); + ~ZigbeeBinary() {} + + // Add binary cluster + bool addBinaryInput(); + // bool addBinaryOutput(); + + // Set the application type and description for the binary input + bool setBinaryInputApplication(uint32_t application_type); // Check esp_zigbee_zcl_binary_input.h for application type values + bool setBinaryInputDescription(const char *description); + + // Set the application type and description for the binary output + // bool setBinaryOutputApplication(uint32_t application_type); // Check esp_zigbee_zcl_binary_output.h for application type values + // bool setBinaryOutputDescription(const char *description); + + // Use to set a cb function to be called on binary output change + // void onBinaryOutputChange(void (*callback)(bool binary_output)) { + // _on_binary_output_change = callback; + // } + + // Set the binary input value + bool setBinaryInput(bool input); + + // Report Binary Input value + bool reportBinaryInput(); + +private: + // void zbAttributeSet(const esp_zb_zcl_set_attr_value_message_t *message) override; + + // void (*_on_binary_output_change)(bool); + // void binaryOutputChanged(bool binary_output); + + uint8_t _binary_clusters; +}; + +#endif // CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeCarbonDioxideSensor.cpp b/libraries/Zigbee/src/ep/ZigbeeCarbonDioxideSensor.cpp index 2718d9275c2..2b8271f09a9 100644 --- a/libraries/Zigbee/src/ep/ZigbeeCarbonDioxideSensor.cpp +++ b/libraries/Zigbee/src/ep/ZigbeeCarbonDioxideSensor.cpp @@ -24,25 +24,39 @@ ZigbeeCarbonDioxideSensor::ZigbeeCarbonDioxideSensor(uint8_t endpoint) : ZigbeeE _ep_config = {.endpoint = _endpoint, .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, .app_device_id = ESP_ZB_HA_SIMPLE_SENSOR_DEVICE_ID, .app_device_version = 0}; } -void ZigbeeCarbonDioxideSensor::setMinMaxValue(float min, float max) { +bool ZigbeeCarbonDioxideSensor::setMinMaxValue(float min, float max) { float zb_min = min / 1000000.0f; float zb_max = max / 1000000.0f; esp_zb_attribute_list_t *carbon_dioxide_measure_cluster = esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_CARBON_DIOXIDE_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); - esp_zb_cluster_update_attr(carbon_dioxide_measure_cluster, ESP_ZB_ZCL_ATTR_CARBON_DIOXIDE_MEASUREMENT_MIN_MEASURED_VALUE_ID, (void *)&zb_min); - esp_zb_cluster_update_attr(carbon_dioxide_measure_cluster, ESP_ZB_ZCL_ATTR_CARBON_DIOXIDE_MEASUREMENT_MAX_MEASURED_VALUE_ID, (void *)&zb_max); + esp_err_t ret = esp_zb_cluster_update_attr(carbon_dioxide_measure_cluster, ESP_ZB_ZCL_ATTR_CARBON_DIOXIDE_MEASUREMENT_MIN_MEASURED_VALUE_ID, (void *)&zb_min); + if (ret != ESP_OK) { + log_e("Failed to set min value: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_cluster_update_attr(carbon_dioxide_measure_cluster, ESP_ZB_ZCL_ATTR_CARBON_DIOXIDE_MEASUREMENT_MAX_MEASURED_VALUE_ID, (void *)&zb_max); + if (ret != ESP_OK) { + log_e("Failed to set max value: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; } -void ZigbeeCarbonDioxideSensor::setTolerance(float tolerance) { +bool ZigbeeCarbonDioxideSensor::setTolerance(float tolerance) { float zb_tolerance = tolerance / 1000000.0f; esp_zb_attribute_list_t *carbon_dioxide_measure_cluster = esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_CARBON_DIOXIDE_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); - esp_zb_carbon_dioxide_measurement_cluster_add_attr( + esp_err_t ret = esp_zb_carbon_dioxide_measurement_cluster_add_attr( carbon_dioxide_measure_cluster, ESP_ZB_ZCL_ATTR_CARBON_DIOXIDE_MEASUREMENT_TOLERANCE_ID, (void *)&zb_tolerance ); + if (ret != ESP_OK) { + log_e("Failed to set tolerance: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; } -void ZigbeeCarbonDioxideSensor::setReporting(uint16_t min_interval, uint16_t max_interval, uint16_t delta) { +bool ZigbeeCarbonDioxideSensor::setReporting(uint16_t min_interval, uint16_t max_interval, uint16_t delta) { esp_zb_zcl_reporting_info_t reporting_info; memset(&reporting_info, 0, sizeof(esp_zb_zcl_reporting_info_t)); reporting_info.direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_SRV; @@ -60,24 +74,35 @@ void ZigbeeCarbonDioxideSensor::setReporting(uint16_t min_interval, uint16_t max memcpy(&reporting_info.u.send_info.delta.s32, &delta_f, sizeof(float)); esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_update_reporting_info(&reporting_info); + esp_err_t ret = esp_zb_zcl_update_reporting_info(&reporting_info); esp_zb_lock_release(); + if (ret != ESP_OK) { + log_e("Failed to set reporting: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; } -void ZigbeeCarbonDioxideSensor::setCarbonDioxide(float carbon_dioxide) { +bool ZigbeeCarbonDioxideSensor::setCarbonDioxide(float carbon_dioxide) { + esp_zb_zcl_status_t ret = ESP_ZB_ZCL_STATUS_SUCCESS; float zb_carbon_dioxide = carbon_dioxide / 1000000.0f; log_v("Updating carbon dioxide sensor value..."); /* Update carbon dioxide sensor measured value */ log_d("Setting carbon dioxide to %0.1f", carbon_dioxide); esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_set_attribute_val( + ret = esp_zb_zcl_set_attribute_val( _endpoint, ESP_ZB_ZCL_CLUSTER_ID_CARBON_DIOXIDE_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_CARBON_DIOXIDE_MEASUREMENT_MEASURED_VALUE_ID, &zb_carbon_dioxide, false ); esp_zb_lock_release(); + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set carbon dioxide: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + return false; + } + return true; } -void ZigbeeCarbonDioxideSensor::report() { +bool ZigbeeCarbonDioxideSensor::report() { /* Send report attributes command */ esp_zb_zcl_report_attr_cmd_t report_attr_cmd; report_attr_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; @@ -88,9 +113,14 @@ void ZigbeeCarbonDioxideSensor::report() { report_attr_cmd.manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC; esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_report_attr_cmd_req(&report_attr_cmd); + esp_err_t ret = esp_zb_zcl_report_attr_cmd_req(&report_attr_cmd); esp_zb_lock_release(); + if (ret != ESP_OK) { + log_e("Failed to send carbon dioxide report: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } log_v("Carbon dioxide report sent"); + return true; } #endif // CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeCarbonDioxideSensor.h b/libraries/Zigbee/src/ep/ZigbeeCarbonDioxideSensor.h index 41a9a4fb355..e0a6de48648 100644 --- a/libraries/Zigbee/src/ep/ZigbeeCarbonDioxideSensor.h +++ b/libraries/Zigbee/src/ep/ZigbeeCarbonDioxideSensor.h @@ -42,20 +42,20 @@ class ZigbeeCarbonDioxideSensor : public ZigbeeEP { ~ZigbeeCarbonDioxideSensor() {} // Set the carbon dioxide value in ppm - void setCarbonDioxide(float carbon_dioxide); + bool setCarbonDioxide(float carbon_dioxide); // Set the min and max value for the carbon dioxide sensor in ppm - void setMinMaxValue(float min, float max); + bool setMinMaxValue(float min, float max); // Set the tolerance value for the carbon dioxide sensor in ppm - void setTolerance(float tolerance); + bool setTolerance(float tolerance); // Set the reporting interval for carbon dioxide measurement in seconds and delta (carbon dioxide change in ppm) // NOTE: Delta reporting is currently not supported by the carbon dioxide sensor - void setReporting(uint16_t min_interval, uint16_t max_interval, uint16_t delta); + bool setReporting(uint16_t min_interval, uint16_t max_interval, uint16_t delta); // Report the carbon dioxide value - void report(); + bool report(); }; #endif // CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeColorDimmableLight.cpp b/libraries/Zigbee/src/ep/ZigbeeColorDimmableLight.cpp index 585b1549816..caac73b5c68 100644 --- a/libraries/Zigbee/src/ep/ZigbeeColorDimmableLight.cpp +++ b/libraries/Zigbee/src/ep/ZigbeeColorDimmableLight.cpp @@ -117,7 +117,8 @@ void ZigbeeColorDimmableLight::lightChanged() { } } -void ZigbeeColorDimmableLight::setLight(bool state, uint8_t level, uint8_t red, uint8_t green, uint8_t blue) { +bool ZigbeeColorDimmableLight::setLight(bool state, uint8_t level, uint8_t red, uint8_t green, uint8_t blue) { + esp_zb_zcl_status_t ret = ESP_ZB_ZCL_STATUS_SUCCESS; //Update all attributes _current_state = state; _current_level = level; @@ -126,55 +127,83 @@ void ZigbeeColorDimmableLight::setLight(bool state, uint8_t level, uint8_t red, espXyColor_t xy_color = espRgbColorToXYColor(_current_color); espHsvColor_t hsv_color = espRgbColorToHsvColor(_current_color); + uint8_t hue = (uint8_t)hsv_color.h; log_v("Updating light state: %d, level: %d, color: %d, %d, %d", state, level, red, green, blue); /* Update light clusters */ esp_zb_lock_acquire(portMAX_DELAY); //set on/off state - esp_zb_zcl_set_attribute_val( + ret = esp_zb_zcl_set_attribute_val( _endpoint, ESP_ZB_ZCL_CLUSTER_ID_ON_OFF, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID, &_current_state, false ); + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set light state: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + goto unlock_and_return; + } //set level - esp_zb_zcl_set_attribute_val( + ret = esp_zb_zcl_set_attribute_val( _endpoint, ESP_ZB_ZCL_CLUSTER_ID_LEVEL_CONTROL, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_LEVEL_CONTROL_CURRENT_LEVEL_ID, &_current_level, false ); - //set xy color - esp_zb_zcl_set_attribute_val( + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set light level: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + goto unlock_and_return; + } + //set x color + ret = esp_zb_zcl_set_attribute_val( _endpoint, ESP_ZB_ZCL_CLUSTER_ID_COLOR_CONTROL, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_COLOR_CONTROL_CURRENT_X_ID, &xy_color.x, false ); - esp_zb_zcl_set_attribute_val( + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set light xy color: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + goto unlock_and_return; + } + //set y color + ret = esp_zb_zcl_set_attribute_val( _endpoint, ESP_ZB_ZCL_CLUSTER_ID_COLOR_CONTROL, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_COLOR_CONTROL_CURRENT_Y_ID, &xy_color.y, false ); - //set hsv color - uint8_t hue = (uint8_t)hsv_color.h; - esp_zb_zcl_set_attribute_val( + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set light y color: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + goto unlock_and_return; + } + //set hue + ret = esp_zb_zcl_set_attribute_val( _endpoint, ESP_ZB_ZCL_CLUSTER_ID_COLOR_CONTROL, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_COLOR_CONTROL_CURRENT_HUE_ID, &hue, false ); - esp_zb_zcl_set_attribute_val( + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set light hue: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + goto unlock_and_return; + } + //set saturation + ret = esp_zb_zcl_set_attribute_val( _endpoint, ESP_ZB_ZCL_CLUSTER_ID_COLOR_CONTROL, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_COLOR_CONTROL_CURRENT_SATURATION_ID, &hsv_color.s, false ); + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set light saturation: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + goto unlock_and_return; + } +unlock_and_return: esp_zb_lock_release(); + return ret == ESP_ZB_ZCL_STATUS_SUCCESS; } -void ZigbeeColorDimmableLight::setLightState(bool state) { - setLight(state, _current_level, _current_color.r, _current_color.g, _current_color.b); +bool ZigbeeColorDimmableLight::setLightState(bool state) { + return setLight(state, _current_level, _current_color.r, _current_color.g, _current_color.b); } -void ZigbeeColorDimmableLight::setLightLevel(uint8_t level) { - setLight(_current_state, level, _current_color.r, _current_color.g, _current_color.b); +bool ZigbeeColorDimmableLight::setLightLevel(uint8_t level) { + return setLight(_current_state, level, _current_color.r, _current_color.g, _current_color.b); } -void ZigbeeColorDimmableLight::setLightColor(uint8_t red, uint8_t green, uint8_t blue) { - setLight(_current_state, _current_level, red, green, blue); +bool ZigbeeColorDimmableLight::setLightColor(uint8_t red, uint8_t green, uint8_t blue) { + return setLight(_current_state, _current_level, red, green, blue); } -void ZigbeeColorDimmableLight::setLightColor(espRgbColor_t rgb_color) { - setLight(_current_state, _current_level, rgb_color.r, rgb_color.g, rgb_color.b); +bool ZigbeeColorDimmableLight::setLightColor(espRgbColor_t rgb_color) { + return setLight(_current_state, _current_level, rgb_color.r, rgb_color.g, rgb_color.b); } -void ZigbeeColorDimmableLight::setLightColor(espHsvColor_t hsv_color) { +bool ZigbeeColorDimmableLight::setLightColor(espHsvColor_t hsv_color) { espRgbColor_t rgb_color = espHsvColorToRgbColor(hsv_color); - setLight(_current_state, _current_level, rgb_color.r, rgb_color.g, rgb_color.b); + return setLight(_current_state, _current_level, rgb_color.r, rgb_color.g, rgb_color.b); } #endif // CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeColorDimmableLight.h b/libraries/Zigbee/src/ep/ZigbeeColorDimmableLight.h index 64df3565793..6681f213ad0 100644 --- a/libraries/Zigbee/src/ep/ZigbeeColorDimmableLight.h +++ b/libraries/Zigbee/src/ep/ZigbeeColorDimmableLight.h @@ -62,12 +62,12 @@ class ZigbeeColorDimmableLight : public ZigbeeEP { lightChanged(); } - void setLightState(bool state); - void setLightLevel(uint8_t level); - void setLightColor(uint8_t red, uint8_t green, uint8_t blue); - void setLightColor(espRgbColor_t rgb_color); - void setLightColor(espHsvColor_t hsv_color); - void setLight(bool state, uint8_t level, uint8_t red, uint8_t green, uint8_t blue); + bool setLightState(bool state); + bool setLightLevel(uint8_t level); + bool setLightColor(uint8_t red, uint8_t green, uint8_t blue); + bool setLightColor(espRgbColor_t rgb_color); + bool setLightColor(espHsvColor_t hsv_color); + bool setLight(bool state, uint8_t level, uint8_t red, uint8_t green, uint8_t blue); bool getLightState() { return _current_state; diff --git a/libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.cpp b/libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.cpp index 68f287153cb..935d638324f 100644 --- a/libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.cpp +++ b/libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.cpp @@ -6,7 +6,8 @@ ZigbeeColorDimmerSwitch *ZigbeeColorDimmerSwitch::_instance = nullptr; ZigbeeColorDimmerSwitch::ZigbeeColorDimmerSwitch(uint8_t endpoint) : ZigbeeEP(endpoint) { _device_id = ESP_ZB_HA_COLOR_DIMMER_SWITCH_DEVICE_ID; - _instance = this; // Set the static pointer to this instance + _instance = this; // Set the static pointer to this instance + _device = nullptr; // Initialize light pointer to null esp_zb_color_dimmable_switch_cfg_t switch_cfg = ESP_ZB_DEFAULT_COLOR_DIMMABLE_SWITCH_CONFIG(); _cluster_list = esp_zb_color_dimmable_switch_clusters_create(&switch_cfg); @@ -17,20 +18,39 @@ ZigbeeColorDimmerSwitch::ZigbeeColorDimmerSwitch(uint8_t endpoint) : ZigbeeEP(en } void ZigbeeColorDimmerSwitch::bindCb(esp_zb_zdp_status_t zdo_status, void *user_ctx) { + ZigbeeColorDimmerSwitch *instance = static_cast(user_ctx); if (zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) { log_i("Bound successfully!"); - if (user_ctx) { - zb_device_params_t *light = (zb_device_params_t *)user_ctx; + if (instance->_device) { + zb_device_params_t *light = (zb_device_params_t *)instance->_device; log_i("The light originating from address(0x%x) on endpoint(%d)", light->short_addr, light->endpoint); - _instance->_bound_devices.push_back(light); + log_d("Light bound to a switch on EP %d", instance->_endpoint); + instance->_bound_devices.push_back(light); } - _is_bound = true; + instance->_is_bound = true; } else { - log_e("Binding failed!"); + instance->_device = nullptr; + } +} + +void ZigbeeColorDimmerSwitch::bindCbWrapper(esp_zb_zdp_status_t zdo_status, void *user_ctx) { + ZigbeeColorDimmerSwitch *instance = static_cast(user_ctx); + if (instance) { + log_d("bindCbWrapper on EP %d", instance->_endpoint); + instance->bindCb(zdo_status, user_ctx); + } +} + +void ZigbeeColorDimmerSwitch::findCbWrapper(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx) { + ZigbeeColorDimmerSwitch *instance = static_cast(user_ctx); + if (instance) { + log_d("findCbWrapper on EP %d", instance->_endpoint); + instance->findCb(zdo_status, addr, endpoint, user_ctx); } } void ZigbeeColorDimmerSwitch::findCb(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx) { + ZigbeeColorDimmerSwitch *instance = static_cast(user_ctx); if (zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) { log_d("Found light endpoint"); esp_zb_zdo_bind_req_param_t bind_req; @@ -39,22 +59,23 @@ void ZigbeeColorDimmerSwitch::findCb(esp_zb_zdp_status_t zdo_status, uint16_t ad light->short_addr = addr; esp_zb_ieee_address_by_short(light->short_addr, light->ieee_addr); esp_zb_get_long_address(bind_req.src_address); - bind_req.src_endp = *((uint8_t *)user_ctx); //_endpoint; + bind_req.src_endp = instance->_endpoint; bind_req.cluster_id = ESP_ZB_ZCL_CLUSTER_ID_ON_OFF; bind_req.dst_addr_mode = ESP_ZB_ZDO_BIND_DST_ADDR_MODE_64_BIT_EXTENDED; memcpy(bind_req.dst_address_u.addr_long, light->ieee_addr, sizeof(esp_zb_ieee_addr_t)); bind_req.dst_endp = endpoint; bind_req.req_dst_addr = esp_zb_get_short_address(); + instance->_device = light; log_v("Try to bind on/off control of dimmable light"); - esp_zb_zdo_device_bind_req(&bind_req, bindCb, NULL); + esp_zb_zdo_device_bind_req(&bind_req, ZigbeeColorDimmerSwitch::bindCbWrapper, NULL); bind_req.cluster_id = ESP_ZB_ZCL_CLUSTER_ID_LEVEL_CONTROL; log_v("Try to bind level control of dimmable light"); - esp_zb_zdo_device_bind_req(&bind_req, bindCb, NULL); + esp_zb_zdo_device_bind_req(&bind_req, ZigbeeColorDimmerSwitch::bindCbWrapper, NULL); bind_req.cluster_id = ESP_ZB_ZCL_CLUSTER_ID_COLOR_CONTROL; log_v("Try to bind color control of dimmable light"); - esp_zb_zdo_device_bind_req(&bind_req, bindCb, (void *)light); + esp_zb_zdo_device_bind_req(&bind_req, ZigbeeColorDimmerSwitch::bindCbWrapper, this); } else { - log_v("No color dimmable light endpoint found"); + log_d("No color dimmable light endpoint found"); } } @@ -70,7 +91,7 @@ void ZigbeeColorDimmerSwitch::findEndpoint(esp_zb_zdo_match_desc_req_param_t *cm .num_out_clusters = 3, .cluster_list = cluster_list, }; - esp_zb_zdo_match_cluster(&color_dimmable_light_req, findCb, &_endpoint); + esp_zb_zdo_match_cluster(&color_dimmable_light_req, ZigbeeColorDimmerSwitch::findCbWrapper, this); } // Methods to control the light diff --git a/libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.h b/libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.h index dbe50a20230..ada1f75fbb4 100644 --- a/libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.h +++ b/libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.h @@ -47,10 +47,13 @@ class ZigbeeColorDimmerSwitch : public ZigbeeEP { private: // save instance of the class in order to use it in static functions static ZigbeeColorDimmerSwitch *_instance; + zb_device_params_t *_device; void findEndpoint(esp_zb_zdo_match_desc_req_param_t *cmd_req); - static void bindCb(esp_zb_zdp_status_t zdo_status, void *user_ctx); - static void findCb(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx); + void bindCb(esp_zb_zdp_status_t zdo_status, void *user_ctx); + void findCb(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx); + static void bindCbWrapper(esp_zb_zdp_status_t zdo_status, void *user_ctx); + static void findCbWrapper(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx); void calculateXY(uint8_t red, uint8_t green, uint8_t blue, uint16_t &x, uint16_t &y); }; diff --git a/libraries/Zigbee/src/ep/ZigbeeContactSwitch.cpp b/libraries/Zigbee/src/ep/ZigbeeContactSwitch.cpp index 6237315d5d9..ced8e43d6ea 100644 --- a/libraries/Zigbee/src/ep/ZigbeeContactSwitch.cpp +++ b/libraries/Zigbee/src/ep/ZigbeeContactSwitch.cpp @@ -29,29 +29,39 @@ void ZigbeeContactSwitch::setIASClientEndpoint(uint8_t ep_number) { _ias_cie_endpoint = ep_number; } -void ZigbeeContactSwitch::setClosed() { +bool ZigbeeContactSwitch::setClosed() { log_v("Setting Contact switch to closed"); uint8_t closed = 0; // ALARM1 = 0, ALARM2 = 0 esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_set_attribute_val( + esp_err_t ret = esp_zb_zcl_set_attribute_val( _endpoint, ESP_ZB_ZCL_CLUSTER_ID_IAS_ZONE, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_IAS_ZONE_ZONESTATUS_ID, &closed, false ); esp_zb_lock_release(); + if (ret != ESP_OK) { + log_e("Failed to set contact switch to closed: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } _zone_status = closed; - report(); + return report(); } -void ZigbeeContactSwitch::setOpen() { +bool ZigbeeContactSwitch::setOpen() { log_v("Setting Contact switch to open"); uint8_t open = ESP_ZB_ZCL_IAS_ZONE_ZONE_STATUS_ALARM1 | ESP_ZB_ZCL_IAS_ZONE_ZONE_STATUS_ALARM2; // ALARM1 = 1, ALARM2 = 1 esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_set_attribute_val(_endpoint, ESP_ZB_ZCL_CLUSTER_ID_IAS_ZONE, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_IAS_ZONE_ZONESTATUS_ID, &open, false); + esp_err_t ret = esp_zb_zcl_set_attribute_val( + _endpoint, ESP_ZB_ZCL_CLUSTER_ID_IAS_ZONE, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_IAS_ZONE_ZONESTATUS_ID, &open, false + ); esp_zb_lock_release(); + if (ret != ESP_OK) { + log_e("Failed to set contact switch to open: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } _zone_status = open; - report(); + return report(); } -void ZigbeeContactSwitch::report() { +bool ZigbeeContactSwitch::report() { /* Send IAS Zone status changed notification command */ esp_zb_zcl_ias_zone_status_change_notif_cmd_t status_change_notif_cmd; @@ -66,9 +76,14 @@ void ZigbeeContactSwitch::report() { status_change_notif_cmd.delay = 0; esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_ias_zone_status_change_notif_cmd_req(&status_change_notif_cmd); + esp_err_t ret = esp_zb_zcl_ias_zone_status_change_notif_cmd_req(&status_change_notif_cmd); esp_zb_lock_release(); + if (ret != ESP_OK) { + log_e("Failed to send IAS Zone status changed notification: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } log_v("IAS Zone status changed notification sent"); + return true; } void ZigbeeContactSwitch::zbIASZoneEnrollResponse(const esp_zb_zcl_ias_zone_enroll_response_message_t *message) { diff --git a/libraries/Zigbee/src/ep/ZigbeeContactSwitch.h b/libraries/Zigbee/src/ep/ZigbeeContactSwitch.h index f44ce1cec40..b33effd8dfc 100644 --- a/libraries/Zigbee/src/ep/ZigbeeContactSwitch.h +++ b/libraries/Zigbee/src/ep/ZigbeeContactSwitch.h @@ -48,13 +48,13 @@ class ZigbeeContactSwitch : public ZigbeeEP { void setIASClientEndpoint(uint8_t ep_number); // Set the contact switch value to closed - void setClosed(); + bool setClosed(); // Set the contact switch value to open - void setOpen(); + bool setOpen(); // Report the contact switch value, done automatically after setting the position - void report(); + bool report(); private: void zbIASZoneEnrollResponse(const esp_zb_zcl_ias_zone_enroll_response_message_t *message) override; diff --git a/libraries/Zigbee/src/ep/ZigbeeDimmableLight.cpp b/libraries/Zigbee/src/ep/ZigbeeDimmableLight.cpp index 34622d1d2db..05a7e5ad6c1 100644 --- a/libraries/Zigbee/src/ep/ZigbeeDimmableLight.cpp +++ b/libraries/Zigbee/src/ep/ZigbeeDimmableLight.cpp @@ -1,4 +1,3 @@ - #include "ZigbeeDimmableLight.h" #if CONFIG_ZB_ENABLED @@ -52,7 +51,8 @@ void ZigbeeDimmableLight::lightChanged() { } } -void ZigbeeDimmableLight::setLight(bool state, uint8_t level) { +bool ZigbeeDimmableLight::setLight(bool state, uint8_t level) { + esp_zb_zcl_status_t ret = ESP_ZB_ZCL_STATUS_SUCCESS; // Update all attributes _current_state = state; _current_level = level; @@ -62,22 +62,32 @@ void ZigbeeDimmableLight::setLight(bool state, uint8_t level) { /* Update light clusters */ esp_zb_lock_acquire(portMAX_DELAY); // set on/off state - esp_zb_zcl_set_attribute_val( + ret = esp_zb_zcl_set_attribute_val( _endpoint, ESP_ZB_ZCL_CLUSTER_ID_ON_OFF, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID, &_current_state, false ); + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set light state: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + goto unlock_and_return; + } // set level - esp_zb_zcl_set_attribute_val( + ret = esp_zb_zcl_set_attribute_val( _endpoint, ESP_ZB_ZCL_CLUSTER_ID_LEVEL_CONTROL, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_LEVEL_CONTROL_CURRENT_LEVEL_ID, &_current_level, false ); + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set light level: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + goto unlock_and_return; + } +unlock_and_return: esp_zb_lock_release(); + return ret == ESP_ZB_ZCL_STATUS_SUCCESS; } -void ZigbeeDimmableLight::setLightState(bool state) { - setLight(state, _current_level); +bool ZigbeeDimmableLight::setLightState(bool state) { + return setLight(state, _current_level); } -void ZigbeeDimmableLight::setLightLevel(uint8_t level) { - setLight(_current_state, level); +bool ZigbeeDimmableLight::setLightLevel(uint8_t level) { + return setLight(_current_state, level); } esp_zb_cluster_list_t *ZigbeeDimmableLight::zigbee_dimmable_light_clusters_create(zigbee_dimmable_light_cfg_t *light_cfg) { diff --git a/libraries/Zigbee/src/ep/ZigbeeDimmableLight.h b/libraries/Zigbee/src/ep/ZigbeeDimmableLight.h index 45c3e97c00b..747fdbafaef 100644 --- a/libraries/Zigbee/src/ep/ZigbeeDimmableLight.h +++ b/libraries/Zigbee/src/ep/ZigbeeDimmableLight.h @@ -76,9 +76,9 @@ class ZigbeeDimmableLight : public ZigbeeEP { lightChanged(); } - void setLightState(bool state); - void setLightLevel(uint8_t level); - void setLight(bool state, uint8_t level); + bool setLightState(bool state); + bool setLightLevel(uint8_t level); + bool setLight(bool state, uint8_t level); bool getLightState() { return _current_state; @@ -89,7 +89,6 @@ class ZigbeeDimmableLight : public ZigbeeEP { private: void zbAttributeSet(const esp_zb_zcl_set_attr_value_message_t *message) override; - void lightChanged(); // callback function to be called on light change (State, Level) void (*_on_light_change)(bool, uint8_t); diff --git a/libraries/Zigbee/src/ep/ZigbeeDoorWindowHandle.cpp b/libraries/Zigbee/src/ep/ZigbeeDoorWindowHandle.cpp index 70008fbab10..c5b62ee2b75 100644 --- a/libraries/Zigbee/src/ep/ZigbeeDoorWindowHandle.cpp +++ b/libraries/Zigbee/src/ep/ZigbeeDoorWindowHandle.cpp @@ -29,41 +29,58 @@ void ZigbeeDoorWindowHandle::setIASClientEndpoint(uint8_t ep_number) { _ias_cie_endpoint = ep_number; } -void ZigbeeDoorWindowHandle::setClosed() { +bool ZigbeeDoorWindowHandle::setClosed() { + esp_zb_zcl_status_t ret = ESP_ZB_ZCL_STATUS_SUCCESS; log_v("Setting Door/Window handle to closed"); uint8_t closed = 0; // ALARM1 = 0, ALARM2 = 0 esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_set_attribute_val( + ret = esp_zb_zcl_set_attribute_val( _endpoint, ESP_ZB_ZCL_CLUSTER_ID_IAS_ZONE, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_IAS_ZONE_ZONESTATUS_ID, &closed, false ); esp_zb_lock_release(); + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set door/window handle to closed: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + return false; + } _zone_status = closed; - report(); + return report(); } -void ZigbeeDoorWindowHandle::setOpen() { +bool ZigbeeDoorWindowHandle::setOpen() { + esp_zb_zcl_status_t ret = ESP_ZB_ZCL_STATUS_SUCCESS; log_v("Setting Door/Window handle to open"); uint8_t open = ESP_ZB_ZCL_IAS_ZONE_ZONE_STATUS_ALARM1 | ESP_ZB_ZCL_IAS_ZONE_ZONE_STATUS_ALARM2; // ALARM1 = 1, ALARM2 = 1 esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_set_attribute_val(_endpoint, ESP_ZB_ZCL_CLUSTER_ID_IAS_ZONE, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_IAS_ZONE_ZONESTATUS_ID, &open, false); + ret = esp_zb_zcl_set_attribute_val( + _endpoint, ESP_ZB_ZCL_CLUSTER_ID_IAS_ZONE, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_IAS_ZONE_ZONESTATUS_ID, &open, false + ); esp_zb_lock_release(); + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set door/window handle to open: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + return false; + } _zone_status = open; - report(); + return report(); } -void ZigbeeDoorWindowHandle::setTilted() { +bool ZigbeeDoorWindowHandle::setTilted() { + esp_zb_zcl_status_t ret = ESP_ZB_ZCL_STATUS_SUCCESS; log_v("Setting Door/Window handle to tilted"); uint8_t tilted = ESP_ZB_ZCL_IAS_ZONE_ZONE_STATUS_ALARM1; // ALARM1 = 1, ALARM2 = 0 esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_set_attribute_val( + ret = esp_zb_zcl_set_attribute_val( _endpoint, ESP_ZB_ZCL_CLUSTER_ID_IAS_ZONE, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_IAS_ZONE_ZONESTATUS_ID, &tilted, false ); esp_zb_lock_release(); + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set door/window handle to tilted: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + return false; + } _zone_status = tilted; - report(); + return report(); } -void ZigbeeDoorWindowHandle::report() { +bool ZigbeeDoorWindowHandle::report() { /* Send IAS Zone status changed notification command */ esp_zb_zcl_ias_zone_status_change_notif_cmd_t status_change_notif_cmd; @@ -77,10 +94,12 @@ void ZigbeeDoorWindowHandle::report() { status_change_notif_cmd.zone_id = _zone_id; status_change_notif_cmd.delay = 0; + //NOTE: Check result of esp_zb_zcl_ias_zone_status_change_notif_cmd_req() and return true if success, false if failure esp_zb_lock_acquire(portMAX_DELAY); esp_zb_zcl_ias_zone_status_change_notif_cmd_req(&status_change_notif_cmd); esp_zb_lock_release(); log_v("IAS Zone status changed notification sent"); + return true; } void ZigbeeDoorWindowHandle::zbIASZoneEnrollResponse(const esp_zb_zcl_ias_zone_enroll_response_message_t *message) { diff --git a/libraries/Zigbee/src/ep/ZigbeeDoorWindowHandle.h b/libraries/Zigbee/src/ep/ZigbeeDoorWindowHandle.h index 8d4eff9e45a..efffd34b12f 100644 --- a/libraries/Zigbee/src/ep/ZigbeeDoorWindowHandle.h +++ b/libraries/Zigbee/src/ep/ZigbeeDoorWindowHandle.h @@ -49,16 +49,16 @@ class ZigbeeDoorWindowHandle : public ZigbeeEP { void setIASClientEndpoint(uint8_t ep_number); // Set the door/window handle value to closed - void setClosed(); + bool setClosed(); // Set the door/window handle value to open - void setOpen(); + bool setOpen(); // Set the door/window handle value to tilted - void setTilted(); + bool setTilted(); // Report the door/window handle value, done automatically after setting the position - void report(); + bool report(); private: void zbIASZoneEnrollResponse(const esp_zb_zcl_ias_zone_enroll_response_message_t *message) override; diff --git a/libraries/Zigbee/src/ep/ZigbeeElectricalMeasurement.cpp b/libraries/Zigbee/src/ep/ZigbeeElectricalMeasurement.cpp new file mode 100644 index 00000000000..8fa456c967a --- /dev/null +++ b/libraries/Zigbee/src/ep/ZigbeeElectricalMeasurement.cpp @@ -0,0 +1,979 @@ +#include "ZigbeeElectricalMeasurement.h" +#if CONFIG_ZB_ENABLED + +// Workaround for wrong name in ZCL header +#define ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_DC_POWER_ID ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_DCPOWER_ID + +esp_zb_cluster_list_t *zigbee_electrical_measurement_clusters_create(zigbee_electrical_measurement_cfg_t *electrical_measurement) { + esp_zb_basic_cluster_cfg_t *basic_cfg = electrical_measurement ? &(electrical_measurement->basic_cfg) : NULL; + esp_zb_identify_cluster_cfg_t *identify_cfg = electrical_measurement ? &(electrical_measurement->identify_cfg) : NULL; + esp_zb_electrical_meas_cluster_cfg_t *electrical_measurement_cfg = electrical_measurement ? &(electrical_measurement->electrical_measurement_cfg) : NULL; + esp_zb_cluster_list_t *cluster_list = esp_zb_zcl_cluster_list_create(); + esp_zb_cluster_list_add_basic_cluster(cluster_list, esp_zb_basic_cluster_create(basic_cfg), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_zb_cluster_list_add_identify_cluster(cluster_list, esp_zb_identify_cluster_create(identify_cfg), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_zb_cluster_list_add_electrical_meas_cluster( + cluster_list, esp_zb_electrical_meas_cluster_create(electrical_measurement_cfg), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE + ); + return cluster_list; +} + +ZigbeeElectricalMeasurement::ZigbeeElectricalMeasurement(uint8_t endpoint) : ZigbeeEP(endpoint) { + _device_id = ESP_ZB_HA_SIMPLE_SENSOR_DEVICE_ID; + + //Create custom pressure sensor configuration + zigbee_electrical_measurement_cfg_t electrical_measurement_cfg = ZIGBEE_DEFAULT_ELECTRICAL_MEASUREMENT_CONFIG(); + _cluster_list = zigbee_electrical_measurement_clusters_create(&electrical_measurement_cfg); + + _ep_config = { + .endpoint = _endpoint, .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, .app_device_id = ESP_ZB_HA_METER_INTERFACE_DEVICE_ID, .app_device_version = 0 + }; +} + +/* DC MEASUREMENT */ + +bool ZigbeeElectricalMeasurement::addDCMeasurement(ZIGBEE_DC_MEASUREMENT_TYPE measurement_type) { + esp_zb_attribute_list_t *electrical_measurement_cluster = + esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_ELECTRICAL_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + + // Set the DC measurement type bit in the measurement type attribute + measure_type |= ESP_ZB_ZCL_ELECTRICAL_MEASUREMENT_DC_MEASUREMENT; + esp_zb_cluster_update_attr(electrical_measurement_cluster, ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_MEASUREMENT_TYPE_ID, &measure_type); + + int16_t default_min = -32767; + int16_t default_max = 32767; + int16_t default_measurement = 0; + uint16_t default_multiplier = 1; + uint16_t default_divisor = 1; + + esp_err_t ret = ESP_OK; + // Add the DC Voltage attributes + if (measurement_type == ZIGBEE_DC_MEASUREMENT_TYPE_VOLTAGE) { + ret = esp_zb_electrical_meas_cluster_add_attr( + electrical_measurement_cluster, ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_DC_VOLTAGE_ID, (void *)&default_measurement + ); + if (ret != ESP_OK) { + log_e("Failed to add DC voltage: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = + esp_zb_electrical_meas_cluster_add_attr(electrical_measurement_cluster, ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_DC_VOLTAGE_MIN_ID, (void *)&default_min); + if (ret != ESP_OK) { + log_e("Failed to add DC voltage min: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = + esp_zb_electrical_meas_cluster_add_attr(electrical_measurement_cluster, ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_DC_VOLTAGE_MAX_ID, (void *)&default_max); + if (ret != ESP_OK) { + log_e("Failed to add DC voltage max: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_electrical_meas_cluster_add_attr( + electrical_measurement_cluster, ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_DC_VOLTAGE_MULTIPLIER_ID, (void *)&default_multiplier + ); + if (ret != ESP_OK) { + log_e("Failed to add DC voltage multiplier: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_electrical_meas_cluster_add_attr( + electrical_measurement_cluster, ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_DC_VOLTAGE_DIVISOR_ID, (void *)&default_divisor + ); + if (ret != ESP_OK) { + log_e("Failed to add DC voltage divisor: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + + } else if (measurement_type == ZIGBEE_DC_MEASUREMENT_TYPE_CURRENT) { + // Add the DC Current attributes + ret = esp_zb_electrical_meas_cluster_add_attr( + electrical_measurement_cluster, ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_DC_CURRENT_ID, (void *)&default_measurement + ); + if (ret != ESP_OK) { + log_e("Failed to add DC current: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = + esp_zb_electrical_meas_cluster_add_attr(electrical_measurement_cluster, ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_DC_CURRENT_MIN_ID, (void *)&default_min); + if (ret != ESP_OK) { + log_e("Failed to add DC current min: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = + esp_zb_electrical_meas_cluster_add_attr(electrical_measurement_cluster, ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_DC_CURRENT_MAX_ID, (void *)&default_max); + if (ret != ESP_OK) { + log_e("Failed to add DC current max: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_electrical_meas_cluster_add_attr( + electrical_measurement_cluster, ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_DC_CURRENT_MULTIPLIER_ID, (void *)&default_multiplier + ); + if (ret != ESP_OK) { + log_e("Failed to add DC current multiplier: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_electrical_meas_cluster_add_attr( + electrical_measurement_cluster, ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_DC_CURRENT_DIVISOR_ID, (void *)&default_divisor + ); + if (ret != ESP_OK) { + log_e("Failed to add DC current divisor: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + } else { //(measurement_type == ZIGBEE_DC_MEASUREMENT_TYPE_POWER) + // Add the DC Power attributes + ret = + esp_zb_electrical_meas_cluster_add_attr(electrical_measurement_cluster, ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_DC_POWER_ID, (void *)&default_measurement); + if (ret != ESP_OK) { + log_e("Failed to add DC power: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_electrical_meas_cluster_add_attr(electrical_measurement_cluster, ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_DC_POWER_MIN_ID, (void *)&default_min); + if (ret != ESP_OK) { + log_e("Failed to add DC power min: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_electrical_meas_cluster_add_attr(electrical_measurement_cluster, ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_DC_POWER_MAX_ID, (void *)&default_max); + if (ret != ESP_OK) { + log_e("Failed to add DC power max: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_electrical_meas_cluster_add_attr( + electrical_measurement_cluster, ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_DC_POWER_MULTIPLIER_ID, (void *)&default_multiplier + ); + if (ret != ESP_OK) { + log_e("Failed to add DC power multiplier: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_electrical_meas_cluster_add_attr( + electrical_measurement_cluster, ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_DC_POWER_DIVISOR_ID, (void *)&default_divisor + ); + if (ret != ESP_OK) { + log_e("Failed to add DC power divisor: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + } + return true; +} + +bool ZigbeeElectricalMeasurement::setDCMinMaxValue(ZIGBEE_DC_MEASUREMENT_TYPE measurement_type, int16_t min, int16_t max) { + esp_zb_attribute_list_t *electrical_measurement_cluster = + esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_ELECTRICAL_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + + esp_zb_zcl_electrical_measurement_attr_t attr_min = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_DC_VOLTAGE_MIN_ID; + esp_zb_zcl_electrical_measurement_attr_t attr_max = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_DC_VOLTAGE_MAX_ID; + if (measurement_type == ZIGBEE_DC_MEASUREMENT_TYPE_CURRENT) { + attr_min = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_DC_CURRENT_MIN_ID; + attr_max = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_DC_CURRENT_MAX_ID; + } else if (measurement_type == ZIGBEE_DC_MEASUREMENT_TYPE_POWER) { + attr_min = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_DC_POWER_MIN_ID; + attr_max = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_DC_POWER_MAX_ID; + } + esp_err_t ret = ESP_OK; + ret = esp_zb_cluster_update_attr(electrical_measurement_cluster, attr_min, (void *)&min); + if (ret != ESP_OK) { + log_e("Failed to set min value: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_cluster_update_attr(electrical_measurement_cluster, attr_max, (void *)&max); + if (ret != ESP_OK) { + log_e("Failed to set max value: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; +} + +bool ZigbeeElectricalMeasurement::setDCMultiplierDivisor(ZIGBEE_DC_MEASUREMENT_TYPE measurement_type, uint16_t multiplier, uint16_t divisor) { + esp_zb_attribute_list_t *electrical_measurement_cluster = + esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_ELECTRICAL_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + + esp_zb_zcl_electrical_measurement_attr_t attr_multiplier = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_DC_VOLTAGE_MULTIPLIER_ID; + esp_zb_zcl_electrical_measurement_attr_t attr_divisor = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_DC_VOLTAGE_DIVISOR_ID; + + if (measurement_type == ZIGBEE_DC_MEASUREMENT_TYPE_CURRENT) { + attr_multiplier = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_DC_CURRENT_MULTIPLIER_ID; + attr_divisor = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_DC_CURRENT_DIVISOR_ID; + } else if (measurement_type == ZIGBEE_DC_MEASUREMENT_TYPE_POWER) { + attr_multiplier = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_DC_POWER_MULTIPLIER_ID; + attr_divisor = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_DC_POWER_DIVISOR_ID; + } + + esp_err_t ret = ESP_OK; + ret = esp_zb_cluster_update_attr(electrical_measurement_cluster, attr_multiplier, (void *)&multiplier); + if (ret != ESP_OK) { + log_e("Failed to set multiplier: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_cluster_update_attr(electrical_measurement_cluster, attr_divisor, (void *)&divisor); + if (ret != ESP_OK) { + log_e("Failed to set divisor: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; +} + +bool ZigbeeElectricalMeasurement::setDCReporting(ZIGBEE_DC_MEASUREMENT_TYPE measurement_type, uint16_t min_interval, uint16_t max_interval, int16_t delta) { + uint16_t attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_DC_VOLTAGE_ID; + if (measurement_type == ZIGBEE_DC_MEASUREMENT_TYPE_CURRENT) { + attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_DC_CURRENT_ID; + } else if (measurement_type == ZIGBEE_DC_MEASUREMENT_TYPE_POWER) { + attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_DC_POWER_ID; + } + + esp_zb_zcl_reporting_info_t reporting_info; + memset(&reporting_info, 0, sizeof(esp_zb_zcl_reporting_info_t)); + reporting_info.direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_SRV; + reporting_info.ep = _endpoint; + reporting_info.cluster_id = ESP_ZB_ZCL_CLUSTER_ID_ELECTRICAL_MEASUREMENT; + reporting_info.cluster_role = ESP_ZB_ZCL_CLUSTER_SERVER_ROLE; + reporting_info.attr_id = attr_id; + reporting_info.u.send_info.min_interval = min_interval; + reporting_info.u.send_info.max_interval = max_interval; + reporting_info.u.send_info.def_min_interval = min_interval; + reporting_info.u.send_info.def_max_interval = max_interval; + reporting_info.u.send_info.delta.s16 = delta; + reporting_info.dst.profile_id = ESP_ZB_AF_HA_PROFILE_ID; + reporting_info.manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC; + esp_zb_lock_acquire(portMAX_DELAY); + esp_err_t ret = esp_zb_zcl_update_reporting_info(&reporting_info); + esp_zb_lock_release(); + if (ret != ESP_OK) { + log_e("Failed to set reporting: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; +} + +bool ZigbeeElectricalMeasurement::setDCMeasurement(ZIGBEE_DC_MEASUREMENT_TYPE measurement_type, int16_t measurement) { + esp_zb_zcl_status_t ret = ESP_ZB_ZCL_STATUS_SUCCESS; + + esp_zb_zcl_electrical_measurement_attr_t attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_DC_VOLTAGE_ID; + if (measurement_type == ZIGBEE_DC_MEASUREMENT_TYPE_CURRENT) { + attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_DC_CURRENT_ID; + } else if (measurement_type == ZIGBEE_DC_MEASUREMENT_TYPE_POWER) { + attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_DC_POWER_ID; + } + + log_v("Updating DC measurement value..."); + /* Update DC sensor measured value */ + log_d("Setting DC measurement to %d", measurement); + esp_zb_lock_acquire(portMAX_DELAY); + ret = esp_zb_zcl_set_attribute_val(_endpoint, ESP_ZB_ZCL_CLUSTER_ID_ELECTRICAL_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, attr_id, &measurement, false); + esp_zb_lock_release(); + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set DC measurement: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + return false; + } + return true; +} + +bool ZigbeeElectricalMeasurement::reportDC(ZIGBEE_DC_MEASUREMENT_TYPE measurement_type) { + uint16_t attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_DC_VOLTAGE_ID; + if (measurement_type == ZIGBEE_DC_MEASUREMENT_TYPE_CURRENT) { + attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_DC_CURRENT_ID; + } else if (measurement_type == ZIGBEE_DC_MEASUREMENT_TYPE_POWER) { + attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_DC_POWER_ID; + } + /* Send report attributes command */ + esp_zb_zcl_report_attr_cmd_t report_attr_cmd; + report_attr_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; + report_attr_cmd.attributeID = attr_id; + report_attr_cmd.direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_CLI; + report_attr_cmd.clusterID = ESP_ZB_ZCL_CLUSTER_ID_ELECTRICAL_MEASUREMENT; + report_attr_cmd.zcl_basic_cmd.src_endpoint = _endpoint; + report_attr_cmd.manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC; + + esp_zb_lock_acquire(portMAX_DELAY); + esp_err_t ret = esp_zb_zcl_report_attr_cmd_req(&report_attr_cmd); + esp_zb_lock_release(); + if (ret != ESP_OK) { + log_e("Failed to send DC report: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + log_v("DC report sent"); + return true; +} + +/* AC MEASUREMENT */ + +bool ZigbeeElectricalMeasurement::addACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE measurement_type, ZIGBEE_AC_PHASE_TYPE phase_type) { + esp_zb_attribute_list_t *electrical_measurement_cluster = + esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_ELECTRICAL_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + + switch (phase_type) { + case ZIGBEE_AC_PHASE_TYPE_NON_SPECIFIC: + // Non phase specific dont need any bit set + break; + case ZIGBEE_AC_PHASE_TYPE_A: measure_type |= ESP_ZB_ZCL_ELECTRICAL_MEASUREMENT_PHASE_A_MEASUREMENT; break; + case ZIGBEE_AC_PHASE_TYPE_B: measure_type |= ESP_ZB_ZCL_ELECTRICAL_MEASUREMENT_PHASE_B_MEASUREMENT; break; + case ZIGBEE_AC_PHASE_TYPE_C: measure_type |= ESP_ZB_ZCL_ELECTRICAL_MEASUREMENT_PHASE_C_MEASUREMENT; break; + default: log_e("Invalid phase type"); break; + } + // Set Active measurement bit for active power and power factor, otherwise no bit needed for voltage, current + if (measurement_type == ZIGBEE_AC_MEASUREMENT_TYPE_POWER || measurement_type == ZIGBEE_AC_MEASUREMENT_TYPE_POWER_FACTOR) { + measure_type |= ESP_ZB_ZCL_ELECTRICAL_MEASUREMENT_ACTIVE_MEASUREMENT; // Active power is used + } + // Update the measurement type attribute + esp_zb_cluster_update_attr(electrical_measurement_cluster, ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_MEASUREMENT_TYPE_ID, &measure_type); + + // Default values for AC measurements + [[maybe_unused]] + int16_t default_ac_power_min = -32767; + [[maybe_unused]] + int16_t default_ac_power_max = 32767; + [[maybe_unused]] + int16_t default_ac_power_measurement = 0; + [[maybe_unused]] + uint16_t default_ac_min = 0x0000; + [[maybe_unused]] + uint16_t default_ac_max = 0xffff; + [[maybe_unused]] + uint16_t default_ac_measurement = 0x0000; + [[maybe_unused]] + uint16_t default_ac_multiplier = 1; + [[maybe_unused]] + uint16_t default_ac_divisor = 1; + [[maybe_unused]] + int8_t default_ac_power_factor = 100; + + esp_err_t ret = ESP_OK; + + // AC Frequency + if (measurement_type == ZIGBEE_AC_MEASUREMENT_TYPE_FREQUENCY) { // No phase specific + ret = esp_zb_electrical_meas_cluster_add_attr( + electrical_measurement_cluster, ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_AC_FREQUENCY_ID, (void *)&default_ac_measurement + ); + if (ret != ESP_OK) { + log_e("Failed to add DC voltage: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_electrical_meas_cluster_add_attr( + electrical_measurement_cluster, ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_AC_FREQUENCY_MIN_ID, (void *)&default_ac_min + ); + if (ret != ESP_OK) { + log_e("Failed to add DC voltage min: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_electrical_meas_cluster_add_attr( + electrical_measurement_cluster, ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_AC_FREQUENCY_MAX_ID, (void *)&default_ac_max + ); + if (ret != ESP_OK) { + log_e("Failed to add DC voltage max: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_electrical_meas_cluster_add_attr( + electrical_measurement_cluster, ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_AC_FREQUENCY_MULTIPLIER_ID, (void *)&default_ac_multiplier + ); + if (ret != ESP_OK) { + log_e("Failed to add DC voltage multiplier: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_electrical_meas_cluster_add_attr( + electrical_measurement_cluster, ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_AC_FREQUENCY_DIVISOR_ID, (void *)&default_ac_divisor + ); + if (ret != ESP_OK) { + log_e("Failed to add DC voltage divisor: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; + } + // Add the AC Voltage attributes + else if (measurement_type == ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE) { + esp_zb_zcl_electrical_measurement_attr_t attr_voltage = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMSVOLTAGE_ID; + esp_zb_zcl_electrical_measurement_attr_t attr_voltage_min = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMS_VOLTAGE_MIN_ID; + esp_zb_zcl_electrical_measurement_attr_t attr_voltage_max = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMS_VOLTAGE_MAX_ID; + switch (phase_type) { + case ZIGBEE_AC_PHASE_TYPE_A: + // already set + break; + case ZIGBEE_AC_PHASE_TYPE_B: + attr_voltage = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMSVOLTAGE_PHB_ID; + attr_voltage_min = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMS_VOLTAGE_MIN_PH_B_ID; + attr_voltage_max = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMS_VOLTAGE_MAX_PH_B_ID; + break; + case ZIGBEE_AC_PHASE_TYPE_C: + attr_voltage = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMSVOLTAGE_PHC_ID; + attr_voltage_min = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMS_VOLTAGE_MIN_PH_C_ID; + attr_voltage_max = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMS_VOLTAGE_MAX_PH_C_ID; + break; + default: log_e("Invalid phase type"); return false; + } + ret = esp_zb_electrical_meas_cluster_add_attr(electrical_measurement_cluster, attr_voltage, (void *)&default_ac_measurement); + if (ret != ESP_OK) { + log_e("Failed to add AC voltage: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_electrical_meas_cluster_add_attr(electrical_measurement_cluster, attr_voltage_min, (void *)&default_ac_min); + if (ret != ESP_OK) { + log_e("Failed to add AC voltage min: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_electrical_meas_cluster_add_attr(electrical_measurement_cluster, attr_voltage_max, (void *)&default_ac_max); + if (ret != ESP_OK) { + log_e("Failed to add AC voltage max: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + if (!ac_volt_mult_div_set) { + ret = esp_zb_electrical_meas_cluster_add_attr( + electrical_measurement_cluster, ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_ACVOLTAGE_MULTIPLIER_ID, (void *)&default_ac_multiplier + ); + if (ret != ESP_OK) { + log_e("Failed to add AC voltage multiplier: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_electrical_meas_cluster_add_attr( + electrical_measurement_cluster, ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_ACVOLTAGE_DIVISOR_ID, (void *)&default_ac_divisor + ); + if (ret != ESP_OK) { + log_e("Failed to add AC voltage divisor: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ac_volt_mult_div_set = true; // Set flag to true, so we dont add the attributes again + } + } + // Add the AC Current attributes + else if (measurement_type == ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT) { + esp_zb_zcl_electrical_measurement_attr_t attr_current = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMSCURRENT_ID; + esp_zb_zcl_electrical_measurement_attr_t attr_current_min = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMS_CURRENT_MIN_ID; + esp_zb_zcl_electrical_measurement_attr_t attr_current_max = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMS_CURRENT_MAX_ID; + switch (phase_type) { + case ZIGBEE_AC_PHASE_TYPE_A: + // already set + break; + case ZIGBEE_AC_PHASE_TYPE_B: + attr_current = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMSCURRENT_PHB_ID; + attr_current_min = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMS_CURRENT_MIN_PH_B_ID; + attr_current_max = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMS_CURRENT_MAX_PH_B_ID; + break; + case ZIGBEE_AC_PHASE_TYPE_C: + attr_current = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMSCURRENT_PHC_ID; + attr_current_min = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMS_CURRENT_MIN_PH_C_ID; + attr_current_max = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMS_CURRENT_MAX_PH_C_ID; + break; + default: log_e("Invalid phase type"); return false; + } + ret = esp_zb_electrical_meas_cluster_add_attr(electrical_measurement_cluster, attr_current, (void *)&default_ac_measurement); + if (ret != ESP_OK) { + log_e("Failed to add AC current: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_electrical_meas_cluster_add_attr(electrical_measurement_cluster, attr_current_min, (void *)&default_ac_min); + if (ret != ESP_OK) { + log_e("Failed to add AC current min: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_electrical_meas_cluster_add_attr(electrical_measurement_cluster, attr_current_max, (void *)&default_ac_max); + if (ret != ESP_OK) { + log_e("Failed to add AC current max: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + if (!ac_current_mult_div_set) { + ret = esp_zb_electrical_meas_cluster_add_attr( + electrical_measurement_cluster, ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_ACCURRENT_MULTIPLIER_ID, (void *)&default_ac_multiplier + ); + if (ret != ESP_OK) { + log_e("Failed to add AC current multiplier: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_electrical_meas_cluster_add_attr( + electrical_measurement_cluster, ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_ACCURRENT_DIVISOR_ID, (void *)&default_ac_divisor + ); + if (ret != ESP_OK) { + log_e("Failed to add AC current divisor: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ac_current_mult_div_set = true; // Set flag to true, so we dont add the attributes again + } + } + // Add the AC Power attributes + else if (measurement_type == ZIGBEE_AC_MEASUREMENT_TYPE_POWER) { + esp_zb_zcl_electrical_measurement_attr_t attr_power = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_ACTIVE_POWER_ID; + esp_zb_zcl_electrical_measurement_attr_t attr_power_min = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_ACTIVE_POWER_MIN_ID; + esp_zb_zcl_electrical_measurement_attr_t attr_power_max = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_ACTIVE_POWER_MAX_ID; + + switch (phase_type) { + case ZIGBEE_AC_PHASE_TYPE_A: + // already set + break; + case ZIGBEE_AC_PHASE_TYPE_B: + attr_power = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_ACTIVE_POWER_PHB_ID; + attr_power_min = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_ACTIVE_POWER_MIN_PH_B_ID; + attr_power_max = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_ACTIVE_POWER_MAX_PH_B_ID; + break; + case ZIGBEE_AC_PHASE_TYPE_C: + attr_power = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_ACTIVE_POWER_PHC_ID; + attr_power_min = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_ACTIVE_POWER_MIN_PH_C_ID; + attr_power_max = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_ACTIVE_POWER_MAX_PH_C_ID; + break; + default: log_e("Invalid phase type"); return false; + } + ret = esp_zb_electrical_meas_cluster_add_attr(electrical_measurement_cluster, attr_power, (void *)&default_ac_measurement); + if (ret != ESP_OK) { + log_e("Failed to add AC power: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_electrical_meas_cluster_add_attr(electrical_measurement_cluster, attr_power_min, (void *)&default_ac_min); + if (ret != ESP_OK) { + log_e("Failed to add AC power min: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_electrical_meas_cluster_add_attr(electrical_measurement_cluster, attr_power_max, (void *)&default_ac_max); + if (ret != ESP_OK) { + log_e("Failed to add AC power max: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + if (!ac_power_mult_div_set) { + ret = esp_zb_electrical_meas_cluster_add_attr( + electrical_measurement_cluster, ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_ACPOWER_MULTIPLIER_ID, (void *)&default_ac_multiplier + ); + if (ret != ESP_OK) { + log_e("Failed to add AC power multiplier: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_electrical_meas_cluster_add_attr( + electrical_measurement_cluster, ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_ACPOWER_DIVISOR_ID, (void *)&default_ac_divisor + ); + if (ret != ESP_OK) { + log_e("Failed to add AC power divisor: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ac_power_mult_div_set = true; // Set flag to true, so we dont add the attributes again + } + } else { //(measurement_type == ZIGBEE_AC_MEASUREMENT_TYPE_POWER_FACTOR) + esp_zb_zcl_electrical_measurement_attr_t attr_power_factor = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_POWER_FACTOR_ID; + + switch (phase_type) { + case ZIGBEE_AC_PHASE_TYPE_A: + // already set + break; + case ZIGBEE_AC_PHASE_TYPE_B: attr_power_factor = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_POWER_FACTOR_PH_B_ID; break; + case ZIGBEE_AC_PHASE_TYPE_C: attr_power_factor = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_POWER_FACTOR_PH_C_ID; break; + default: log_e("Invalid phase type"); return false; + } + ret = esp_zb_electrical_meas_cluster_add_attr(electrical_measurement_cluster, attr_power_factor, (void *)&default_ac_power_factor); + if (ret != ESP_OK) { + log_e("Failed to add AC power factor: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + } + return true; +} + +bool ZigbeeElectricalMeasurement::setACMinMaxValue( + ZIGBEE_AC_MEASUREMENT_TYPE measurement_type, ZIGBEE_AC_PHASE_TYPE phase_type, int32_t min_value, int32_t max_value +) { + uint16_t attr_min_id = 0; + uint16_t attr_max_id = 0; + + // Check min/max values are valid for the measurement type + switch (measurement_type) { + case ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE: + case ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT: + case ZIGBEE_AC_MEASUREMENT_TYPE_FREQUENCY: + if (min_value < 0 || min_value > UINT16_MAX || max_value < 0 || max_value > UINT16_MAX) { + log_e("AC measurement min/max values must be between 0 and %u (got min=%d, max=%d)", UINT16_MAX, min_value, max_value); + return false; + } + break; + + case ZIGBEE_AC_MEASUREMENT_TYPE_POWER: + if (min_value < INT16_MIN || min_value > INT16_MAX || max_value < INT16_MIN || max_value > INT16_MAX) { + log_e("AC power min/max values must be between %d and %d (got min=%d, max=%d)", INT16_MIN, INT16_MAX, min_value, max_value); + return false; + } + break; + + default: log_e("Invalid measurement type"); return false; + } + + [[maybe_unused]] + int16_t int16_min_value = (int16_t)min_value; + [[maybe_unused]] + int16_t int16_max_value = (int16_t)max_value; + [[maybe_unused]] + uint16_t uint16_min_value = (uint16_t)min_value; + [[maybe_unused]] + uint16_t uint16_max_value = (uint16_t)max_value; + + //TODO: Log info about min and max values for different measurement types + switch (measurement_type) { + case ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE: + switch (phase_type) { + case ZIGBEE_AC_PHASE_TYPE_A: + attr_min_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMS_VOLTAGE_MIN_ID; + attr_max_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMS_VOLTAGE_MAX_ID; + break; + case ZIGBEE_AC_PHASE_TYPE_B: + attr_min_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMS_VOLTAGE_MIN_PH_B_ID; + attr_max_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMS_VOLTAGE_MAX_PH_B_ID; + break; + case ZIGBEE_AC_PHASE_TYPE_C: + attr_min_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMS_VOLTAGE_MIN_PH_C_ID; + attr_max_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMS_VOLTAGE_MAX_PH_C_ID; + break; + default: log_e("Invalid phase type"); return false; + } + break; + + case ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT: + switch (phase_type) { + case ZIGBEE_AC_PHASE_TYPE_A: + attr_min_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMS_CURRENT_MIN_ID; + attr_max_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMS_CURRENT_MAX_ID; + break; + case ZIGBEE_AC_PHASE_TYPE_B: + attr_min_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMS_CURRENT_MIN_PH_B_ID; + attr_max_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMS_CURRENT_MAX_PH_B_ID; + break; + case ZIGBEE_AC_PHASE_TYPE_C: + attr_min_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMS_CURRENT_MIN_PH_C_ID; + attr_max_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMS_CURRENT_MAX_PH_C_ID; + break; + default: log_e("Invalid phase type"); return false; + } + break; + + case ZIGBEE_AC_MEASUREMENT_TYPE_POWER: + switch (phase_type) { + case ZIGBEE_AC_PHASE_TYPE_A: + attr_min_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_ACTIVE_POWER_MIN_ID; + attr_max_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_ACTIVE_POWER_MAX_ID; + break; + case ZIGBEE_AC_PHASE_TYPE_B: + attr_min_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_ACTIVE_POWER_MIN_PH_B_ID; + attr_max_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_ACTIVE_POWER_MAX_PH_B_ID; + break; + case ZIGBEE_AC_PHASE_TYPE_C: + attr_min_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_ACTIVE_POWER_MIN_PH_C_ID; + attr_max_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_ACTIVE_POWER_MAX_PH_C_ID; + break; + default: log_e("Invalid phase type"); return false; + } + break; + + default: log_e("Invalid measurement type"); return false; + } + esp_zb_attribute_list_t *electrical_measurement_cluster = + esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_ELECTRICAL_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + + esp_err_t ret = ESP_OK; + ret = esp_zb_cluster_update_attr(electrical_measurement_cluster, attr_min_id, (void *)&min_value); + if (ret != ESP_OK) { + log_e("Failed to set min value: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_cluster_update_attr(electrical_measurement_cluster, attr_max_id, (void *)&max_value); + if (ret != ESP_OK) { + log_e("Failed to set max value: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; +} + +bool ZigbeeElectricalMeasurement::setACMultiplierDivisor(ZIGBEE_AC_MEASUREMENT_TYPE measurement_type, uint16_t multiplier, uint16_t divisor) { + uint16_t attr_multiplier = 0; + uint16_t attr_divisor = 0; + + switch (measurement_type) { + case ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE: + attr_multiplier = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_ACVOLTAGE_MULTIPLIER_ID; + attr_divisor = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_ACVOLTAGE_DIVISOR_ID; + break; + case ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT: + attr_multiplier = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_ACCURRENT_MULTIPLIER_ID; + attr_divisor = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_ACCURRENT_DIVISOR_ID; + break; + case ZIGBEE_AC_MEASUREMENT_TYPE_POWER: + attr_multiplier = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_ACPOWER_MULTIPLIER_ID; + attr_divisor = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_ACPOWER_DIVISOR_ID; + break; + case ZIGBEE_AC_MEASUREMENT_TYPE_FREQUENCY: + attr_multiplier = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_AC_FREQUENCY_MULTIPLIER_ID; + attr_divisor = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_AC_FREQUENCY_DIVISOR_ID; + break; + default: log_e("Invalid measurement type"); return false; + } + esp_zb_attribute_list_t *electrical_measurement_cluster = + esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_ELECTRICAL_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + + esp_err_t ret = ESP_OK; + ret = esp_zb_cluster_update_attr(electrical_measurement_cluster, attr_multiplier, (void *)&multiplier); + if (ret != ESP_OK) { + log_e("Failed to set multiplier: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_cluster_update_attr(electrical_measurement_cluster, attr_divisor, (void *)&divisor); + if (ret != ESP_OK) { + log_e("Failed to set divisor: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; +} + +bool ZigbeeElectricalMeasurement::setACPowerFactor(ZIGBEE_AC_PHASE_TYPE phase_type, int8_t power_factor) { + uint16_t attr_id = 0; + + switch (phase_type) { + case ZIGBEE_AC_PHASE_TYPE_A: attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_POWER_FACTOR_ID; break; + case ZIGBEE_AC_PHASE_TYPE_B: attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_POWER_FACTOR_PH_B_ID; break; + case ZIGBEE_AC_PHASE_TYPE_C: attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_POWER_FACTOR_PH_C_ID; break; + case ZIGBEE_AC_PHASE_TYPE_NON_SPECIFIC: + default: log_e("Invalid phase type"); return false; + } + + esp_zb_attribute_list_t *electrical_measurement_cluster = + esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_ELECTRICAL_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + + esp_err_t ret = ESP_OK; + ret = esp_zb_cluster_update_attr(electrical_measurement_cluster, attr_id, (void *)&power_factor); + if (ret != ESP_OK) { + log_e("Failed to set power factor: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; +} +bool ZigbeeElectricalMeasurement::setACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE measurement_type, ZIGBEE_AC_PHASE_TYPE phase_type, int32_t value) { + esp_zb_zcl_status_t ret = ESP_ZB_ZCL_STATUS_SUCCESS; + uint16_t attr_id = 0; + + // Check value is valid for the measurement type + switch (measurement_type) { + case ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE: + case ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT: + case ZIGBEE_AC_MEASUREMENT_TYPE_FREQUENCY: + if (value < 0 || value > UINT16_MAX) { + log_e("AC measurement value must be between 0 and %u (got %d)", UINT16_MAX, value); + return false; + } + break; + + case ZIGBEE_AC_MEASUREMENT_TYPE_POWER: + if (value < INT16_MIN || value > INT16_MAX) { + log_e("AC power value must be between %d and %d (got %d)", INT16_MIN, INT16_MAX, value); + return false; + } + break; + + case ZIGBEE_AC_MEASUREMENT_TYPE_POWER_FACTOR: + if (value < -100 || value > 100) { + log_e("AC power factor value must be between -100 and 100 (got %d)", value); + return false; + } + break; + + default: log_e("Invalid measurement type"); return false; + } + // Convert value to appropriate type based on measurement type + uint16_t uint16_value = (uint16_t)value; + int16_t int16_value = (int16_t)value; + int8_t int8_value = (int8_t)value; + + switch (measurement_type) { + case ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE: + switch (phase_type) { + case ZIGBEE_AC_PHASE_TYPE_A: attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMSVOLTAGE_ID; break; + case ZIGBEE_AC_PHASE_TYPE_B: attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMSVOLTAGE_PHB_ID; break; + case ZIGBEE_AC_PHASE_TYPE_C: attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMSVOLTAGE_PHC_ID; break; + case ZIGBEE_AC_PHASE_TYPE_NON_SPECIFIC: + default: log_e("Invalid phase type"); return false; + } + // Use uint16_t for voltage + log_v("Updating AC voltage measurement value..."); + log_d("Setting AC voltage to %u", uint16_value); + esp_zb_lock_acquire(portMAX_DELAY); + ret = + esp_zb_zcl_set_attribute_val(_endpoint, ESP_ZB_ZCL_CLUSTER_ID_ELECTRICAL_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, attr_id, &uint16_value, false); + esp_zb_lock_release(); + break; + + case ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT: + switch (phase_type) { + case ZIGBEE_AC_PHASE_TYPE_A: attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMSCURRENT_ID; break; + case ZIGBEE_AC_PHASE_TYPE_B: attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMSCURRENT_PHB_ID; break; + case ZIGBEE_AC_PHASE_TYPE_C: attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMSCURRENT_PHC_ID; break; + case ZIGBEE_AC_PHASE_TYPE_NON_SPECIFIC: + default: log_e("Invalid phase type"); return false; + } + // Use uint16_t for current + log_v("Updating AC current measurement value..."); + log_d("Setting AC current to %u", uint16_value); + esp_zb_lock_acquire(portMAX_DELAY); + ret = + esp_zb_zcl_set_attribute_val(_endpoint, ESP_ZB_ZCL_CLUSTER_ID_ELECTRICAL_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, attr_id, &uint16_value, false); + esp_zb_lock_release(); + break; + + case ZIGBEE_AC_MEASUREMENT_TYPE_POWER: + switch (phase_type) { + case ZIGBEE_AC_PHASE_TYPE_A: attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_ACTIVE_POWER_ID; break; + case ZIGBEE_AC_PHASE_TYPE_B: attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_ACTIVE_POWER_PHB_ID; break; + case ZIGBEE_AC_PHASE_TYPE_C: attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_ACTIVE_POWER_PHC_ID; break; + case ZIGBEE_AC_PHASE_TYPE_NON_SPECIFIC: + default: log_e("Invalid phase type"); return false; + } + // Use int16_t for power + log_v("Updating AC power measurement value..."); + log_d("Setting AC power to %d", int16_value); + esp_zb_lock_acquire(portMAX_DELAY); + ret = esp_zb_zcl_set_attribute_val(_endpoint, ESP_ZB_ZCL_CLUSTER_ID_ELECTRICAL_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, attr_id, &int16_value, false); + esp_zb_lock_release(); + break; + + case ZIGBEE_AC_MEASUREMENT_TYPE_FREQUENCY: + attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_AC_FREQUENCY_ID; + // Use uint16_t for frequency + log_v("Updating AC frequency measurement value..."); + log_d("Setting AC frequency to %u", uint16_value); + esp_zb_lock_acquire(portMAX_DELAY); + ret = + esp_zb_zcl_set_attribute_val(_endpoint, ESP_ZB_ZCL_CLUSTER_ID_ELECTRICAL_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, attr_id, &uint16_value, false); + esp_zb_lock_release(); + break; + case ZIGBEE_AC_MEASUREMENT_TYPE_POWER_FACTOR: + switch (phase_type) { + case ZIGBEE_AC_PHASE_TYPE_A: attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_POWER_FACTOR_ID; break; + case ZIGBEE_AC_PHASE_TYPE_B: attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_POWER_FACTOR_PH_B_ID; break; + case ZIGBEE_AC_PHASE_TYPE_C: attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_POWER_FACTOR_PH_C_ID; break; + case ZIGBEE_AC_PHASE_TYPE_NON_SPECIFIC: + default: log_e("Invalid phase type"); return false; + } + // Use int8_t for power factor + log_v("Updating AC power factor measurement value..."); + log_d("Setting AC power factor to %d", int8_value); + esp_zb_lock_acquire(portMAX_DELAY); + ret = esp_zb_zcl_set_attribute_val(_endpoint, ESP_ZB_ZCL_CLUSTER_ID_ELECTRICAL_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, attr_id, &int8_value, false); + esp_zb_lock_release(); + break; + default: log_e("Invalid measurement type"); return false; + } + + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set AC measurement: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + return false; + } + return true; +} + +bool ZigbeeElectricalMeasurement::setACReporting( + ZIGBEE_AC_MEASUREMENT_TYPE measurement_type, ZIGBEE_AC_PHASE_TYPE phase_type, uint16_t min_interval, uint16_t max_interval, int32_t delta +) { + uint16_t attr_id = 0; + + // Convert value to appropriate type based on measurement type + uint16_t uint16_delta = (uint16_t)delta; + int16_t int16_delta = (int16_t)delta; + + switch (measurement_type) { + case ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE: + switch (phase_type) { + case ZIGBEE_AC_PHASE_TYPE_A: attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMSVOLTAGE_ID; break; + case ZIGBEE_AC_PHASE_TYPE_B: attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMSVOLTAGE_PHB_ID; break; + case ZIGBEE_AC_PHASE_TYPE_C: attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMSVOLTAGE_PHC_ID; break; + case ZIGBEE_AC_PHASE_TYPE_NON_SPECIFIC: + default: log_e("Invalid phase type"); return false; + } + break; + case ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT: + switch (phase_type) { + case ZIGBEE_AC_PHASE_TYPE_A: attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMSCURRENT_ID; break; + case ZIGBEE_AC_PHASE_TYPE_B: attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMSCURRENT_PHB_ID; break; + case ZIGBEE_AC_PHASE_TYPE_C: attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMSCURRENT_PHC_ID; break; + case ZIGBEE_AC_PHASE_TYPE_NON_SPECIFIC: + default: log_e("Invalid phase type"); return false; + } + break; + case ZIGBEE_AC_MEASUREMENT_TYPE_POWER: + switch (phase_type) { + case ZIGBEE_AC_PHASE_TYPE_A: attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_ACTIVE_POWER_ID; break; + case ZIGBEE_AC_PHASE_TYPE_B: attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_ACTIVE_POWER_PHB_ID; break; + case ZIGBEE_AC_PHASE_TYPE_C: attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_ACTIVE_POWER_PHC_ID; break; + case ZIGBEE_AC_PHASE_TYPE_NON_SPECIFIC: + default: log_e("Invalid phase type"); return false; + } + break; + case ZIGBEE_AC_MEASUREMENT_TYPE_FREQUENCY: attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_AC_FREQUENCY_ID; break; + case ZIGBEE_AC_MEASUREMENT_TYPE_POWER_FACTOR: log_e("Power factor attribute reporting not supported by zigbee specification"); return false; + default: log_e("Invalid measurement type"); return false; + } + + esp_zb_zcl_reporting_info_t reporting_info; + memset(&reporting_info, 0, sizeof(esp_zb_zcl_reporting_info_t)); + reporting_info.direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_SRV; + reporting_info.ep = _endpoint; + reporting_info.cluster_id = ESP_ZB_ZCL_CLUSTER_ID_ELECTRICAL_MEASUREMENT; + reporting_info.cluster_role = ESP_ZB_ZCL_CLUSTER_SERVER_ROLE; + reporting_info.attr_id = attr_id; + reporting_info.u.send_info.min_interval = min_interval; + reporting_info.u.send_info.max_interval = max_interval; + reporting_info.u.send_info.def_min_interval = min_interval; + reporting_info.u.send_info.def_max_interval = max_interval; + if (measurement_type == ZIGBEE_AC_MEASUREMENT_TYPE_POWER) { + reporting_info.u.send_info.delta.s16 = int16_delta; + } else { + reporting_info.u.send_info.delta.u16 = uint16_delta; + } + reporting_info.dst.profile_id = ESP_ZB_AF_HA_PROFILE_ID; + reporting_info.manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC; + esp_zb_lock_acquire(portMAX_DELAY); + esp_err_t ret = esp_zb_zcl_update_reporting_info(&reporting_info); + esp_zb_lock_release(); + if (ret != ESP_OK) { + log_e("Failed to set reporting: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; +} + +bool ZigbeeElectricalMeasurement::reportAC(ZIGBEE_AC_MEASUREMENT_TYPE measurement_type, ZIGBEE_AC_PHASE_TYPE phase_type) { + uint16_t attr_id = 0; + + switch (measurement_type) { + case ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE: + switch (phase_type) { + case ZIGBEE_AC_PHASE_TYPE_A: attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMSVOLTAGE_ID; break; + case ZIGBEE_AC_PHASE_TYPE_B: attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMSVOLTAGE_PHB_ID; break; + case ZIGBEE_AC_PHASE_TYPE_C: attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMSVOLTAGE_PHC_ID; break; + case ZIGBEE_AC_PHASE_TYPE_NON_SPECIFIC: + default: log_e("Invalid phase type"); return false; + } + break; + case ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT: + switch (phase_type) { + case ZIGBEE_AC_PHASE_TYPE_A: attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMSCURRENT_ID; break; + case ZIGBEE_AC_PHASE_TYPE_B: attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMSCURRENT_PHB_ID; break; + case ZIGBEE_AC_PHASE_TYPE_C: attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_RMSCURRENT_PHC_ID; break; + case ZIGBEE_AC_PHASE_TYPE_NON_SPECIFIC: + default: log_e("Invalid phase type"); return false; + } + break; + case ZIGBEE_AC_MEASUREMENT_TYPE_POWER: + switch (phase_type) { + case ZIGBEE_AC_PHASE_TYPE_A: attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_ACTIVE_POWER_ID; break; + case ZIGBEE_AC_PHASE_TYPE_B: attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_ACTIVE_POWER_PHB_ID; break; + case ZIGBEE_AC_PHASE_TYPE_C: attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_ACTIVE_POWER_PHC_ID; break; + case ZIGBEE_AC_PHASE_TYPE_NON_SPECIFIC: + default: log_e("Invalid phase type"); return false; + } + break; + case ZIGBEE_AC_MEASUREMENT_TYPE_FREQUENCY: attr_id = ESP_ZB_ZCL_ATTR_ELECTRICAL_MEASUREMENT_AC_FREQUENCY_ID; break; + case ZIGBEE_AC_MEASUREMENT_TYPE_POWER_FACTOR: log_e("Power factor attribute reporting not supported by zigbee specification"); return false; + default: log_e("Invalid measurement type"); return false; + } + /* Send report attributes command */ + esp_zb_zcl_report_attr_cmd_t report_attr_cmd; + report_attr_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; + report_attr_cmd.attributeID = attr_id; + report_attr_cmd.direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_CLI; + report_attr_cmd.clusterID = ESP_ZB_ZCL_CLUSTER_ID_ELECTRICAL_MEASUREMENT; + report_attr_cmd.zcl_basic_cmd.src_endpoint = _endpoint; + report_attr_cmd.manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC; + + esp_zb_lock_acquire(portMAX_DELAY); + esp_err_t ret = esp_zb_zcl_report_attr_cmd_req(&report_attr_cmd); + esp_zb_lock_release(); + if (ret != ESP_OK) { + log_e("Failed to send AC report: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + log_v("AC report sent"); + return true; +} + +#endif // CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeElectricalMeasurement.h b/libraries/Zigbee/src/ep/ZigbeeElectricalMeasurement.h new file mode 100644 index 00000000000..74d4a718fe2 --- /dev/null +++ b/libraries/Zigbee/src/ep/ZigbeeElectricalMeasurement.h @@ -0,0 +1,105 @@ +/* Class of Zigbee Pressure sensor endpoint inherited from common EP class */ + +#pragma once + +#include "soc/soc_caps.h" +#include "sdkconfig.h" +#if CONFIG_ZB_ENABLED + +#include "ZigbeeEP.h" +#include "ha/esp_zigbee_ha_standard.h" + +// clang-format off +#define ZIGBEE_DEFAULT_ELECTRICAL_MEASUREMENT_CONFIG() \ + { \ + .basic_cfg = \ + { \ + .zcl_version = ESP_ZB_ZCL_BASIC_ZCL_VERSION_DEFAULT_VALUE, \ + .power_source = ESP_ZB_ZCL_BASIC_POWER_SOURCE_DEFAULT_VALUE, \ + }, \ + .identify_cfg = \ + { \ + .identify_time = ESP_ZB_ZCL_IDENTIFY_IDENTIFY_TIME_DEFAULT_VALUE, \ + }, \ + .electrical_measurement_cfg = \ + { \ + .measured_type = 0x00, \ + }, \ + } +// clang-format on + +enum ZIGBEE_DC_MEASUREMENT_TYPE { + ZIGBEE_DC_MEASUREMENT_TYPE_VOLTAGE = 0x0001, + ZIGBEE_DC_MEASUREMENT_TYPE_CURRENT = 0x0002, + ZIGBEE_DC_MEASUREMENT_TYPE_POWER = 0x0003, +}; + +enum ZIGBEE_AC_MEASUREMENT_TYPE { + ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE = 0x0001, + ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT = 0x0002, + ZIGBEE_AC_MEASUREMENT_TYPE_POWER = 0x0003, + ZIGBEE_AC_MEASUREMENT_TYPE_POWER_FACTOR = 0x0004, + ZIGBEE_AC_MEASUREMENT_TYPE_FREQUENCY = 0x0005, +}; + +enum ZIGBEE_AC_PHASE_TYPE { + ZIGBEE_AC_PHASE_TYPE_NON_SPECIFIC = 0x0000, + ZIGBEE_AC_PHASE_TYPE_A = 0x0001, + ZIGBEE_AC_PHASE_TYPE_B = 0x0002, + ZIGBEE_AC_PHASE_TYPE_C = 0x0003, +}; + +typedef struct zigbee_electrical_measurement_cfg_s { + esp_zb_basic_cluster_cfg_t basic_cfg; + esp_zb_identify_cluster_cfg_t identify_cfg; + esp_zb_electrical_meas_cluster_cfg_t electrical_measurement_cfg; +} zigbee_electrical_measurement_cfg_t; + +class ZigbeeElectricalMeasurement : public ZigbeeEP { +public: + ZigbeeElectricalMeasurement(uint8_t endpoint); + ~ZigbeeElectricalMeasurement() {} + + /** + * @brief DC measurement methods + */ + // Add a DC measurement type + bool addDCMeasurement(ZIGBEE_DC_MEASUREMENT_TYPE measurement_type); + // Set the DC measurement value for the given measurement type + bool setDCMeasurement(ZIGBEE_DC_MEASUREMENT_TYPE measurement_type, int16_t value); + // Set the DC min and max value for the given measurement type + bool setDCMinMaxValue(ZIGBEE_DC_MEASUREMENT_TYPE measurement_type, int16_t min, int16_t max); + // Set the DC multiplier and divisor for the given measurement type + bool setDCMultiplierDivisor(ZIGBEE_DC_MEASUREMENT_TYPE measurement_type, uint16_t multiplier, uint16_t divisor); + // Set the DC reporting interval for the given measurement type in seconds and delta (measurement change) + bool setDCReporting(ZIGBEE_DC_MEASUREMENT_TYPE measurement_type, uint16_t min_interval, uint16_t max_interval, int16_t delta); + // Report the DC measurement value for the given measurement type + bool reportDC(ZIGBEE_DC_MEASUREMENT_TYPE measurement_type); + + /** + * @brief AC measurement methods + */ + // Add an AC measurement type for selected phase type + bool addACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE measurement_type, ZIGBEE_AC_PHASE_TYPE phase_type); + // Set the AC measurement value for the given measurement type and phase type (uint16_t for voltage, current and frequency, int32_t for power) + bool setACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE measurement_type, ZIGBEE_AC_PHASE_TYPE phase_type, int32_t value); + // Set the AC min and max value for the given measurement type and phase type (uint16_t for voltage, current and frequency, int32_t for power) + bool setACMinMaxValue(ZIGBEE_AC_MEASUREMENT_TYPE measurement_type, ZIGBEE_AC_PHASE_TYPE phase_type, int32_t min, int32_t max); + // Set the AC multiplier and divisor for the given measurement type (common for all phases) + bool setACMultiplierDivisor(ZIGBEE_AC_MEASUREMENT_TYPE measurement_type, uint16_t multiplier, uint16_t divisor); + // Set the AC power factor for the given phase type (-100 to 100 %) + bool setACPowerFactor(ZIGBEE_AC_PHASE_TYPE phase_type, int8_t power_factor); + // Set the AC reporting interval for the given measurement type and phase type in seconds and delta (measurement change - uint16_t for voltage, current and frequency, int32_t for power) + bool + setACReporting(ZIGBEE_AC_MEASUREMENT_TYPE measurement_type, ZIGBEE_AC_PHASE_TYPE phase_type, uint16_t min_interval, uint16_t max_interval, int32_t delta); + // Report the AC measurement value for the given measurement type and phase type + bool reportAC(ZIGBEE_AC_MEASUREMENT_TYPE measurement_type, ZIGBEE_AC_PHASE_TYPE phase_type); + +private: + uint32_t measure_type = 0x0000; + bool ac_volt_mult_div_set = false; + bool ac_current_mult_div_set = false; + bool ac_power_mult_div_set = false; +}; + +#endif // CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeFlowSensor.cpp b/libraries/Zigbee/src/ep/ZigbeeFlowSensor.cpp index 11fbf7c906b..8a60af5a8e1 100644 --- a/libraries/Zigbee/src/ep/ZigbeeFlowSensor.cpp +++ b/libraries/Zigbee/src/ep/ZigbeeFlowSensor.cpp @@ -22,24 +22,37 @@ ZigbeeFlowSensor::ZigbeeFlowSensor(uint8_t endpoint) : ZigbeeEP(endpoint) { _ep_config = {.endpoint = _endpoint, .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, .app_device_id = ESP_ZB_HA_SIMPLE_SENSOR_DEVICE_ID, .app_device_version = 0}; } -void ZigbeeFlowSensor::setMinMaxValue(float min, float max) { +bool ZigbeeFlowSensor::setMinMaxValue(float min, float max) { uint16_t zb_min = (uint16_t)(min * 10); uint16_t zb_max = (uint16_t)(max * 10); esp_zb_attribute_list_t *flow_measure_cluster = esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_FLOW_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); - esp_zb_cluster_update_attr(flow_measure_cluster, ESP_ZB_ZCL_ATTR_FLOW_MEASUREMENT_MIN_VALUE_ID, (void *)&zb_min); - esp_zb_cluster_update_attr(flow_measure_cluster, ESP_ZB_ZCL_ATTR_FLOW_MEASUREMENT_MAX_VALUE_ID, (void *)&zb_max); + esp_err_t ret = esp_zb_cluster_update_attr(flow_measure_cluster, ESP_ZB_ZCL_ATTR_FLOW_MEASUREMENT_MIN_VALUE_ID, (void *)&zb_min); + if (ret != ESP_OK) { + log_e("Failed to set min value: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_cluster_update_attr(flow_measure_cluster, ESP_ZB_ZCL_ATTR_FLOW_MEASUREMENT_MAX_VALUE_ID, (void *)&zb_max); + if (ret != ESP_OK) { + log_e("Failed to set max value: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; } -void ZigbeeFlowSensor::setTolerance(float tolerance) { - // Convert tolerance to ZCL uint16_t +bool ZigbeeFlowSensor::setTolerance(float tolerance) { uint16_t zb_tolerance = (uint16_t)(tolerance * 10); esp_zb_attribute_list_t *flow_measure_cluster = esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_FLOW_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); - esp_zb_flow_meas_cluster_add_attr(flow_measure_cluster, ESP_ZB_ZCL_ATTR_FLOW_MEASUREMENT_TOLERANCE_ID, (void *)&zb_tolerance); + esp_err_t ret = esp_zb_flow_meas_cluster_add_attr(flow_measure_cluster, ESP_ZB_ZCL_ATTR_FLOW_MEASUREMENT_TOLERANCE_ID, (void *)&zb_tolerance); + if (ret != ESP_OK) { + log_e("Failed to set tolerance: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; } -void ZigbeeFlowSensor::setReporting(uint16_t min_interval, uint16_t max_interval, float delta) { +bool ZigbeeFlowSensor::setReporting(uint16_t min_interval, uint16_t max_interval, float delta) { esp_zb_zcl_reporting_info_t reporting_info; memset(&reporting_info, 0, sizeof(esp_zb_zcl_reporting_info_t)); reporting_info.direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_SRV; @@ -54,24 +67,39 @@ void ZigbeeFlowSensor::setReporting(uint16_t min_interval, uint16_t max_interval reporting_info.u.send_info.delta.u16 = (uint16_t)(delta * 10); // Convert delta to ZCL uint16_t reporting_info.dst.profile_id = ESP_ZB_AF_HA_PROFILE_ID; reporting_info.manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC; + esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_update_reporting_info(&reporting_info); + esp_err_t ret = esp_zb_zcl_update_reporting_info(&reporting_info); esp_zb_lock_release(); + + if (ret != ESP_OK) { + log_e("Failed to set reporting: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; } -void ZigbeeFlowSensor::setFlow(float flow) { +bool ZigbeeFlowSensor::setFlow(float flow) { + esp_zb_zcl_status_t ret = ESP_ZB_ZCL_STATUS_SUCCESS; uint16_t zb_flow = (uint16_t)(flow * 10); log_v("Updating flow sensor value..."); /* Update temperature sensor measured value */ log_d("Setting flow to %d", zb_flow); + esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_set_attribute_val( + ret = esp_zb_zcl_set_attribute_val( _endpoint, ESP_ZB_ZCL_CLUSTER_ID_FLOW_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_FLOW_MEASUREMENT_VALUE_ID, &zb_flow, false ); esp_zb_lock_release(); + + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set flow value: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + return false; + } + return true; } -void ZigbeeFlowSensor::report() { +bool ZigbeeFlowSensor::report() { /* Send report attributes command */ esp_zb_zcl_report_attr_cmd_t report_attr_cmd; report_attr_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; @@ -82,9 +110,15 @@ void ZigbeeFlowSensor::report() { report_attr_cmd.manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC; esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_report_attr_cmd_req(&report_attr_cmd); + esp_err_t ret = esp_zb_zcl_report_attr_cmd_req(&report_attr_cmd); esp_zb_lock_release(); + + if (ret != ESP_OK) { + log_e("Failed to send flow report: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } log_v("Flow report sent"); + return true; } #endif // CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeFlowSensor.h b/libraries/Zigbee/src/ep/ZigbeeFlowSensor.h index 5e9e20e4d1a..fa16b4a5636 100644 --- a/libraries/Zigbee/src/ep/ZigbeeFlowSensor.h +++ b/libraries/Zigbee/src/ep/ZigbeeFlowSensor.h @@ -42,19 +42,19 @@ class ZigbeeFlowSensor : public ZigbeeEP { ~ZigbeeFlowSensor() {} // Set the flow value in 0,1 m3/h - void setFlow(float value); + bool setFlow(float value); // Set the min and max value for the flow sensor in 0,1 m3/h - void setMinMaxValue(float min, float max); + bool setMinMaxValue(float min, float max); // Set the tolerance value for the flow sensor in 0,01 m3/h - void setTolerance(float tolerance); + bool setTolerance(float tolerance); // Set the reporting interval for flow measurement in seconds and delta (temp change in 0,1 m3/h) - void setReporting(uint16_t min_interval, uint16_t max_interval, float delta); + bool setReporting(uint16_t min_interval, uint16_t max_interval, float delta); // Report the flow value - void report(); + bool report(); }; #endif // CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeIlluminanceSensor.cpp b/libraries/Zigbee/src/ep/ZigbeeIlluminanceSensor.cpp new file mode 100644 index 00000000000..f1661c3a026 --- /dev/null +++ b/libraries/Zigbee/src/ep/ZigbeeIlluminanceSensor.cpp @@ -0,0 +1,106 @@ +#include "ZigbeeIlluminanceSensor.h" +#if CONFIG_ZB_ENABLED + +ZigbeeIlluminanceSensor::ZigbeeIlluminanceSensor(uint8_t endpoint) : ZigbeeEP(endpoint) { + _device_id = ESP_ZB_HA_LIGHT_SENSOR_DEVICE_ID; + + esp_zb_light_sensor_cfg_t light_sensor_cfg = ZIGBEE_DEFAULT_ILLUMINANCE_SENSOR_CONFIG(); + _cluster_list = esp_zb_light_sensor_clusters_create(&light_sensor_cfg); + + _ep_config = {.endpoint = _endpoint, .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, .app_device_id = ESP_ZB_HA_LIGHT_SENSOR_DEVICE_ID, .app_device_version = 0}; +} + +bool ZigbeeIlluminanceSensor::setMinMaxValue(uint16_t min, uint16_t max) { + esp_zb_attribute_list_t *light_measure_cluster = + esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_ILLUMINANCE_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_err_t ret = esp_zb_cluster_update_attr(light_measure_cluster, ESP_ZB_ZCL_ATTR_ILLUMINANCE_MEASUREMENT_MIN_MEASURED_VALUE_ID, (void *)&min); + if (ret != ESP_OK) { + log_e("Failed to set min value: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_cluster_update_attr(light_measure_cluster, ESP_ZB_ZCL_ATTR_ILLUMINANCE_MEASUREMENT_MAX_MEASURED_VALUE_ID, (void *)&max); + if (ret != ESP_OK) { + log_e("Failed to set max value: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; +} + +bool ZigbeeIlluminanceSensor::setTolerance(uint16_t tolerance) { + esp_zb_attribute_list_t *light_measure_cluster = + esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_ILLUMINANCE_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_err_t ret = esp_zb_illuminance_meas_cluster_add_attr(light_measure_cluster, ESP_ZB_ZCL_ATTR_ILLUMINANCE_MEASUREMENT_TOLERANCE_ID, (void *)&tolerance); + if (ret != ESP_OK) { + log_e("Failed to set tolerance: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; +} + +bool ZigbeeIlluminanceSensor::setReporting(uint16_t min_interval, uint16_t max_interval, uint16_t delta) { + esp_zb_zcl_reporting_info_t reporting_info; + memset(&reporting_info, 0, sizeof(esp_zb_zcl_reporting_info_t)); + reporting_info.direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_SRV; + reporting_info.ep = _endpoint; + reporting_info.cluster_id = ESP_ZB_ZCL_CLUSTER_ID_ILLUMINANCE_MEASUREMENT; + reporting_info.cluster_role = ESP_ZB_ZCL_CLUSTER_SERVER_ROLE; + reporting_info.attr_id = ESP_ZB_ZCL_ATTR_ILLUMINANCE_MEASUREMENT_MEASURED_VALUE_ID; + reporting_info.u.send_info.min_interval = min_interval; + reporting_info.u.send_info.max_interval = max_interval; + reporting_info.u.send_info.def_min_interval = min_interval; + reporting_info.u.send_info.def_max_interval = max_interval; + reporting_info.u.send_info.delta.u16 = delta; + reporting_info.dst.profile_id = ESP_ZB_AF_HA_PROFILE_ID; + reporting_info.manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC; + + esp_zb_lock_acquire(portMAX_DELAY); + esp_err_t ret = esp_zb_zcl_update_reporting_info(&reporting_info); + esp_zb_lock_release(); + + if (ret != ESP_OK) { + log_e("Failed to set reporting: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; +} + +bool ZigbeeIlluminanceSensor::setIlluminance(uint16_t illuminanceValue) { + esp_zb_zcl_status_t ret = ESP_ZB_ZCL_STATUS_SUCCESS; + log_v("Updating Illuminance..."); + /* Update illuminance sensor measured illuminance */ + log_d("Setting Illuminance to %d", illuminanceValue); + esp_zb_lock_acquire(portMAX_DELAY); + ret = esp_zb_zcl_set_attribute_val( + _endpoint, ESP_ZB_ZCL_CLUSTER_ID_ILLUMINANCE_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_ILLUMINANCE_MEASUREMENT_MEASURED_VALUE_ID, + &illuminanceValue, false + ); + esp_zb_lock_release(); + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set illuminance: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + return false; + } + return true; +} + +bool ZigbeeIlluminanceSensor::report() { + /* Send report attributes command */ + esp_zb_zcl_report_attr_cmd_t report_attr_cmd; + report_attr_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; + report_attr_cmd.attributeID = ESP_ZB_ZCL_ATTR_ILLUMINANCE_MEASUREMENT_MEASURED_VALUE_ID; + report_attr_cmd.direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_CLI; + report_attr_cmd.clusterID = ESP_ZB_ZCL_CLUSTER_ID_ILLUMINANCE_MEASUREMENT; + report_attr_cmd.zcl_basic_cmd.src_endpoint = _endpoint; + report_attr_cmd.manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC; + + esp_zb_lock_acquire(portMAX_DELAY); + esp_err_t ret = esp_zb_zcl_report_attr_cmd_req(&report_attr_cmd); + esp_zb_lock_release(); + if (ret != ESP_OK) { + log_e("Failed to send illuminance report: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + log_v("Illuminance report sent"); + return true; +} + +#endif // CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeIlluminanceSensor.h b/libraries/Zigbee/src/ep/ZigbeeIlluminanceSensor.h new file mode 100644 index 00000000000..133dfc315db --- /dev/null +++ b/libraries/Zigbee/src/ep/ZigbeeIlluminanceSensor.h @@ -0,0 +1,51 @@ +/* Class of Zigbee Illuminance sensor endpoint inherited from common EP class */ + +#pragma once + +#include "soc/soc_caps.h" +#include "sdkconfig.h" +#if CONFIG_ZB_ENABLED + +#include "ZigbeeEP.h" +#include "ha/esp_zigbee_ha_standard.h" + +#define ZIGBEE_DEFAULT_ILLUMINANCE_SENSOR_CONFIG() \ + { \ + .basic_cfg = \ + { \ + .zcl_version = ESP_ZB_ZCL_BASIC_ZCL_VERSION_DEFAULT_VALUE, \ + .power_source = ESP_ZB_ZCL_BASIC_POWER_SOURCE_DEFAULT_VALUE, \ + }, \ + .identify_cfg = \ + { \ + .identify_time = ESP_ZB_ZCL_IDENTIFY_IDENTIFY_TIME_DEFAULT_VALUE, \ + }, \ + .illuminance_cfg = { \ + .measured_value = ESP_ZB_ZCL_ILLUMINANCE_MEASUREMENT_LIGHT_SENSOR_TYPE_DEFAULT_VALUE, \ + .min_value = ESP_ZB_ZCL_ATTR_ILLUMINANCE_MEASUREMENT_MIN_MEASURED_VALUE_MIN_VALUE, \ + .max_value = ESP_ZB_ZCL_ATTR_ILLUMINANCE_MEASUREMENT_MAX_MEASURED_VALUE_MAX_VALUE, \ + }, \ + } + +class ZigbeeIlluminanceSensor : public ZigbeeEP { +public: + ZigbeeIlluminanceSensor(uint8_t endpoint); + ~ZigbeeIlluminanceSensor() {} + + // Set the illuminance value + bool setIlluminance(uint16_t value); + + // Set the min and max value for the illuminance sensor + bool setMinMaxValue(uint16_t min, uint16_t max); + + // Set the tolerance value for the illuminance sensor + bool setTolerance(uint16_t tolerance); + + // Set the reporting interval for illuminance measurement in seconds and delta + bool setReporting(uint16_t min_interval, uint16_t max_interval, uint16_t delta); + + // Report the illuminance value + bool report(); +}; + +#endif // CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeLight.cpp b/libraries/Zigbee/src/ep/ZigbeeLight.cpp index 2a87db71287..edfac04fcdf 100644 --- a/libraries/Zigbee/src/ep/ZigbeeLight.cpp +++ b/libraries/Zigbee/src/ep/ZigbeeLight.cpp @@ -33,17 +33,24 @@ void ZigbeeLight::lightChanged() { } } -void ZigbeeLight::setLight(bool state) { +bool ZigbeeLight::setLight(bool state) { + esp_zb_zcl_status_t ret = ESP_ZB_ZCL_STATUS_SUCCESS; _current_state = state; lightChanged(); log_v("Updating on/off light state to %d", state); /* Update on/off light state */ esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_set_attribute_val( + ret = esp_zb_zcl_set_attribute_val( _endpoint, ESP_ZB_ZCL_CLUSTER_ID_ON_OFF, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID, &_current_state, false ); esp_zb_lock_release(); + + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set light state: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + return false; + } + return true; } #endif // CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeLight.h b/libraries/Zigbee/src/ep/ZigbeeLight.h index 807802be9b3..773fbb14ec5 100644 --- a/libraries/Zigbee/src/ep/ZigbeeLight.h +++ b/libraries/Zigbee/src/ep/ZigbeeLight.h @@ -23,7 +23,7 @@ class ZigbeeLight : public ZigbeeEP { lightChanged(); } // Use to control light state - void setLight(bool state); + bool setLight(bool state); // Use to get light state bool getLightState() { return _current_state; diff --git a/libraries/Zigbee/src/ep/ZigbeeOccupancySensor.cpp b/libraries/Zigbee/src/ep/ZigbeeOccupancySensor.cpp index 31a1f7e90e1..b8f88fed4a4 100644 --- a/libraries/Zigbee/src/ep/ZigbeeOccupancySensor.cpp +++ b/libraries/Zigbee/src/ep/ZigbeeOccupancySensor.cpp @@ -22,26 +22,41 @@ ZigbeeOccupancySensor::ZigbeeOccupancySensor(uint8_t endpoint) : ZigbeeEP(endpoi _ep_config = {.endpoint = _endpoint, .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, .app_device_id = ESP_ZB_HA_SIMPLE_SENSOR_DEVICE_ID, .app_device_version = 0}; } -void ZigbeeOccupancySensor::setSensorType(uint8_t sensor_type) { +bool ZigbeeOccupancySensor::setSensorType(uint8_t sensor_type) { uint8_t sensor_type_bitmap = 1 << sensor_type; esp_zb_attribute_list_t *occupancy_sens_cluster = esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_OCCUPANCY_SENSING, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); - esp_zb_cluster_update_attr(occupancy_sens_cluster, ESP_ZB_ZCL_ATTR_OCCUPANCY_SENSING_OCCUPANCY_SENSOR_TYPE_ID, (void *)&sensor_type); - esp_zb_cluster_update_attr(occupancy_sens_cluster, ESP_ZB_ZCL_ATTR_OCCUPANCY_SENSING_OCCUPANCY_SENSOR_TYPE_BITMAP_ID, (void *)&sensor_type_bitmap); + esp_err_t ret = esp_zb_cluster_update_attr(occupancy_sens_cluster, ESP_ZB_ZCL_ATTR_OCCUPANCY_SENSING_OCCUPANCY_SENSOR_TYPE_ID, (void *)&sensor_type); + if (ret != ESP_OK) { + log_e("Failed to set sensor type: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_cluster_update_attr(occupancy_sens_cluster, ESP_ZB_ZCL_ATTR_OCCUPANCY_SENSING_OCCUPANCY_SENSOR_TYPE_BITMAP_ID, (void *)&sensor_type_bitmap); + if (ret != ESP_OK) { + log_e("Failed to set sensor type bitmap: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; } -void ZigbeeOccupancySensor::setOccupancy(bool occupied) { +bool ZigbeeOccupancySensor::setOccupancy(bool occupied) { + esp_zb_zcl_status_t ret = ESP_ZB_ZCL_STATUS_SUCCESS; log_v("Updating occupancy sensor value..."); /* Update occupancy sensor value */ log_d("Setting occupancy to %d", occupied); esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_set_attribute_val( + ret = esp_zb_zcl_set_attribute_val( _endpoint, ESP_ZB_ZCL_CLUSTER_ID_OCCUPANCY_SENSING, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_OCCUPANCY_SENSING_OCCUPANCY_ID, &occupied, false ); esp_zb_lock_release(); + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set occupancy: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + return false; + } + return true; } -void ZigbeeOccupancySensor::report() { +bool ZigbeeOccupancySensor::report() { /* Send report attributes command */ esp_zb_zcl_report_attr_cmd_t report_attr_cmd; report_attr_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; @@ -52,9 +67,14 @@ void ZigbeeOccupancySensor::report() { report_attr_cmd.manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC; esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_report_attr_cmd_req(&report_attr_cmd); + esp_err_t ret = esp_zb_zcl_report_attr_cmd_req(&report_attr_cmd); esp_zb_lock_release(); + if (ret != ESP_OK) { + log_e("Failed to send occupancy report: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } log_v("Occupancy report sent"); + return true; } #endif // CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeOccupancySensor.h b/libraries/Zigbee/src/ep/ZigbeeOccupancySensor.h index fa622d5a707..7408e10a76b 100644 --- a/libraries/Zigbee/src/ep/ZigbeeOccupancySensor.h +++ b/libraries/Zigbee/src/ep/ZigbeeOccupancySensor.h @@ -42,13 +42,13 @@ class ZigbeeOccupancySensor : public ZigbeeEP { ~ZigbeeOccupancySensor() {} // Set the occupancy value. True for occupied, false for unoccupied - void setOccupancy(bool occupied); + bool setOccupancy(bool occupied); // Set the sensor type, see esp_zb_zcl_occupancy_sensing_occupancy_sensor_type_t - void setSensorType(uint8_t sensor_type); + bool setSensorType(uint8_t sensor_type); // Report the occupancy value - void report(); + bool report(); }; #endif // CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeePM25Sensor.cpp b/libraries/Zigbee/src/ep/ZigbeePM25Sensor.cpp new file mode 100644 index 00000000000..d25d15e5de3 --- /dev/null +++ b/libraries/Zigbee/src/ep/ZigbeePM25Sensor.cpp @@ -0,0 +1,118 @@ +#include "ZigbeePM25Sensor.h" +#if CONFIG_ZB_ENABLED + +esp_zb_cluster_list_t *zigbee_pm2_5_sensor_clusters_create(zigbee_pm2_5_sensor_cfg_t *pm2_5_sensor) { + esp_zb_basic_cluster_cfg_t *basic_cfg = pm2_5_sensor ? &(pm2_5_sensor->basic_cfg) : NULL; + esp_zb_identify_cluster_cfg_t *identify_cfg = pm2_5_sensor ? &(pm2_5_sensor->identify_cfg) : NULL; + esp_zb_pm2_5_measurement_cluster_cfg_t *pm2_5_meas_cfg = pm2_5_sensor ? &(pm2_5_sensor->pm2_5_meas_cfg) : NULL; + esp_zb_cluster_list_t *cluster_list = esp_zb_zcl_cluster_list_create(); + esp_zb_cluster_list_add_basic_cluster(cluster_list, esp_zb_basic_cluster_create(basic_cfg), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_zb_cluster_list_add_identify_cluster(cluster_list, esp_zb_identify_cluster_create(identify_cfg), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_zb_cluster_list_add_pm2_5_measurement_cluster(cluster_list, esp_zb_pm2_5_measurement_cluster_create(pm2_5_meas_cfg), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + return cluster_list; +} + +ZigbeePM25Sensor::ZigbeePM25Sensor(uint8_t endpoint) : ZigbeeEP(endpoint) { + _device_id = ESP_ZB_HA_SIMPLE_SENSOR_DEVICE_ID; + + //Create custom PM2.5 sensor configuration + zigbee_pm2_5_sensor_cfg_t pm2_5_sensor_cfg = ZIGBEE_DEFAULT_PM2_5_SENSOR_CONFIG(); + _cluster_list = zigbee_pm2_5_sensor_clusters_create(&pm2_5_sensor_cfg); + + _ep_config = {.endpoint = _endpoint, .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, .app_device_id = ESP_ZB_HA_SIMPLE_SENSOR_DEVICE_ID, .app_device_version = 0}; +} + +bool ZigbeePM25Sensor::setMinMaxValue(float min, float max) { + esp_zb_attribute_list_t *pm2_5_measure_cluster = + esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_PM2_5_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_err_t ret = esp_zb_cluster_update_attr(pm2_5_measure_cluster, ESP_ZB_ZCL_ATTR_PM2_5_MEASUREMENT_MIN_MEASURED_VALUE_ID, (void *)&min); + if (ret != ESP_OK) { + log_e("Failed to set min value: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_cluster_update_attr(pm2_5_measure_cluster, ESP_ZB_ZCL_ATTR_PM2_5_MEASUREMENT_MAX_MEASURED_VALUE_ID, (void *)&max); + if (ret != ESP_OK) { + log_e("Failed to set max value: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; +} + +bool ZigbeePM25Sensor::setTolerance(float tolerance) { + esp_zb_attribute_list_t *pm2_5_measure_cluster = + esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_PM2_5_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_err_t ret = esp_zb_pm2_5_measurement_cluster_add_attr(pm2_5_measure_cluster, ESP_ZB_ZCL_ATTR_PM2_5_MEASUREMENT_TOLERANCE_ID, (void *)&tolerance); + if (ret != ESP_OK) { + log_e("Failed to set tolerance: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; +} + +bool ZigbeePM25Sensor::setReporting(uint16_t min_interval, uint16_t max_interval, float delta) { + esp_zb_zcl_reporting_info_t reporting_info; + memset(&reporting_info, 0, sizeof(esp_zb_zcl_reporting_info_t)); + reporting_info.direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_SRV; + reporting_info.ep = _endpoint; + reporting_info.cluster_id = ESP_ZB_ZCL_CLUSTER_ID_PM2_5_MEASUREMENT; + reporting_info.cluster_role = ESP_ZB_ZCL_CLUSTER_SERVER_ROLE; + reporting_info.attr_id = ESP_ZB_ZCL_ATTR_PM2_5_MEASUREMENT_MEASURED_VALUE_ID; + reporting_info.u.send_info.min_interval = min_interval; + reporting_info.u.send_info.max_interval = max_interval; + reporting_info.u.send_info.def_min_interval = min_interval; + reporting_info.u.send_info.def_max_interval = max_interval; + // reporting_info.u.send_info.delta.u16 = (uint16_t)(delta * 100); // Convert delta to ZCL uint16_t + reporting_info.dst.profile_id = ESP_ZB_AF_HA_PROFILE_ID; + reporting_info.manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC; + float delta_f = delta; + memcpy(&reporting_info.u.send_info.delta.s32, &delta_f, sizeof(float)); + + esp_zb_lock_acquire(portMAX_DELAY); + esp_err_t ret = esp_zb_zcl_update_reporting_info(&reporting_info); + esp_zb_lock_release(); + if (ret != ESP_OK) { + log_e("Failed to set reporting: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; +} + +bool ZigbeePM25Sensor::setPM25(float pm25) { + esp_zb_zcl_status_t ret = ESP_ZB_ZCL_STATUS_SUCCESS; + log_v("Updating PM2.5 sensor value..."); + /* Update PM2.5 sensor measured value */ + log_d("Setting PM2.5 to %0.1f", pm25); + esp_zb_lock_acquire(portMAX_DELAY); + ret = esp_zb_zcl_set_attribute_val( + _endpoint, ESP_ZB_ZCL_CLUSTER_ID_PM2_5_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_PM2_5_MEASUREMENT_MEASURED_VALUE_ID, &pm25, false + ); + esp_zb_lock_release(); + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set PM2.5: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + return false; + } + return true; +} + +bool ZigbeePM25Sensor::report() { + /* Send report attributes command */ + esp_zb_zcl_report_attr_cmd_t report_attr_cmd; + report_attr_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; + report_attr_cmd.attributeID = ESP_ZB_ZCL_ATTR_PM2_5_MEASUREMENT_MEASURED_VALUE_ID; + report_attr_cmd.direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_CLI; + report_attr_cmd.clusterID = ESP_ZB_ZCL_CLUSTER_ID_PM2_5_MEASUREMENT; + report_attr_cmd.zcl_basic_cmd.src_endpoint = _endpoint; + report_attr_cmd.manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC; + + esp_zb_lock_acquire(portMAX_DELAY); + esp_err_t ret = esp_zb_zcl_report_attr_cmd_req(&report_attr_cmd); + esp_zb_lock_release(); + if (ret != ESP_OK) { + log_e("Failed to send PM2.5 report: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + log_v("PM2.5 report sent"); + return true; +} + +#endif // CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeePM25Sensor.h b/libraries/Zigbee/src/ep/ZigbeePM25Sensor.h new file mode 100644 index 00000000000..344f3e1f479 --- /dev/null +++ b/libraries/Zigbee/src/ep/ZigbeePM25Sensor.h @@ -0,0 +1,60 @@ +/* Class of Zigbee PM2.5 sensor endpoint inherited from common EP class */ + +#pragma once + +#include "soc/soc_caps.h" +#include "sdkconfig.h" +#if CONFIG_ZB_ENABLED + +#include "ZigbeeEP.h" +#include "ha/esp_zigbee_ha_standard.h" + +// clang-format off +#define ZIGBEE_DEFAULT_PM2_5_SENSOR_CONFIG() \ + { \ + .basic_cfg = \ + { \ + .zcl_version = ESP_ZB_ZCL_BASIC_ZCL_VERSION_DEFAULT_VALUE, \ + .power_source = ESP_ZB_ZCL_BASIC_POWER_SOURCE_DEFAULT_VALUE, \ + }, \ + .identify_cfg = \ + { \ + .identify_time = ESP_ZB_ZCL_IDENTIFY_IDENTIFY_TIME_DEFAULT_VALUE, \ + }, \ + .pm2_5_meas_cfg = \ + { \ + .measured_value = 0.0, \ + .min_measured_value = 0.0, \ + .max_measured_value = 500.0, \ + }, \ + } +// clang-format on + +typedef struct zigbee_pm2_5_sensor_cfg_s { + esp_zb_basic_cluster_cfg_t basic_cfg; + esp_zb_identify_cluster_cfg_t identify_cfg; + esp_zb_pm2_5_measurement_cluster_cfg_t pm2_5_meas_cfg; +} zigbee_pm2_5_sensor_cfg_t; + +class ZigbeePM25Sensor : public ZigbeeEP { +public: + ZigbeePM25Sensor(uint8_t endpoint); + ~ZigbeePM25Sensor() {} + + // Set the PM2.5 value in 0.1 µg/m³ + bool setPM25(float pm25); + + // Set the min and max value for the PM2.5 sensor in 0.1 µg/m³ + bool setMinMaxValue(float min, float max); + + // Set the tolerance value for the PM2.5 sensor in 0.1 µg/m³ + bool setTolerance(float tolerance); + + // Set the reporting interval for PM2.5 measurement in seconds and delta (PM2.5 change in 0.1 µg/m³) + bool setReporting(uint16_t min_interval, uint16_t max_interval, float delta); + + // Report the PM2.5 value + bool report(); +}; + +#endif // CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeePowerOutlet.cpp b/libraries/Zigbee/src/ep/ZigbeePowerOutlet.cpp new file mode 100644 index 00000000000..b96ba672c04 --- /dev/null +++ b/libraries/Zigbee/src/ep/ZigbeePowerOutlet.cpp @@ -0,0 +1,58 @@ +#include "ZigbeePowerOutlet.h" +#if CONFIG_ZB_ENABLED + +ZigbeePowerOutlet::ZigbeePowerOutlet(uint8_t endpoint) : ZigbeeEP(endpoint) { + _device_id = ESP_ZB_HA_MAINS_POWER_OUTLET_DEVICE_ID; + + esp_zb_mains_power_outlet_cfg_t outlet_cfg = ESP_ZB_DEFAULT_MAINS_POWER_OUTLET_CONFIG(); + _cluster_list = esp_zb_mains_power_outlet_clusters_create(&outlet_cfg); + _ep_config = { + .endpoint = endpoint, .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, .app_device_id = ESP_ZB_HA_MAINS_POWER_OUTLET_DEVICE_ID, .app_device_version = 0 + }; + log_v("Outlet endpoint created %d", _endpoint); +} + +//set attribute method -> method overridden in child class +void ZigbeePowerOutlet::zbAttributeSet(const esp_zb_zcl_set_attr_value_message_t *message) { + //check the data and call right method + if (message->info.cluster == ESP_ZB_ZCL_CLUSTER_ID_ON_OFF) { + if (message->attribute.id == ESP_ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID && message->attribute.data.type == ESP_ZB_ZCL_ATTR_TYPE_BOOL) { + _current_state = *(bool *)message->attribute.data.value; + stateChanged(); + } else { + log_w("Received message ignored. Attribute ID: %d not supported for On/Off Outlet", message->attribute.id); + } + } else { + log_w("Received message ignored. Cluster ID: %d not supported for On/Off Outlet", message->info.cluster); + } +} + +void ZigbeePowerOutlet::stateChanged() { + if (_on_state_change) { + _on_state_change(_current_state); + } else { + log_w("No callback function set for outlet change"); + } +} + +bool ZigbeePowerOutlet::setState(bool state) { + esp_zb_zcl_status_t ret = ESP_ZB_ZCL_STATUS_SUCCESS; + _current_state = state; + stateChanged(); + + log_v("Updating on/off outlet state to %d", state); + /* Update on/off outlet state */ + esp_zb_lock_acquire(portMAX_DELAY); + ret = esp_zb_zcl_set_attribute_val( + _endpoint, ESP_ZB_ZCL_CLUSTER_ID_ON_OFF, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID, &_current_state, false + ); + esp_zb_lock_release(); + + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set outlet state: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + return false; + } + return true; +} + +#endif // CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeePowerOutlet.h b/libraries/Zigbee/src/ep/ZigbeePowerOutlet.h new file mode 100644 index 00000000000..1ddb19587c7 --- /dev/null +++ b/libraries/Zigbee/src/ep/ZigbeePowerOutlet.h @@ -0,0 +1,41 @@ +/* Class of Zigbee On/Off Power outlet endpoint inherited from common EP class */ + +#pragma once + +#include "soc/soc_caps.h" +#include "sdkconfig.h" +#if CONFIG_ZB_ENABLED + +#include "ZigbeeEP.h" +#include "ha/esp_zigbee_ha_standard.h" + +class ZigbeePowerOutlet : public ZigbeeEP { +public: + ZigbeePowerOutlet(uint8_t endpoint); + ~ZigbeePowerOutlet() {} + + // Use to set a cb function to be called on outlet change + void onPowerOutletChange(void (*callback)(bool)) { + _on_state_change = callback; + } + // Use to restore outlet state + void restoreState() { + stateChanged(); + } + // Use to control outlet state + bool setState(bool state); + // Use to get outlet state + bool getPowerOutletState() { + return _current_state; + } + +private: + void zbAttributeSet(const esp_zb_zcl_set_attr_value_message_t *message) override; + //callback function to be called on outlet change + void (*_on_state_change)(bool); + void stateChanged(); + + bool _current_state; +}; + +#endif // CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeePressureSensor.cpp b/libraries/Zigbee/src/ep/ZigbeePressureSensor.cpp index 21456a51511..bca06a35d0c 100644 --- a/libraries/Zigbee/src/ep/ZigbeePressureSensor.cpp +++ b/libraries/Zigbee/src/ep/ZigbeePressureSensor.cpp @@ -22,21 +22,33 @@ ZigbeePressureSensor::ZigbeePressureSensor(uint8_t endpoint) : ZigbeeEP(endpoint _ep_config = {.endpoint = _endpoint, .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, .app_device_id = ESP_ZB_HA_SIMPLE_SENSOR_DEVICE_ID, .app_device_version = 0}; } -void ZigbeePressureSensor::setMinMaxValue(int16_t min, int16_t max) { - +bool ZigbeePressureSensor::setMinMaxValue(int16_t min, int16_t max) { esp_zb_attribute_list_t *pressure_measure_cluster = esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_PRESSURE_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); - esp_zb_cluster_update_attr(pressure_measure_cluster, ESP_ZB_ZCL_ATTR_PRESSURE_MEASUREMENT_MIN_VALUE_ID, (void *)&min); - esp_zb_cluster_update_attr(pressure_measure_cluster, ESP_ZB_ZCL_ATTR_PRESSURE_MEASUREMENT_MAX_VALUE_ID, (void *)&max); + esp_err_t ret = esp_zb_cluster_update_attr(pressure_measure_cluster, ESP_ZB_ZCL_ATTR_PRESSURE_MEASUREMENT_MIN_VALUE_ID, (void *)&min); + if (ret != ESP_OK) { + log_e("Failed to set min value: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_cluster_update_attr(pressure_measure_cluster, ESP_ZB_ZCL_ATTR_PRESSURE_MEASUREMENT_MAX_VALUE_ID, (void *)&max); + if (ret != ESP_OK) { + log_e("Failed to set max value: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; } -void ZigbeePressureSensor::setTolerance(uint16_t tolerance) { +bool ZigbeePressureSensor::setTolerance(uint16_t tolerance) { esp_zb_attribute_list_t *pressure_measure_cluster = esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_PRESSURE_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); - esp_zb_pressure_meas_cluster_add_attr(pressure_measure_cluster, ESP_ZB_ZCL_ATTR_PRESSURE_MEASUREMENT_TOLERANCE_ID, (void *)&tolerance); + esp_err_t ret = esp_zb_pressure_meas_cluster_add_attr(pressure_measure_cluster, ESP_ZB_ZCL_ATTR_PRESSURE_MEASUREMENT_TOLERANCE_ID, (void *)&tolerance); + if (ret != ESP_OK) { + log_e("Failed to set tolerance: 0x%x: %s", ret, esp_err_to_name(ret)); + } + return ret == ESP_OK; } -void ZigbeePressureSensor::setReporting(uint16_t min_interval, uint16_t max_interval, uint16_t delta) { +bool ZigbeePressureSensor::setReporting(uint16_t min_interval, uint16_t max_interval, uint16_t delta) { esp_zb_zcl_reporting_info_t reporting_info; memset(&reporting_info, 0, sizeof(esp_zb_zcl_reporting_info_t)); reporting_info.direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_SRV; @@ -52,22 +64,33 @@ void ZigbeePressureSensor::setReporting(uint16_t min_interval, uint16_t max_inte reporting_info.dst.profile_id = ESP_ZB_AF_HA_PROFILE_ID; reporting_info.manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC; esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_update_reporting_info(&reporting_info); + esp_err_t ret = esp_zb_zcl_update_reporting_info(&reporting_info); esp_zb_lock_release(); + if (ret != ESP_OK) { + log_e("Failed to set reporting: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; } -void ZigbeePressureSensor::setPressure(int16_t pressure) { +bool ZigbeePressureSensor::setPressure(int16_t pressure) { + esp_zb_zcl_status_t ret = ESP_ZB_ZCL_STATUS_SUCCESS; log_v("Updating pressure sensor value..."); /* Update pressure sensor measured value */ log_d("Setting pressure to %d hPa", pressure); esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_set_attribute_val( + ret = esp_zb_zcl_set_attribute_val( _endpoint, ESP_ZB_ZCL_CLUSTER_ID_PRESSURE_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_PRESSURE_MEASUREMENT_VALUE_ID, &pressure, false ); esp_zb_lock_release(); + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set pressure: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + return false; + } + return true; } -void ZigbeePressureSensor::report() { +bool ZigbeePressureSensor::report() { /* Send report attributes command */ esp_zb_zcl_report_attr_cmd_t report_attr_cmd; report_attr_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; @@ -78,9 +101,14 @@ void ZigbeePressureSensor::report() { report_attr_cmd.manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC; esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_report_attr_cmd_req(&report_attr_cmd); + esp_err_t ret = esp_zb_zcl_report_attr_cmd_req(&report_attr_cmd); esp_zb_lock_release(); + if (ret != ESP_OK) { + log_e("Failed to send pressure report: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } log_v("Pressure report sent"); + return true; } #endif // CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeePressureSensor.h b/libraries/Zigbee/src/ep/ZigbeePressureSensor.h index db14dd1c341..f93df7a7411 100644 --- a/libraries/Zigbee/src/ep/ZigbeePressureSensor.h +++ b/libraries/Zigbee/src/ep/ZigbeePressureSensor.h @@ -42,19 +42,19 @@ class ZigbeePressureSensor : public ZigbeeEP { ~ZigbeePressureSensor() {} // Set the pressure value in 1 hPa - void setPressure(int16_t value); + bool setPressure(int16_t value); // Set the min and max value for the pressure sensor in 1 hPa - void setMinMaxValue(int16_t min, int16_t max); + bool setMinMaxValue(int16_t min, int16_t max); // Set the tolerance value for the pressure sensor in 1 hPa - void setTolerance(uint16_t tolerance); + bool setTolerance(uint16_t tolerance); // Set the reporting interval for pressure measurement in seconds and delta (pressure change in 1 hPa) - void setReporting(uint16_t min_interval, uint16_t max_interval, uint16_t delta); + bool setReporting(uint16_t min_interval, uint16_t max_interval, uint16_t delta); // Report the pressure value - void report(); + bool report(); }; #endif // CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeSwitch.cpp b/libraries/Zigbee/src/ep/ZigbeeSwitch.cpp index 86c68ae1870..38fd7d370fb 100644 --- a/libraries/Zigbee/src/ep/ZigbeeSwitch.cpp +++ b/libraries/Zigbee/src/ep/ZigbeeSwitch.cpp @@ -7,6 +7,7 @@ ZigbeeSwitch *ZigbeeSwitch::_instance = nullptr; ZigbeeSwitch::ZigbeeSwitch(uint8_t endpoint) : ZigbeeEP(endpoint) { _device_id = ESP_ZB_HA_ON_OFF_SWITCH_DEVICE_ID; _instance = this; // Set the static pointer to this instance + _device = nullptr; esp_zb_on_off_switch_cfg_t switch_cfg = ESP_ZB_DEFAULT_ON_OFF_SWITCH_CONFIG(); _cluster_list = esp_zb_on_off_switch_clusters_create(&switch_cfg); @@ -15,18 +16,40 @@ ZigbeeSwitch::ZigbeeSwitch(uint8_t endpoint) : ZigbeeEP(endpoint) { } void ZigbeeSwitch::bindCb(esp_zb_zdp_status_t zdo_status, void *user_ctx) { + ZigbeeSwitch *instance = static_cast(user_ctx); if (zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) { log_i("Bound successfully!"); - if (user_ctx) { - zb_device_params_t *light = (zb_device_params_t *)user_ctx; + if (instance->_device) { + zb_device_params_t *light = (zb_device_params_t *)instance->_device; log_i("The light originating from address(0x%x) on endpoint(%d)", light->short_addr, light->endpoint); - _instance->_bound_devices.push_back(light); + log_d("Light bound to a switch on EP %d", instance->_endpoint); + instance->_bound_devices.push_back(light); } - _is_bound = true; + instance->_is_bound = true; + } else { + instance->_device = nullptr; + } +} + +void ZigbeeSwitch::bindCbWrapper(esp_zb_zdp_status_t zdo_status, void *user_ctx) { + ZigbeeSwitch *instance = static_cast(user_ctx); + if (instance) { + log_d("bindCbWrapper on EP %d", instance->_endpoint); + instance->bindCb(zdo_status, user_ctx); + } +} + +// Static wrapper for findCb +void ZigbeeSwitch::findCbWrapper(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx) { + ZigbeeSwitch *instance = static_cast(user_ctx); + if (instance) { + log_d("findCbWrapper on EP %d", instance->_endpoint); + instance->findCb(zdo_status, addr, endpoint, user_ctx); } } void ZigbeeSwitch::findCb(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx) { + ZigbeeSwitch *instance = static_cast(user_ctx); if (zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) { log_d("Found light endpoint"); esp_zb_zdo_bind_req_param_t bind_req; @@ -34,15 +57,21 @@ void ZigbeeSwitch::findCb(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t light->endpoint = endpoint; light->short_addr = addr; esp_zb_ieee_address_by_short(light->short_addr, light->ieee_addr); + log_d("Light found: short address(0x%x), endpoint(%d)", light->short_addr, light->endpoint); + esp_zb_get_long_address(bind_req.src_address); - bind_req.src_endp = *((uint8_t *)user_ctx); //_endpoint; + bind_req.src_endp = instance->_endpoint; bind_req.cluster_id = ESP_ZB_ZCL_CLUSTER_ID_ON_OFF; bind_req.dst_addr_mode = ESP_ZB_ZDO_BIND_DST_ADDR_MODE_64_BIT_EXTENDED; memcpy(bind_req.dst_address_u.addr_long, light->ieee_addr, sizeof(esp_zb_ieee_addr_t)); bind_req.dst_endp = endpoint; bind_req.req_dst_addr = esp_zb_get_short_address(); - log_i("Try to bind On/Off"); - esp_zb_zdo_device_bind_req(&bind_req, bindCb, (void *)light); + log_v("Try to bind On/Off"); + //save light params in the class + instance->_device = light; + + log_d("Find callback on EP %d", instance->_endpoint); + esp_zb_zdo_device_bind_req(&bind_req, ZigbeeSwitch::bindCbWrapper, this); } else { log_d("No light endpoint found"); } @@ -59,7 +88,7 @@ void ZigbeeSwitch::findEndpoint(esp_zb_zdo_match_desc_req_param_t *cmd_req) { .num_out_clusters = 1, .cluster_list = cluster_list, }; - esp_zb_zdo_match_cluster(&on_off_req, findCb, &_endpoint); + esp_zb_zdo_match_cluster(&on_off_req, ZigbeeSwitch::findCbWrapper, this); } // Methods to control the light diff --git a/libraries/Zigbee/src/ep/ZigbeeSwitch.h b/libraries/Zigbee/src/ep/ZigbeeSwitch.h index 5c527bec6e3..0e7011c3312 100644 --- a/libraries/Zigbee/src/ep/ZigbeeSwitch.h +++ b/libraries/Zigbee/src/ep/ZigbeeSwitch.h @@ -37,10 +37,12 @@ class ZigbeeSwitch : public ZigbeeEP { private: // save instance of the class in order to use it in static functions static ZigbeeSwitch *_instance; - + zb_device_params_t *_device; void findEndpoint(esp_zb_zdo_match_desc_req_param_t *cmd_req); - static void bindCb(esp_zb_zdp_status_t zdo_status, void *user_ctx); - static void findCb(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx); + void bindCb(esp_zb_zdp_status_t zdo_status, void *user_ctx); + void findCb(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx); + static void findCbWrapper(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx); + static void bindCbWrapper(esp_zb_zdp_status_t zdo_status, void *user_ctx); }; #endif // CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeTempSensor.cpp b/libraries/Zigbee/src/ep/ZigbeeTempSensor.cpp index b3ff03f0a6b..7126dae15cf 100644 --- a/libraries/Zigbee/src/ep/ZigbeeTempSensor.cpp +++ b/libraries/Zigbee/src/ep/ZigbeeTempSensor.cpp @@ -17,24 +17,38 @@ static int16_t zb_float_to_s16(float temp) { return (int16_t)(temp * 100); } -void ZigbeeTempSensor::setMinMaxValue(float min, float max) { +bool ZigbeeTempSensor::setMinMaxValue(float min, float max) { int16_t zb_min = zb_float_to_s16(min); int16_t zb_max = zb_float_to_s16(max); esp_zb_attribute_list_t *temp_measure_cluster = esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); - esp_zb_cluster_update_attr(temp_measure_cluster, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MIN_VALUE_ID, (void *)&zb_min); - esp_zb_cluster_update_attr(temp_measure_cluster, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MAX_VALUE_ID, (void *)&zb_max); + esp_err_t ret = esp_zb_cluster_update_attr(temp_measure_cluster, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MIN_VALUE_ID, (void *)&zb_min); + if (ret != ESP_OK) { + log_e("Failed to set min value: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_cluster_update_attr(temp_measure_cluster, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MAX_VALUE_ID, (void *)&zb_max); + if (ret != ESP_OK) { + log_e("Failed to set max value: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; } -void ZigbeeTempSensor::setTolerance(float tolerance) { +bool ZigbeeTempSensor::setTolerance(float tolerance) { // Convert tolerance to ZCL uint16_t uint16_t zb_tolerance = (uint16_t)(tolerance * 100); esp_zb_attribute_list_t *temp_measure_cluster = esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); - esp_zb_temperature_meas_cluster_add_attr(temp_measure_cluster, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_TOLERANCE_ID, (void *)&zb_tolerance); + esp_err_t ret = esp_zb_temperature_meas_cluster_add_attr(temp_measure_cluster, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_TOLERANCE_ID, (void *)&zb_tolerance); + if (ret != ESP_OK) { + log_e("Failed to set tolerance: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; } -void ZigbeeTempSensor::setReporting(uint16_t min_interval, uint16_t max_interval, float delta) { +bool ZigbeeTempSensor::setReporting(uint16_t min_interval, uint16_t max_interval, float delta) { esp_zb_zcl_reporting_info_t reporting_info; memset(&reporting_info, 0, sizeof(esp_zb_zcl_reporting_info_t)); reporting_info.direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_SRV; @@ -50,23 +64,34 @@ void ZigbeeTempSensor::setReporting(uint16_t min_interval, uint16_t max_interval reporting_info.dst.profile_id = ESP_ZB_AF_HA_PROFILE_ID; reporting_info.manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC; esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_update_reporting_info(&reporting_info); + esp_err_t ret = esp_zb_zcl_update_reporting_info(&reporting_info); esp_zb_lock_release(); + if (ret != ESP_OK) { + log_e("Failed to set reporting: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; } -void ZigbeeTempSensor::setTemperature(float temperature) { +bool ZigbeeTempSensor::setTemperature(float temperature) { + esp_zb_zcl_status_t ret = ESP_ZB_ZCL_STATUS_SUCCESS; int16_t zb_temperature = zb_float_to_s16(temperature); log_v("Updating temperature sensor value..."); /* Update temperature sensor measured value */ log_d("Setting temperature to %d", zb_temperature); esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_set_attribute_val( + ret = esp_zb_zcl_set_attribute_val( _endpoint, ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID, &zb_temperature, false ); esp_zb_lock_release(); + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set temperature: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + return false; + } + return true; } -void ZigbeeTempSensor::reportTemperature() { +bool ZigbeeTempSensor::reportTemperature() { /* Send report attributes command */ esp_zb_zcl_report_attr_cmd_t report_attr_cmd; report_attr_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; @@ -77,9 +102,14 @@ void ZigbeeTempSensor::reportTemperature() { report_attr_cmd.manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC; esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_report_attr_cmd_req(&report_attr_cmd); + esp_err_t ret = esp_zb_zcl_report_attr_cmd_req(&report_attr_cmd); esp_zb_lock_release(); + if (ret != ESP_OK) { + log_e("Failed to send temperature report: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } log_v("Temperature report sent"); + return true; } void ZigbeeTempSensor::addHumiditySensor(float min, float max, float tolerance) { @@ -96,20 +126,26 @@ void ZigbeeTempSensor::addHumiditySensor(float min, float max, float tolerance) _humidity_sensor = true; } -void ZigbeeTempSensor::setHumidity(float humidity) { +bool ZigbeeTempSensor::setHumidity(float humidity) { + esp_zb_zcl_status_t ret = ESP_ZB_ZCL_STATUS_SUCCESS; int16_t zb_humidity = zb_float_to_s16(humidity); log_v("Updating humidity sensor value..."); /* Update humidity sensor measured value */ log_d("Setting humidity to %d", zb_humidity); esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_set_attribute_val( + ret = esp_zb_zcl_set_attribute_val( _endpoint, ESP_ZB_ZCL_CLUSTER_ID_REL_HUMIDITY_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_REL_HUMIDITY_MEASUREMENT_VALUE_ID, &zb_humidity, false ); esp_zb_lock_release(); + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set humidity: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + return false; + } + return true; } -void ZigbeeTempSensor::reportHumidity() { +bool ZigbeeTempSensor::reportHumidity() { /* Send report attributes command */ esp_zb_zcl_report_attr_cmd_t report_attr_cmd; report_attr_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; @@ -120,12 +156,17 @@ void ZigbeeTempSensor::reportHumidity() { report_attr_cmd.manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC; esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_report_attr_cmd_req(&report_attr_cmd); + esp_err_t ret = esp_zb_zcl_report_attr_cmd_req(&report_attr_cmd); esp_zb_lock_release(); + if (ret != ESP_OK) { + log_e("Failed to send humidity report: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } log_v("Humidity report sent"); + return true; } -void ZigbeeTempSensor::setHumidityReporting(uint16_t min_interval, uint16_t max_interval, float delta) { +bool ZigbeeTempSensor::setHumidityReporting(uint16_t min_interval, uint16_t max_interval, float delta) { esp_zb_zcl_reporting_info_t reporting_info; memset(&reporting_info, 0, sizeof(esp_zb_zcl_reporting_info_t)); reporting_info.direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_SRV; @@ -141,15 +182,22 @@ void ZigbeeTempSensor::setHumidityReporting(uint16_t min_interval, uint16_t max_ reporting_info.dst.profile_id = ESP_ZB_AF_HA_PROFILE_ID; reporting_info.manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC; esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_update_reporting_info(&reporting_info); + esp_err_t ret = esp_zb_zcl_update_reporting_info(&reporting_info); esp_zb_lock_release(); + if (ret != ESP_OK) { + log_e("Failed to set humidity reporting: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; } -void ZigbeeTempSensor::report() { - reportTemperature(); +bool ZigbeeTempSensor::report() { + bool temp_ret = reportTemperature(); + bool hum_ret = true; if (_humidity_sensor) { - reportHumidity(); + hum_ret = reportHumidity(); } + return temp_ret && hum_ret; } #endif // CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeTempSensor.h b/libraries/Zigbee/src/ep/ZigbeeTempSensor.h index 41da03d9db8..bc769b32de6 100644 --- a/libraries/Zigbee/src/ep/ZigbeeTempSensor.h +++ b/libraries/Zigbee/src/ep/ZigbeeTempSensor.h @@ -15,34 +15,34 @@ class ZigbeeTempSensor : public ZigbeeEP { ~ZigbeeTempSensor() {} // Set the temperature value in 0,01°C - void setTemperature(float value); + bool setTemperature(float value); // Set the min and max value for the temperature sensor in 0,01°C - void setMinMaxValue(float min, float max); + bool setMinMaxValue(float min, float max); // Set the tolerance value for the temperature sensor in 0,01°C - void setTolerance(float tolerance); + bool setTolerance(float tolerance); // Set the reporting interval for temperature measurement in seconds and delta (temp change in 0,01 °C) - void setReporting(uint16_t min_interval, uint16_t max_interval, float delta); + bool setReporting(uint16_t min_interval, uint16_t max_interval, float delta); // Report the temperature value - void reportTemperature(); + bool reportTemperature(); // Add humidity cluster to the temperature sensor device void addHumiditySensor(float min, float max, float tolerance); // Set the humidity value in 0,01% - void setHumidity(float value); + bool setHumidity(float value); // Set the reporting interval for humidity measurement in seconds and delta (humidity change in 0,01%) - void setHumidityReporting(uint16_t min_interval, uint16_t max_interval, float delta); + bool setHumidityReporting(uint16_t min_interval, uint16_t max_interval, float delta); // Report the humidity value - void reportHumidity(); + bool reportHumidity(); // Report the temperature and humidity values if humidity sensor is added - void report(); + bool report(); private: bool _humidity_sensor; diff --git a/libraries/Zigbee/src/ep/ZigbeeThermostat.cpp b/libraries/Zigbee/src/ep/ZigbeeThermostat.cpp index 357bcaed1bc..633a60d0ff9 100644 --- a/libraries/Zigbee/src/ep/ZigbeeThermostat.cpp +++ b/libraries/Zigbee/src/ep/ZigbeeThermostat.cpp @@ -10,7 +10,8 @@ ZigbeeThermostat *ZigbeeThermostat::_instance = nullptr; ZigbeeThermostat::ZigbeeThermostat(uint8_t endpoint) : ZigbeeEP(endpoint) { _device_id = ESP_ZB_HA_THERMOSTAT_DEVICE_ID; - _instance = this; // Set the static pointer to this instance + _instance = this; // Set the static pointer to this instance + _device = nullptr; // Initialize sensor pointer to null //use custom config to avoid narrowing error -> must be fixed in zigbee-sdk esp_zb_thermostat_cfg_t thermostat_cfg = ZB_DEFAULT_THERMOSTAT_CONFIG(); @@ -29,21 +30,39 @@ ZigbeeThermostat::ZigbeeThermostat(uint8_t endpoint) : ZigbeeEP(endpoint) { } void ZigbeeThermostat::bindCb(esp_zb_zdp_status_t zdo_status, void *user_ctx) { + ZigbeeThermostat *instance = static_cast(user_ctx); if (zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) { - if (user_ctx) { - zb_device_params_t *sensor = (zb_device_params_t *)user_ctx; - log_i("The temperature sensor originating from address(0x%x) on endpoint(%d)", sensor->short_addr, sensor->endpoint); - _instance->_bound_devices.push_back(sensor); - } else { - log_v("Local binding success"); + log_i("Bound successfully!"); + if (instance->_device) { + zb_device_params_t *sensor = (zb_device_params_t *)instance->_device; + log_i("The sensor originating from address(0x%x) on endpoint(%d)", sensor->short_addr, sensor->endpoint); + log_d("Sensor bound to thermostat on EP %d", instance->_endpoint); + instance->_bound_devices.push_back(sensor); } - _is_bound = true; + instance->_is_bound = true; } else { - log_e("Binding failed!"); + instance->_device = nullptr; + } +} + +void ZigbeeThermostat::bindCbWrapper(esp_zb_zdp_status_t zdo_status, void *user_ctx) { + ZigbeeThermostat *instance = static_cast(user_ctx); + if (instance) { + log_d("bindCbWrapper on EP %d", instance->_endpoint); + instance->bindCb(zdo_status, user_ctx); + } +} + +void ZigbeeThermostat::findCbWrapper(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx) { + ZigbeeThermostat *instance = static_cast(user_ctx); + if (instance) { + log_d("findCbWrapper on EP %d", instance->_endpoint); + instance->findCb(zdo_status, addr, endpoint, user_ctx); } } void ZigbeeThermostat::findCb(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx) { + ZigbeeThermostat *instance = static_cast(user_ctx); if (zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) { log_i("Found temperature sensor"); esp_zb_zdo_bind_req_param_t bind_req; @@ -56,37 +75,34 @@ void ZigbeeThermostat::findCb(esp_zb_zdp_status_t zdo_status, uint16_t addr, uin /* 1. Send binding request to the sensor */ bind_req.req_dst_addr = addr; - log_d("Request temperature sensor to bind us"); - - /* populate the src information of the binding */ memcpy(bind_req.src_address, sensor->ieee_addr, sizeof(esp_zb_ieee_addr_t)); bind_req.src_endp = endpoint; bind_req.cluster_id = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT; - log_d("Bind temperature sensor"); - - /* populate the dst information of the binding */ bind_req.dst_addr_mode = ESP_ZB_ZDO_BIND_DST_ADDR_MODE_64_BIT_EXTENDED; esp_zb_get_long_address(bind_req.dst_address_u.addr_long); - bind_req.dst_endp = *((uint8_t *)user_ctx); //_endpoint; + bind_req.dst_endp = instance->_endpoint; log_i("Request temperature sensor to bind us"); - esp_zb_zdo_device_bind_req(&bind_req, bindCb, NULL); + esp_zb_zdo_device_bind_req(&bind_req, ZigbeeThermostat::bindCbWrapper, NULL); /* 2. Send binding request to self */ bind_req.req_dst_addr = esp_zb_get_short_address(); /* populate the src information of the binding */ esp_zb_get_long_address(bind_req.src_address); - bind_req.src_endp = *((uint8_t *)user_ctx); //_endpoint; + bind_req.src_endp = instance->_endpoint; bind_req.cluster_id = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT; - - /* populate the dst information of the binding */ bind_req.dst_addr_mode = ESP_ZB_ZDO_BIND_DST_ADDR_MODE_64_BIT_EXTENDED; memcpy(bind_req.dst_address_u.addr_long, sensor->ieee_addr, sizeof(esp_zb_ieee_addr_t)); bind_req.dst_endp = endpoint; + log_i("Try to bind Temperature Measurement"); + //save sensor params in the class + instance->_device = sensor; - log_i("Bind temperature sensor"); - esp_zb_zdo_device_bind_req(&bind_req, bindCb, (void *)sensor); + log_d("Find callback on EP %d", instance->_endpoint); + esp_zb_zdo_device_bind_req(&bind_req, ZigbeeThermostat::bindCbWrapper, this); + } else { + log_d("No temperature sensor endpoint found"); } } @@ -96,7 +112,7 @@ void ZigbeeThermostat::findEndpoint(esp_zb_zdo_match_desc_req_param_t *param) { param->num_in_clusters = 1; param->num_out_clusters = 0; param->cluster_list = cluster_list; - esp_zb_zdo_match_cluster(param, findCb, &_endpoint); + esp_zb_zdo_match_cluster(param, ZigbeeThermostat::findCbWrapper, this); } void ZigbeeThermostat::zbAttributeRead(uint16_t cluster_id, const esp_zb_zcl_attribute_t *attribute) { diff --git a/libraries/Zigbee/src/ep/ZigbeeThermostat.h b/libraries/Zigbee/src/ep/ZigbeeThermostat.h index 7895115e1d1..acdcd68e512 100644 --- a/libraries/Zigbee/src/ep/ZigbeeThermostat.h +++ b/libraries/Zigbee/src/ep/ZigbeeThermostat.h @@ -48,6 +48,7 @@ class ZigbeeThermostat : public ZigbeeEP { private: // save instance of the class in order to use it in static functions static ZigbeeThermostat *_instance; + zb_device_params_t *_device; void (*_on_temp_recieve)(float); void (*_on_config_recieve)(float, float, float); @@ -56,8 +57,10 @@ class ZigbeeThermostat : public ZigbeeEP { float _tolerance; void findEndpoint(esp_zb_zdo_match_desc_req_param_t *cmd_req); - static void bindCb(esp_zb_zdp_status_t zdo_status, void *user_ctx); - static void findCb(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx); + void bindCb(esp_zb_zdp_status_t zdo_status, void *user_ctx); + void findCb(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx); + static void bindCbWrapper(esp_zb_zdp_status_t zdo_status, void *user_ctx); + static void findCbWrapper(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx); void zbAttributeRead(uint16_t cluster_id, const esp_zb_zcl_attribute_t *attribute) override; }; diff --git a/libraries/Zigbee/src/ep/ZigbeeVibrationSensor.cpp b/libraries/Zigbee/src/ep/ZigbeeVibrationSensor.cpp index 9fc75297262..6be457c389a 100644 --- a/libraries/Zigbee/src/ep/ZigbeeVibrationSensor.cpp +++ b/libraries/Zigbee/src/ep/ZigbeeVibrationSensor.cpp @@ -29,16 +29,22 @@ void ZigbeeVibrationSensor::setIASClientEndpoint(uint8_t ep_number) { _ias_cie_endpoint = ep_number; } -void ZigbeeVibrationSensor::setVibration(bool sensed) { +bool ZigbeeVibrationSensor::setVibration(bool sensed) { + esp_zb_zcl_status_t ret = ESP_ZB_ZCL_STATUS_SUCCESS; log_v("Setting Vibration sensor to %s", sensed ? "sensed" : "not sensed"); uint8_t vibration = (uint8_t)sensed; esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_set_attribute_val( + ret = esp_zb_zcl_set_attribute_val( _endpoint, ESP_ZB_ZCL_CLUSTER_ID_IAS_ZONE, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_IAS_ZONE_ZONESTATUS_ID, &vibration, false ); esp_zb_lock_release(); + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set vibration status: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + return false; + } _zone_status = vibration; report(); + return true; } void ZigbeeVibrationSensor::report() { @@ -49,7 +55,6 @@ void ZigbeeVibrationSensor::report() { status_change_notif_cmd.zcl_basic_cmd.src_endpoint = _endpoint; status_change_notif_cmd.zcl_basic_cmd.dst_endpoint = _ias_cie_endpoint; //default is 1 memcpy(status_change_notif_cmd.zcl_basic_cmd.dst_addr_u.addr_long, _ias_cie_addr, sizeof(esp_zb_ieee_addr_t)); - status_change_notif_cmd.zone_status = _zone_status; status_change_notif_cmd.extend_status = 0; status_change_notif_cmd.zone_id = _zone_id; diff --git a/libraries/Zigbee/src/ep/ZigbeeVibrationSensor.h b/libraries/Zigbee/src/ep/ZigbeeVibrationSensor.h index 1ee3740dcc3..2f67c7bb6b4 100644 --- a/libraries/Zigbee/src/ep/ZigbeeVibrationSensor.h +++ b/libraries/Zigbee/src/ep/ZigbeeVibrationSensor.h @@ -48,7 +48,7 @@ class ZigbeeVibrationSensor : public ZigbeeEP { void setIASClientEndpoint(uint8_t ep_number); // Set the vibration sensor value (true = sensed, false = not sensed) - void setVibration(bool sensed); + bool setVibration(bool sensed); // Report the vibration sensor value, done automatically after setting the sensed value void report(); diff --git a/libraries/Zigbee/src/ep/ZigbeeWindSpeedSensor.cpp b/libraries/Zigbee/src/ep/ZigbeeWindSpeedSensor.cpp index d93b02adbc3..72184927d4d 100644 --- a/libraries/Zigbee/src/ep/ZigbeeWindSpeedSensor.cpp +++ b/libraries/Zigbee/src/ep/ZigbeeWindSpeedSensor.cpp @@ -28,25 +28,39 @@ static uint16_t zb_windspeed_to_u16(float windspeed) { return (uint16_t)(windspeed * 100); } -void ZigbeeWindSpeedSensor::setMinMaxValue(float min, float max) { +bool ZigbeeWindSpeedSensor::setMinMaxValue(float min, float max) { uint16_t zb_min = zb_windspeed_to_u16(min); uint16_t zb_max = zb_windspeed_to_u16(max); esp_zb_attribute_list_t *windspeed_measure_cluster = esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_WIND_SPEED_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); - // - esp_zb_cluster_update_attr(windspeed_measure_cluster, ESP_ZB_ZCL_ATTR_WIND_SPEED_MEASUREMENT_MIN_MEASURED_VALUE_ID, (void *)&zb_min); - esp_zb_cluster_update_attr(windspeed_measure_cluster, ESP_ZB_ZCL_ATTR_WIND_SPEED_MEASUREMENT_MAX_MEASURED_VALUE_ID, (void *)&zb_max); + esp_err_t ret = esp_zb_cluster_update_attr(windspeed_measure_cluster, ESP_ZB_ZCL_ATTR_WIND_SPEED_MEASUREMENT_MIN_MEASURED_VALUE_ID, (void *)&zb_min); + if (ret != ESP_OK) { + log_e("Failed to set min value: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_cluster_update_attr(windspeed_measure_cluster, ESP_ZB_ZCL_ATTR_WIND_SPEED_MEASUREMENT_MAX_MEASURED_VALUE_ID, (void *)&zb_max); + if (ret != ESP_OK) { + log_e("Failed to set max value: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; } -void ZigbeeWindSpeedSensor::setTolerance(float tolerance) { +bool ZigbeeWindSpeedSensor::setTolerance(float tolerance) { // Convert tolerance to ZCL uint16_t uint16_t zb_tolerance = zb_windspeed_to_u16(tolerance); esp_zb_attribute_list_t *windspeed_measure_cluster = esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_WIND_SPEED_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); - esp_zb_wind_speed_measurement_cluster_add_attr(windspeed_measure_cluster, ESP_ZB_ZCL_ATTR_WIND_SPEED_MEASUREMENT_TOLERANCE_ID, (void *)&zb_tolerance); + esp_err_t ret = + esp_zb_wind_speed_measurement_cluster_add_attr(windspeed_measure_cluster, ESP_ZB_ZCL_ATTR_WIND_SPEED_MEASUREMENT_TOLERANCE_ID, (void *)&zb_tolerance); + if (ret != ESP_OK) { + log_e("Failed to set tolerance: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; } -void ZigbeeWindSpeedSensor::setReporting(uint16_t min_interval, uint16_t max_interval, float delta) { +bool ZigbeeWindSpeedSensor::setReporting(uint16_t min_interval, uint16_t max_interval, float delta) { esp_zb_zcl_reporting_info_t reporting_info; memset(&reporting_info, 0, sizeof(esp_zb_zcl_reporting_info_t)); reporting_info.direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_SRV; @@ -62,24 +76,35 @@ void ZigbeeWindSpeedSensor::setReporting(uint16_t min_interval, uint16_t max_int reporting_info.dst.profile_id = ESP_ZB_AF_HA_PROFILE_ID; reporting_info.manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC; esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_update_reporting_info(&reporting_info); + esp_err_t ret = esp_zb_zcl_update_reporting_info(&reporting_info); esp_zb_lock_release(); + if (ret != ESP_OK) { + log_e("Failed to set reporting: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; } -void ZigbeeWindSpeedSensor::setWindSpeed(float windspeed) { +bool ZigbeeWindSpeedSensor::setWindSpeed(float windspeed) { + esp_zb_zcl_status_t ret = ESP_ZB_ZCL_STATUS_SUCCESS; uint16_t zb_windspeed = zb_windspeed_to_u16(windspeed); log_v("Updating windspeed sensor value..."); /* Update windspeed sensor measured value */ log_d("Setting windspeed to %d", zb_windspeed); esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_set_attribute_val( + ret = esp_zb_zcl_set_attribute_val( _endpoint, ESP_ZB_ZCL_CLUSTER_ID_WIND_SPEED_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_WIND_SPEED_MEASUREMENT_MEASURED_VALUE_ID, &zb_windspeed, false ); esp_zb_lock_release(); + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set wind speed: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + return false; + } + return true; } -void ZigbeeWindSpeedSensor::reportWindSpeed() { +bool ZigbeeWindSpeedSensor::reportWindSpeed() { /* Send report attributes command */ esp_zb_zcl_report_attr_cmd_t report_attr_cmd; report_attr_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; @@ -90,9 +115,14 @@ void ZigbeeWindSpeedSensor::reportWindSpeed() { report_attr_cmd.manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC; esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_report_attr_cmd_req(&report_attr_cmd); + esp_err_t ret = esp_zb_zcl_report_attr_cmd_req(&report_attr_cmd); esp_zb_lock_release(); + if (ret != ESP_OK) { + log_e("Failed to send wind speed report: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } log_v("Wind speed measurement report sent"); + return true; } #endif //CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeWindSpeedSensor.h b/libraries/Zigbee/src/ep/ZigbeeWindSpeedSensor.h index e091d3ae548..641c1d84780 100644 --- a/libraries/Zigbee/src/ep/ZigbeeWindSpeedSensor.h +++ b/libraries/Zigbee/src/ep/ZigbeeWindSpeedSensor.h @@ -40,17 +40,17 @@ class ZigbeeWindSpeedSensor : public ZigbeeEP { ~ZigbeeWindSpeedSensor() {} // Set the WindSpeed value in 0,01 m/s - void setWindSpeed(float value); + bool setWindSpeed(float value); // Set the min and max value for the WindSpeed sensor - void setMinMaxValue(float min, float max); + bool setMinMaxValue(float min, float max); // Set the tolerance value for the WindSpeed sensor - void setTolerance(float tolerance); + bool setTolerance(float tolerance); // Set the reporting interval for WindSpeed measurement in seconds and delta - void setReporting(uint16_t min_interval, uint16_t max_interval, float delta); - void reportWindSpeed(); + bool setReporting(uint16_t min_interval, uint16_t max_interval, float delta); + bool reportWindSpeed(); }; #endif //CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeWindowCovering.cpp b/libraries/Zigbee/src/ep/ZigbeeWindowCovering.cpp index f6d6ec268ea..7c7889dbbf7 100644 --- a/libraries/Zigbee/src/ep/ZigbeeWindowCovering.cpp +++ b/libraries/Zigbee/src/ep/ZigbeeWindowCovering.cpp @@ -1,4 +1,3 @@ - #include "ZigbeeWindowCovering.h" #if CONFIG_ZB_ENABLED @@ -72,13 +71,18 @@ ZigbeeWindowCovering::ZigbeeWindowCovering(uint8_t endpoint) : ZigbeeEP(endpoint } // Configuration methods for window covering -void ZigbeeWindowCovering::setCoveringType(ZigbeeWindowCoveringType covering_type) { +bool ZigbeeWindowCovering::setCoveringType(ZigbeeWindowCoveringType covering_type) { esp_zb_attribute_list_t *window_covering_cluster = esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_WINDOW_COVERING, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); - esp_zb_cluster_update_attr(window_covering_cluster, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_WINDOW_COVERING_TYPE_ID, (void *)&covering_type); + esp_err_t ret = esp_zb_cluster_update_attr(window_covering_cluster, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_WINDOW_COVERING_TYPE_ID, (void *)&covering_type); + if (ret != ESP_OK) { + log_e("Failed to set covering type: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; } -void ZigbeeWindowCovering::setConfigStatus( +bool ZigbeeWindowCovering::setConfigStatus( bool operational, bool online, bool commands_reversed, bool lift_closed_loop, bool tilt_closed_loop, bool lift_encoder_controlled, bool tilt_encoder_controlled ) { @@ -93,10 +97,15 @@ void ZigbeeWindowCovering::setConfigStatus( esp_zb_attribute_list_t *window_covering_cluster = esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_WINDOW_COVERING, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); - esp_zb_cluster_update_attr(window_covering_cluster, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_CONFIG_STATUS_ID, (void *)&config_status); + esp_err_t ret = esp_zb_cluster_update_attr(window_covering_cluster, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_CONFIG_STATUS_ID, (void *)&config_status); + if (ret != ESP_OK) { + log_e("Failed to set config status: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; } -void ZigbeeWindowCovering::setMode(bool motor_reversed, bool calibration_mode, bool maintenance_mode, bool leds_on) { +bool ZigbeeWindowCovering::setMode(bool motor_reversed, bool calibration_mode, bool maintenance_mode, bool leds_on) { uint8_t mode = (motor_reversed ? ESP_ZB_ZCL_ATTR_WINDOW_COVERING_TYPE_REVERSED_MOTOR_DIRECTION : 0) | (calibration_mode ? ESP_ZB_ZCL_ATTR_WINDOW_COVERING_TYPE_RUN_IN_CALIBRATION_MODE : 0) | (maintenance_mode ? ESP_ZB_ZCL_ATTR_WINDOW_COVERING_TYPE_MOTOR_IS_RUNNING_IN_MAINTENANCE_MODE : 0) @@ -106,10 +115,15 @@ void ZigbeeWindowCovering::setMode(bool motor_reversed, bool calibration_mode, b esp_zb_attribute_list_t *window_covering_cluster = esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_WINDOW_COVERING, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); - esp_zb_cluster_update_attr(window_covering_cluster, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_MODE_ID, (void *)&mode); + esp_err_t ret = esp_zb_cluster_update_attr(window_covering_cluster, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_MODE_ID, (void *)&mode); + if (ret != ESP_OK) { + log_e("Failed to set mode: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; } -void ZigbeeWindowCovering::setLimits( +bool ZigbeeWindowCovering::setLimits( uint16_t installed_open_limit_lift, uint16_t installed_closed_limit_lift, uint16_t installed_open_limit_tilt, uint16_t installed_closed_limit_tilt ) { _installed_open_limit_lift = installed_open_limit_lift; @@ -121,12 +135,41 @@ void ZigbeeWindowCovering::setLimits( esp_zb_attribute_list_t *window_covering_cluster = esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_WINDOW_COVERING, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); - esp_zb_cluster_update_attr(window_covering_cluster, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_INSTALLED_OPEN_LIMIT_LIFT_ID, (void *)&_installed_open_limit_lift); - esp_zb_cluster_update_attr(window_covering_cluster, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_INSTALLED_CLOSED_LIMIT_LIFT_ID, (void *)&_installed_closed_limit_lift); - esp_zb_cluster_update_attr(window_covering_cluster, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_INSTALLED_OPEN_LIMIT_TILT_ID, (void *)&_installed_open_limit_tilt); - esp_zb_cluster_update_attr(window_covering_cluster, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_INSTALLED_CLOSED_LIMIT_TILT_ID, (void *)&_installed_closed_limit_tilt); - esp_zb_cluster_update_attr(window_covering_cluster, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_PHYSICAL_CLOSED_LIMIT_LIFT_ID, (void *)&_physical_closed_limit_lift); - esp_zb_cluster_update_attr(window_covering_cluster, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_PHY_CLOSED_LIMIT_TILT_ID, (void *)&_physical_closed_limit_tilt); + esp_err_t ret = + esp_zb_cluster_update_attr(window_covering_cluster, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_INSTALLED_OPEN_LIMIT_LIFT_ID, (void *)&_installed_open_limit_lift); + if (ret != ESP_OK) { + log_e("Failed to set installed open limit lift: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = + esp_zb_cluster_update_attr(window_covering_cluster, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_INSTALLED_CLOSED_LIMIT_LIFT_ID, (void *)&_installed_closed_limit_lift); + if (ret != ESP_OK) { + log_e("Failed to set installed closed limit lift: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_cluster_update_attr(window_covering_cluster, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_INSTALLED_OPEN_LIMIT_TILT_ID, (void *)&_installed_open_limit_tilt); + if (ret != ESP_OK) { + log_e("Failed to set installed open limit tilt: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = + esp_zb_cluster_update_attr(window_covering_cluster, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_INSTALLED_CLOSED_LIMIT_TILT_ID, (void *)&_installed_closed_limit_tilt); + if (ret != ESP_OK) { + log_e("Failed to set installed closed limit tilt: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = + esp_zb_cluster_update_attr(window_covering_cluster, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_PHYSICAL_CLOSED_LIMIT_LIFT_ID, (void *)&_physical_closed_limit_lift); + if (ret != ESP_OK) { + log_e("Failed to set physical closed limit lift: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_cluster_update_attr(window_covering_cluster, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_PHY_CLOSED_LIMIT_TILT_ID, (void *)&_physical_closed_limit_tilt); + if (ret != ESP_OK) { + log_e("Failed to set physical closed limit tilt: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; } // Callback for handling incoming messages and commands @@ -183,12 +226,13 @@ void ZigbeeWindowCovering::zbWindowCoveringMovementCmd(const esp_zb_zcl_window_c if (_current_lift_percentage != message->payload.percentage_lift_value) { _current_lift_percentage = message->payload.percentage_lift_value; goToLiftPercentage(_current_lift_percentage); + return; } - return; } else if (message->command == ESP_ZB_ZCL_CMD_WINDOW_COVERING_GO_TO_TILT_PERCENTAGE) { if (_current_tilt_percentage != message->payload.percentage_tilt_value) { _current_tilt_percentage = message->payload.percentage_tilt_value; goToTiltPercentage(_current_tilt_percentage); + return; } } else { log_w("Received message ignored. Command: %d not supported for Window Covering", message->command); @@ -229,80 +273,122 @@ void ZigbeeWindowCovering::stop() { } // Methods to control window covering from user application -void ZigbeeWindowCovering::setLiftPosition(uint16_t lift_position) { +bool ZigbeeWindowCovering::setLiftPosition(uint16_t lift_position) { + esp_zb_zcl_status_t ret = ESP_ZB_ZCL_STATUS_SUCCESS; // Update both lift attributes _current_lift_position = lift_position; _current_lift_percentage = ((lift_position - _installed_open_limit_lift) * 100) / (_installed_closed_limit_lift - _installed_open_limit_lift); - log_v("Updating window covering lift position to %d (%d%)", _current_lift_position, _current_lift_percentage); - // set lift state + esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_set_attribute_val( + ret = esp_zb_zcl_set_attribute_val( _endpoint, ESP_ZB_ZCL_CLUSTER_ID_WINDOW_COVERING, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_CURRENT_POSITION_LIFT_ID, &_current_lift_position, false ); - esp_zb_zcl_set_attribute_val( + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set lift position: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + goto unlock_and_return; + } + ret = esp_zb_zcl_set_attribute_val( _endpoint, ESP_ZB_ZCL_CLUSTER_ID_WINDOW_COVERING, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_CURRENT_POSITION_LIFT_PERCENTAGE_ID, &_current_lift_percentage, false ); + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set lift percentage: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + goto unlock_and_return; + } +unlock_and_return: esp_zb_lock_release(); + return ret == ESP_ZB_ZCL_STATUS_SUCCESS; } -void ZigbeeWindowCovering::setLiftPercentage(uint8_t lift_percentage) { +bool ZigbeeWindowCovering::setLiftPercentage(uint8_t lift_percentage) { + esp_zb_zcl_status_t ret = ESP_ZB_ZCL_STATUS_SUCCESS; // Update both lift attributes _current_lift_percentage = lift_percentage; _current_lift_position = _installed_open_limit_lift + ((_installed_closed_limit_lift - _installed_open_limit_lift) * lift_percentage) / 100; + log_v("Updating window covering lift percentage to %d%% (%d)", _current_lift_percentage, _current_lift_position); - log_v("Updating window covering lift position to %d (%d%)", _current_lift_position, _current_lift_percentage); - // set lift state esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_set_attribute_val( + ret = esp_zb_zcl_set_attribute_val( _endpoint, ESP_ZB_ZCL_CLUSTER_ID_WINDOW_COVERING, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_CURRENT_POSITION_LIFT_ID, &_current_lift_position, false ); - esp_zb_zcl_set_attribute_val( + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set lift position: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + goto unlock_and_return; + } + ret = esp_zb_zcl_set_attribute_val( _endpoint, ESP_ZB_ZCL_CLUSTER_ID_WINDOW_COVERING, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_CURRENT_POSITION_LIFT_PERCENTAGE_ID, &_current_lift_percentage, false ); + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set lift percentage: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + goto unlock_and_return; + } +unlock_and_return: esp_zb_lock_release(); + return ret == ESP_ZB_ZCL_STATUS_SUCCESS; } -void ZigbeeWindowCovering::setTiltPosition(uint16_t tilt_position) { +bool ZigbeeWindowCovering::setTiltPosition(uint16_t tilt_position) { + esp_zb_zcl_status_t ret = ESP_ZB_ZCL_STATUS_SUCCESS; // Update both tilt attributes _current_tilt_position = tilt_position; _current_tilt_percentage = ((tilt_position - _installed_open_limit_tilt) * 100) / (_installed_closed_limit_tilt - _installed_open_limit_tilt); log_v("Updating window covering tilt position to %d (%d%)", _current_tilt_position, _current_tilt_percentage); - // set lift state + esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_set_attribute_val( + ret = esp_zb_zcl_set_attribute_val( _endpoint, ESP_ZB_ZCL_CLUSTER_ID_WINDOW_COVERING, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_CURRENT_POSITION_TILT_ID, &_current_tilt_position, false ); - esp_zb_zcl_set_attribute_val( + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set tilt position: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + goto unlock_and_return; + } + ret = esp_zb_zcl_set_attribute_val( _endpoint, ESP_ZB_ZCL_CLUSTER_ID_WINDOW_COVERING, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_CURRENT_POSITION_TILT_PERCENTAGE_ID, &_current_tilt_percentage, false ); + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set tilt percentage: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + goto unlock_and_return; + } +unlock_and_return: esp_zb_lock_release(); + return ret == ESP_ZB_ZCL_STATUS_SUCCESS; } -void ZigbeeWindowCovering::setTiltPercentage(uint8_t tilt_percentage) { +bool ZigbeeWindowCovering::setTiltPercentage(uint8_t tilt_percentage) { + esp_zb_zcl_status_t ret = ESP_ZB_ZCL_STATUS_SUCCESS; // Update both tilt attributes _current_tilt_percentage = tilt_percentage; - _current_tilt_position = _installed_open_limit_lift + ((_installed_closed_limit_tilt - _installed_open_limit_tilt) * tilt_percentage) / 100; + _current_tilt_position = _installed_open_limit_tilt + ((_installed_closed_limit_tilt - _installed_open_limit_tilt) * tilt_percentage) / 100; + + log_v("Updating window covering tilt percentage to %d%% (%d)", _current_tilt_percentage, _current_tilt_position); - log_v("Updating window covering tilt position to %d (%d%)", _current_tilt_position, _current_tilt_percentage); - // set lift state esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_set_attribute_val( + ret = esp_zb_zcl_set_attribute_val( _endpoint, ESP_ZB_ZCL_CLUSTER_ID_WINDOW_COVERING, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_CURRENT_POSITION_TILT_ID, &_current_tilt_position, false ); - esp_zb_zcl_set_attribute_val( + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set tilt position: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + goto unlock_and_return; + } + ret = esp_zb_zcl_set_attribute_val( _endpoint, ESP_ZB_ZCL_CLUSTER_ID_WINDOW_COVERING, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_CURRENT_POSITION_TILT_PERCENTAGE_ID, &_current_tilt_percentage, false ); + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set tilt percentage: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + goto unlock_and_return; + } +unlock_and_return: esp_zb_lock_release(); + return ret == ESP_ZB_ZCL_STATUS_SUCCESS; } #endif // CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeWindowCovering.h b/libraries/Zigbee/src/ep/ZigbeeWindowCovering.h index f3a368370c4..288d92c5765 100644 --- a/libraries/Zigbee/src/ep/ZigbeeWindowCovering.h +++ b/libraries/Zigbee/src/ep/ZigbeeWindowCovering.h @@ -87,25 +87,25 @@ class ZigbeeWindowCovering : public ZigbeeEP { } // Set the window covering position in centimeters or percentage (0-100) - void setLiftPosition(uint16_t lift_position); - void setLiftPercentage(uint8_t lift_percentage); - void setTiltPosition(uint16_t tilt_position); - void setTiltPercentage(uint8_t tilt_percentage); + bool setLiftPosition(uint16_t lift_position); + bool setLiftPercentage(uint8_t lift_percentage); + bool setTiltPosition(uint16_t tilt_position); + bool setTiltPercentage(uint8_t tilt_percentage); // Set the window covering type (see ZigbeeWindowCoveringType) - void setCoveringType(ZigbeeWindowCoveringType covering_type); + bool setCoveringType(ZigbeeWindowCoveringType covering_type); // Set window covering config/status, for more info see esp_zb_zcl_window_covering_config_status_t - void setConfigStatus( + bool setConfigStatus( bool operational, bool online, bool commands_reversed, bool lift_closed_loop, bool tilt_closed_loop, bool lift_encoder_controlled, bool tilt_encoder_controlled ); // Set configuration mode of window covering, for more info see esp_zb_zcl_window_covering_mode_t - void setMode(bool motor_reversed, bool calibration_mode, bool maintenance_mode, bool leds_on); + bool setMode(bool motor_reversed, bool calibration_mode, bool maintenance_mode, bool leds_on); // Set limits of motion, for more info see esp_zb_zcl_window_covering_info_attr_t - void setLimits( + bool setLimits( uint16_t installed_open_limit_lift, uint16_t installed_closed_limit_lift, uint16_t installed_open_limit_tilt, uint16_t installed_closed_limit_tilt ); diff --git a/package/package_esp32_index.template.json b/package/package_esp32_index.template.json index 249ab43acc6..14aa8e9b4cf 100644 --- a/package/package_esp32_index.template.json +++ b/package/package_esp32_index.template.json @@ -26,13 +26,22 @@ "name": "ESP32 Dev Board" }, { - "name": "ESP32-S2 Dev Board" + "name": "ESP32-C3 Dev Board" }, { - "name": "ESP32-S3 Dev Board" + "name": "ESP32-C6 Dev Board" }, { - "name": "ESP32-C3 Dev Board" + "name": "ESP32-H2 Dev Board" + }, + { + "name": "ESP32-P4 Dev Board" + }, + { + "name": "ESP32-S2 Dev Board" + }, + { + "name": "ESP32-S3 Dev Board" }, { "name": "Arduino Nano ESP32" @@ -42,7 +51,7 @@ { "packager": "esp32", "name": "esp32-arduino-libs", - "version": "idf-release_v5.4-d4aa25a3-v1" + "version": "idf-release_v5.4-aed8bdc8-v1" }, { "packager": "esp32", @@ -67,7 +76,7 @@ { "packager": "esp32", "name": "openocd-esp32", - "version": "v0.12.0-esp32-20241016" + "version": "v0.12.0-esp32-20250422" }, { "packager": "esp32", @@ -95,63 +104,63 @@ "tools": [ { "name": "esp32-arduino-libs", - "version": "idf-release_v5.4-d4aa25a3-v1", + "version": "idf-release_v5.4-aed8bdc8-v1", "systems": [ { "host": "i686-mingw32", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.4/esp32-arduino-libs-idf-release_v5.4-d4aa25a3-v1.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.4-d4aa25a3-v1.zip", - "checksum": "SHA-256:81101d580ebafb78f71bd494f4f5162fd829279d18634282c0f8f95c9e928335", - "size": "350941396" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.4/esp32-arduino-libs-idf-release_v5.4-aed8bdc8-v1.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.4-aed8bdc8-v1.zip", + "checksum": "SHA-256:448691c3171f79b2136e4ab8006e9c78bd1627156dab1365fff8f8867a6a7e5b", + "size": "353758763" }, { "host": "x86_64-mingw32", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.4/esp32-arduino-libs-idf-release_v5.4-d4aa25a3-v1.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.4-d4aa25a3-v1.zip", - "checksum": "SHA-256:81101d580ebafb78f71bd494f4f5162fd829279d18634282c0f8f95c9e928335", - "size": "350941396" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.4/esp32-arduino-libs-idf-release_v5.4-aed8bdc8-v1.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.4-aed8bdc8-v1.zip", + "checksum": "SHA-256:448691c3171f79b2136e4ab8006e9c78bd1627156dab1365fff8f8867a6a7e5b", + "size": "353758763" }, { "host": "arm64-apple-darwin", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.4/esp32-arduino-libs-idf-release_v5.4-d4aa25a3-v1.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.4-d4aa25a3-v1.zip", - "checksum": "SHA-256:81101d580ebafb78f71bd494f4f5162fd829279d18634282c0f8f95c9e928335", - "size": "350941396" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.4/esp32-arduino-libs-idf-release_v5.4-aed8bdc8-v1.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.4-aed8bdc8-v1.zip", + "checksum": "SHA-256:448691c3171f79b2136e4ab8006e9c78bd1627156dab1365fff8f8867a6a7e5b", + "size": "353758763" }, { "host": "x86_64-apple-darwin", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.4/esp32-arduino-libs-idf-release_v5.4-d4aa25a3-v1.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.4-d4aa25a3-v1.zip", - "checksum": "SHA-256:81101d580ebafb78f71bd494f4f5162fd829279d18634282c0f8f95c9e928335", - "size": "350941396" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.4/esp32-arduino-libs-idf-release_v5.4-aed8bdc8-v1.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.4-aed8bdc8-v1.zip", + "checksum": "SHA-256:448691c3171f79b2136e4ab8006e9c78bd1627156dab1365fff8f8867a6a7e5b", + "size": "353758763" }, { "host": "x86_64-pc-linux-gnu", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.4/esp32-arduino-libs-idf-release_v5.4-d4aa25a3-v1.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.4-d4aa25a3-v1.zip", - "checksum": "SHA-256:81101d580ebafb78f71bd494f4f5162fd829279d18634282c0f8f95c9e928335", - "size": "350941396" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.4/esp32-arduino-libs-idf-release_v5.4-aed8bdc8-v1.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.4-aed8bdc8-v1.zip", + "checksum": "SHA-256:448691c3171f79b2136e4ab8006e9c78bd1627156dab1365fff8f8867a6a7e5b", + "size": "353758763" }, { "host": "i686-pc-linux-gnu", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.4/esp32-arduino-libs-idf-release_v5.4-d4aa25a3-v1.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.4-d4aa25a3-v1.zip", - "checksum": "SHA-256:81101d580ebafb78f71bd494f4f5162fd829279d18634282c0f8f95c9e928335", - "size": "350941396" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.4/esp32-arduino-libs-idf-release_v5.4-aed8bdc8-v1.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.4-aed8bdc8-v1.zip", + "checksum": "SHA-256:448691c3171f79b2136e4ab8006e9c78bd1627156dab1365fff8f8867a6a7e5b", + "size": "353758763" }, { "host": "aarch64-linux-gnu", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.4/esp32-arduino-libs-idf-release_v5.4-d4aa25a3-v1.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.4-d4aa25a3-v1.zip", - "checksum": "SHA-256:81101d580ebafb78f71bd494f4f5162fd829279d18634282c0f8f95c9e928335", - "size": "350941396" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.4/esp32-arduino-libs-idf-release_v5.4-aed8bdc8-v1.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.4-aed8bdc8-v1.zip", + "checksum": "SHA-256:448691c3171f79b2136e4ab8006e9c78bd1627156dab1365fff8f8867a6a7e5b", + "size": "353758763" }, { "host": "arm-linux-gnueabihf", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.4/esp32-arduino-libs-idf-release_v5.4-d4aa25a3-v1.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.4-d4aa25a3-v1.zip", - "checksum": "SHA-256:81101d580ebafb78f71bd494f4f5162fd829279d18634282c0f8f95c9e928335", - "size": "350941396" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.4/esp32-arduino-libs-idf-release_v5.4-aed8bdc8-v1.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.4-aed8bdc8-v1.zip", + "checksum": "SHA-256:448691c3171f79b2136e4ab8006e9c78bd1627156dab1365fff8f8867a6a7e5b", + "size": "353758763" } ] }, @@ -405,56 +414,56 @@ }, { "name": "openocd-esp32", - "version": "v0.12.0-esp32-20241016", + "version": "v0.12.0-esp32-20250422", "systems": [ { "host": "x86_64-pc-linux-gnu", - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20241016/openocd-esp32-linux-amd64-0.12.0-esp32-20241016.tar.gz", - "archiveFileName": "openocd-esp32-linux-amd64-0.12.0-esp32-20241016.tar.gz", - "checksum": "SHA-256:e82b0f036dc99244bead5f09a86e91bb2365cbcd1122ac68261e5647942485df", - "size": "2398717" + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20250422/openocd-esp32-linux-amd64-0.12.0-esp32-20250422.tar.gz", + "archiveFileName": "openocd-esp32-linux-amd64-0.12.0-esp32-20250422.tar.gz", + "checksum": "SHA-256:eb1fa9b21c65b45a2200af6dcc2914e32335d37b6dbbd181778dcc0dc025e70a", + "size": "2445546" }, { "host": "aarch64-linux-gnu", - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20241016/openocd-esp32-linux-arm64-0.12.0-esp32-20241016.tar.gz", - "archiveFileName": "openocd-esp32-linux-arm64-0.12.0-esp32-20241016.tar.gz", - "checksum": "SHA-256:8f8daf5bd22ec5d2fa9257b0862ec33da18ee677e023fb9a9eb17f74ce208c76", - "size": "2271584" + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20250422/openocd-esp32-linux-arm64-0.12.0-esp32-20250422.tar.gz", + "archiveFileName": "openocd-esp32-linux-arm64-0.12.0-esp32-20250422.tar.gz", + "checksum": "SHA-256:f70334a9b12a75b4d943e09fa5db30973037c39dbb54d6fa9f1a7118228b3d1c", + "size": "2330926" }, { "host": "arm-linux-gnueabihf", - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20241016/openocd-esp32-linux-armel-0.12.0-esp32-20241016.tar.gz", - "archiveFileName": "openocd-esp32-linux-armel-0.12.0-esp32-20241016.tar.gz", - "checksum": "SHA-256:bc9c020ecf20e2000f76cffa44305fd5bc44d2e688ea78cce423399d33f19767", - "size": "2414206" + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20250422/openocd-esp32-linux-armel-0.12.0-esp32-20250422.tar.gz", + "archiveFileName": "openocd-esp32-linux-armel-0.12.0-esp32-20250422.tar.gz", + "checksum": "SHA-256:4ac34d6fd1af86aeda87c8318732f8d691c300c285c7fd2f5037c432c63fbbb3", + "size": "2470732" }, { "host": "x86_64-apple-darwin", - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20241016/openocd-esp32-macos-0.12.0-esp32-20241016.tar.gz", - "archiveFileName": "openocd-esp32-macos-0.12.0-esp32-20241016.tar.gz", - "checksum": "SHA-256:02a2dffe801a2d005fa9e614d80ff8173395b2cb0b5d3118d0229d094a9946a7", - "size": "2508089" + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20250422/openocd-esp32-macos-0.12.0-esp32-20250422.tar.gz", + "archiveFileName": "openocd-esp32-macos-0.12.0-esp32-20250422.tar.gz", + "checksum": "SHA-256:9186a7a06304c6d9201cbce4ee3c7099b393bf8d329cda17a68874f92308f6ce", + "size": "2548730" }, { "host": "arm64-apple-darwin", - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20241016/openocd-esp32-macos-arm64-0.12.0-esp32-20241016.tar.gz", - "archiveFileName": "openocd-esp32-macos-arm64-0.12.0-esp32-20241016.tar.gz", - "checksum": "SHA-256:c382f9e884d6565cb6089bff5f200f4810994667d885f062c3d3c5625a0fa9d6", - "size": "2552569" + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20250422/openocd-esp32-macos-arm64-0.12.0-esp32-20250422.tar.gz", + "archiveFileName": "openocd-esp32-macos-arm64-0.12.0-esp32-20250422.tar.gz", + "checksum": "SHA-256:2cc39318d52f393233ff1f777871aebe5b97b3fbad29556a238489263401b774", + "size": "2593819" }, { "host": "i686-mingw32", - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20241016/openocd-esp32-win32-0.12.0-esp32-20241016.zip", - "archiveFileName": "openocd-esp32-win32-0.12.0-esp32-20241016.zip", - "checksum": "SHA-256:3b5d615e0a72cc771a45dd469031312d5881c01d7b6bc9edb29b8b6bda8c2e90", - "size": "2946244" + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20250422/openocd-esp32-win32-0.12.0-esp32-20250422.zip", + "archiveFileName": "openocd-esp32-win32-0.12.0-esp32-20250422.zip", + "checksum": "SHA-256:ecb4f8533fa9098d10000f5f7e8b8eaa8591015b824b481078ddb2b37e7aa6f2", + "size": "2988859" }, { "host": "x86_64-mingw32", - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20241016/openocd-esp32-win64-0.12.0-esp32-20241016.zip", - "archiveFileName": "openocd-esp32-win64-0.12.0-esp32-20241016.zip", - "checksum": "SHA-256:5e7b2fd1947d3a8625f6a11db7a2340cf2f41ff4c61284c022c7d7c32b18780a", - "size": "2946244" + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20250422/openocd-esp32-win64-0.12.0-esp32-20250422.zip", + "archiveFileName": "openocd-esp32-win64-0.12.0-esp32-20250422.zip", + "checksum": "SHA-256:e9eae8e1a8d0e030cd81dcb08394a9137cb7338a6211dfabcdbdfb37b58c5a23", + "size": "2988858" } ] }, diff --git a/tests/validation/i2c_master/i2c_master.ino b/tests/validation/i2c_master/i2c_master.ino index 9b4cc508a35..41e7d2ae5f9 100644 --- a/tests/validation/i2c_master/i2c_master.ino +++ b/tests/validation/i2c_master/i2c_master.ino @@ -162,7 +162,7 @@ void rtc_run_clock() { ds1307_get_time(&read_sec, &read_min, &read_hour, &read_day, &read_month, &read_year); //Check time - TEST_ASSERT_UINT8_WITHIN(2, start_sec + 5, read_sec); + TEST_ASSERT_NOT_EQUAL(start_sec, read_sec); //Seconds should have changed TEST_ASSERT_EQUAL(start_min, read_min); TEST_ASSERT_EQUAL(start_hour, read_hour); TEST_ASSERT_EQUAL(start_day, read_day); diff --git a/tests/validation/uart/diagram.esp32.json b/tests/validation/uart/diagram.esp32.json index a31c06d8313..c2fbd952fd0 100644 --- a/tests/validation/uart/diagram.esp32.json +++ b/tests/validation/uart/diagram.esp32.json @@ -6,7 +6,7 @@ { "type": "board-esp32-devkit-c-v4", "id": "esp", - "attrs": { "cpuFrequency": "40" } + "attrs": { "cpuFrequency": "120" } } ], "connections": [ diff --git a/tests/validation/uart/uart.ino b/tests/validation/uart/uart.ino index 358276c00b4..794fc9affc2 100644 --- a/tests/validation/uart/uart.ino +++ b/tests/validation/uart/uart.ino @@ -53,6 +53,8 @@ public: : uart_num(num), serial(serial_ref), peeked_char(-1), default_rx_pin(rx_pin), default_tx_pin(tx_pin), recv_msg("") {} void begin(unsigned long baudrate) { + // pinMode will force enabling the internal pullup resistor (IDF 5.3.2 Change) + pinMode(default_rx_pin, INPUT_PULLUP); serial.begin(baudrate, SERIAL_8N1, default_rx_pin, default_tx_pin); while (!serial) { delay(10); @@ -365,6 +367,8 @@ void change_pins_test(void) { if (TEST_UART_NUM == 1) { UARTTestConfig &config = *uart_test_configs[0]; + // pinMode will force enabling the internal pullup resistor (IDF 5.3.2 Change) + pinMode(NEW_RX1, INPUT_PULLUP); config.serial.setPins(NEW_RX1, NEW_TX1); TEST_ASSERT_EQUAL(NEW_RX1, uart_get_RxPin(config.uart_num)); TEST_ASSERT_EQUAL(NEW_TX1, uart_get_TxPin(config.uart_num)); diff --git a/tools/gen_esp32part.exe b/tools/gen_esp32part.exe index 5bd12c6360d..2e7b1001bb0 100644 Binary files a/tools/gen_esp32part.exe and b/tools/gen_esp32part.exe differ diff --git a/tools/gen_esp32part.py b/tools/gen_esp32part.py index ffa740a36e0..959b3188a0a 100755 --- a/tools/gen_esp32part.py +++ b/tools/gen_esp32part.py @@ -7,11 +7,8 @@ # See https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/partition-tables.html # for explanation of partition table structure and uses. # -# SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2016-2025 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Apache-2.0 - -from __future__ import division, print_function, unicode_literals - import argparse import binascii import errno @@ -22,26 +19,34 @@ import sys MAX_PARTITION_LENGTH = 0xC00 # 3K for partition data (96 entries) leaves 1K in a 4K sector for signature -MD5_PARTITION_BEGIN = b"\xEB\xEB" + b"\xFF" * 14 # The first 2 bytes are like magic numbers for MD5 sum +MD5_PARTITION_BEGIN = b"\xeb\xeb" + b"\xff" * 14 # The first 2 bytes are like magic numbers for MD5 sum PARTITION_TABLE_SIZE = 0x1000 # Size of partition table MIN_PARTITION_SUBTYPE_APP_OTA = 0x10 NUM_PARTITION_SUBTYPE_APP_OTA = 16 +MIN_PARTITION_SUBTYPE_APP_TEE = 0x30 +NUM_PARTITION_SUBTYPE_APP_TEE = 2 SECURE_NONE = None SECURE_V1 = "v1" SECURE_V2 = "v2" -__version__ = "1.2" +__version__ = "1.5" APP_TYPE = 0x00 DATA_TYPE = 0x01 +BOOTLOADER_TYPE = 0x02 +PARTITION_TABLE_TYPE = 0x03 TYPES = { + "bootloader": BOOTLOADER_TYPE, + "partition_table": PARTITION_TABLE_TYPE, "app": APP_TYPE, "data": DATA_TYPE, } +NVS_RW_MIN_PARTITION_SIZE = 0x3000 + def get_ptype_as_int(ptype): """Convert a string which might be numeric or the name of a partition type to an integer""" @@ -56,6 +61,15 @@ def get_ptype_as_int(ptype): # Keep this map in sync with esp_partition_subtype_t enum in esp_partition.h SUBTYPES = { + BOOTLOADER_TYPE: { + "primary": 0x00, + "ota": 0x01, + "recovery": 0x02, + }, + PARTITION_TABLE_TYPE: { + "primary": 0x00, + "ota": 0x01, + }, APP_TYPE: { "factory": 0x00, "test": 0x20, @@ -72,6 +86,7 @@ def get_ptype_as_int(ptype): "fat": 0x81, "spiffs": 0x82, "littlefs": 0x83, + "tee_ota": 0x90, }, } @@ -90,6 +105,8 @@ def get_subtype_as_int(ptype, subtype): ALIGNMENT = { APP_TYPE: 0x10000, DATA_TYPE: 0x1000, + BOOTLOADER_TYPE: 0x1000, + PARTITION_TABLE_TYPE: 0x1000, } @@ -98,14 +115,18 @@ def get_alignment_offset_for_type(ptype): def get_alignment_size_for_type(ptype): - if ptype == APP_TYPE and secure == SECURE_V1: - # For secure boot v1 case, app partition must be 64K aligned - # signature block (68 bytes) lies at the very end of 64K block - return 0x10000 - if ptype == APP_TYPE and secure == SECURE_V2: - # For secure boot v2 case, app partition must be 4K aligned - # signature block (4K) is kept after padding the unsigned image to 64K boundary - return 0x1000 + if ptype == APP_TYPE: + if secure == SECURE_V1: + # For secure boot v1 case, app partition must be 64K aligned + # signature block (68 bytes) lies at the very end of 64K block + return 0x10000 + elif secure == SECURE_V2: + # For secure boot v2 case, app partition must be 4K aligned + # signature block (4K) is kept after padding the unsigned image to 64K boundary + return 0x1000 + else: + # For no secure boot enabled case, app partition must be 4K aligned (min. flash erase size) + return 0x1000 # No specific size alignment requirement as such return 0x1 @@ -115,6 +136,10 @@ def get_partition_type(ptype): return APP_TYPE if ptype == "data": return DATA_TYPE + if ptype == "bootloader": + return BOOTLOADER_TYPE + if ptype == "partition_table": + return PARTITION_TABLE_TYPE raise InputError("Invalid partition type") @@ -134,6 +159,8 @@ def add_extra_subtypes(csv): md5sum = True secure = SECURE_NONE offset_part_table = 0 +primary_bootloader_offset = None +recovery_bootloader_offset = None def status(msg): @@ -165,7 +192,7 @@ def from_file(cls, f): return cls.from_csv(data), False @classmethod - def from_csv(cls, csv_contents): # noqa: C901 + def from_csv(cls, csv_contents): res = PartitionTable() lines = csv_contents.splitlines() @@ -194,6 +221,11 @@ def expand_vars(f): # fix up missing offsets & negative sizes last_end = offset_part_table + PARTITION_TABLE_SIZE # first offset after partition table for e in res: + is_primary_bootloader = e.type == BOOTLOADER_TYPE and e.subtype == SUBTYPES[e.type]["primary"] + is_primary_partition_table = e.type == PARTITION_TABLE_TYPE and e.subtype == SUBTYPES[e.type]["primary"] + if is_primary_bootloader or is_primary_partition_table: + # They do not participate in the restoration of missing offsets + continue if e.offset is not None and e.offset < last_end: if e == res[0]: raise InputError( @@ -203,8 +235,8 @@ def expand_vars(f): ) else: raise InputError( - "CSV Error at line %d: Partitions overlap. Partition sets offset 0x%x. Previous partition ends 0x%x" # noqa: E501 - % (e.line_no, e.offset, last_end) + "CSV Error at line %d: Partitions overlap. Partition sets offset 0x%x. " + "Previous partition ends 0x%x" % (e.line_no, e.offset, last_end) ) if e.offset is None: pad_to = get_alignment_offset_for_type(e.type) @@ -246,14 +278,14 @@ def find_by_name(self, name): return p return None - def verify(self): # noqa: C901 + def verify(self): # verify each partition individually for p in self: p.verify() # check on duplicate name names = [p.name for p in self] - duplicates = set(n for n in names if names.count(n) > 1) # noqa: C401 + duplicates = {n for n in names if names.count(n) > 1} # print sorted duplicate partitions by name if len(duplicates) != 0: @@ -267,9 +299,12 @@ def verify(self): # noqa: C901 last = None for p in sorted(self, key=lambda x: x.offset): if p.offset < offset_part_table + PARTITION_TABLE_SIZE: - raise InputError( - "Partition offset 0x%x is below 0x%x" % (p.offset, offset_part_table + PARTITION_TABLE_SIZE) - ) + is_primary_bootloader = p.type == BOOTLOADER_TYPE and p.subtype == SUBTYPES[p.type]["primary"] + is_primary_partition_table = p.type == PARTITION_TABLE_TYPE and p.subtype == SUBTYPES[p.type]["primary"] + if not (is_primary_bootloader or is_primary_partition_table): + raise InputError( + "Partition offset 0x%x is below 0x%x" % (p.offset, offset_part_table + PARTITION_TABLE_SIZE) + ) if last is not None and p.offset < last.offset + last.size: raise InputError( "Partition at 0x%x overlaps 0x%x-0x%x" % (p.offset, last.offset, last.offset + last.size - 1) @@ -282,7 +317,8 @@ def verify(self): # noqa: C901 for p in otadata_duplicates: critical("%s" % (p.to_csv())) raise InputError( - 'Found multiple otadata partitions. Only one partition can be defined with type="data"(1) and subtype="ota"(0).' # noqa: E501 + "Found multiple otadata partitions. Only one partition can be defined with " + 'type="data"(1) and subtype="ota"(0).' ) if len(otadata_duplicates) == 1 and otadata_duplicates[0].size != 0x2000: @@ -290,6 +326,23 @@ def verify(self): # noqa: C901 critical("%s" % (p.to_csv())) raise InputError("otadata partition must have size = 0x2000") + # Above checks but for TEE otadata + otadata_duplicates = [ + p for p in self if p.type == TYPES["data"] and p.subtype == SUBTYPES[DATA_TYPE]["tee_ota"] + ] + if len(otadata_duplicates) > 1: + for p in otadata_duplicates: + critical("%s" % (p.to_csv())) + raise InputError( + "Found multiple TEE otadata partitions. Only one partition can be defined with " + 'type="data"(1) and subtype="tee_ota"(0x90).' + ) + + if len(otadata_duplicates) == 1 and otadata_duplicates[0].size != 0x2000: + p = otadata_duplicates[0] + critical("%s" % (p.to_csv())) + raise InputError("TEE otadata partition must have size = 0x2000") + def flash_size(self): """Return the size that partitions will occupy in flash (ie the offset the last partition ends at) @@ -321,7 +374,7 @@ def from_binary(cls, b): data = b[o : o + 32] if len(data) != 32: raise InputError("Partition table length must be a multiple of 32 bytes") - if data == b"\xFF" * 32: + if data == b"\xff" * 32: return result # got end marker if md5sum and data[:2] == MD5_PARTITION_BEGIN[:2]: # check only the magic number part if data[16:] == md5.digest(): @@ -342,7 +395,7 @@ def to_binary(self): result += MD5_PARTITION_BEGIN + hashlib.md5(result).digest() if len(result) >= MAX_PARTITION_LENGTH: raise InputError("Binary partition table length (%d) longer than max" % len(result)) - result += b"\xFF" * (MAX_PARTITION_LENGTH - len(result)) # pad the sector, for signing + result += b"\xff" * (MAX_PARTITION_LENGTH - len(result)) # pad the sector, for signing return result def to_csv(self, simple_formatting=False): @@ -352,16 +405,20 @@ def to_csv(self, simple_formatting=False): class PartitionDefinition(object): - MAGIC_BYTES = b"\xAA\x50" + MAGIC_BYTES = b"\xaa\x50" # dictionary maps flag name (as used in CSV flags list, property name) # to bit set in flags words in binary format - FLAGS = {"encrypted": 0} + FLAGS = {"encrypted": 0, "readonly": 1} # add subtypes for the 16 OTA slot values ("ota_XX, etc.") for ota_slot in range(NUM_PARTITION_SUBTYPE_APP_OTA): SUBTYPES[TYPES["app"]]["ota_%d" % ota_slot] = MIN_PARTITION_SUBTYPE_APP_OTA + ota_slot + # add subtypes for the 2 TEE OTA slot values ("tee_XX, etc.") + for tee_slot in range(NUM_PARTITION_SUBTYPE_APP_TEE): + SUBTYPES[TYPES["app"]]["tee_%d" % tee_slot] = MIN_PARTITION_SUBTYPE_APP_TEE + tee_slot + def __init__(self): self.name = "" self.type = None @@ -369,6 +426,7 @@ def __init__(self): self.offset = None self.size = None self.encrypted = False + self.readonly = False @classmethod def from_csv(cls, line, line_no): @@ -381,8 +439,8 @@ def from_csv(cls, line, line_no): res.name = fields[0] res.type = res.parse_type(fields[1]) res.subtype = res.parse_subtype(fields[2]) - res.offset = res.parse_address(fields[3]) - res.size = res.parse_address(fields[4]) + res.offset = res.parse_address(fields[3], res.type, res.subtype) + res.size = res.parse_size(fields[4], res.type) if res.size is None: raise InputError("Size field can't be empty") @@ -452,12 +510,36 @@ def parse_subtype(self, strval): return SUBTYPES[DATA_TYPE]["undefined"] return parse_int(strval, SUBTYPES.get(self.type, {})) - def parse_address(self, strval): + def parse_size(self, strval, ptype): + if ptype == BOOTLOADER_TYPE: + if primary_bootloader_offset is None: + raise InputError("Primary bootloader offset is not defined. Please use --primary-bootloader-offset") + return offset_part_table - primary_bootloader_offset + if ptype == PARTITION_TABLE_TYPE: + return PARTITION_TABLE_SIZE if strval == "": return None # PartitionTable will fill in default return parse_int(strval) - def verify(self): # noqa: C901 + def parse_address(self, strval, ptype, psubtype): + if ptype == BOOTLOADER_TYPE: + if psubtype == SUBTYPES[ptype]["primary"]: + if primary_bootloader_offset is None: + raise InputError("Primary bootloader offset is not defined. Please use --primary-bootloader-offset") + return primary_bootloader_offset + if psubtype == SUBTYPES[ptype]["recovery"]: + if recovery_bootloader_offset is None: + raise InputError( + "Recovery bootloader offset is not defined. Please use --recovery-bootloader-offset" + ) + return recovery_bootloader_offset + if ptype == PARTITION_TABLE_TYPE and psubtype == SUBTYPES[ptype]["primary"]: + return offset_part_table + if strval == "": + return None # PartitionTable will fill in default + return parse_int(strval) + + def verify(self): if self.type is None: raise ValidationError(self, "Type field is not set") if self.subtype is None: @@ -469,7 +551,7 @@ def verify(self): # noqa: C901 offset_align = get_alignment_offset_for_type(self.type) if self.offset % offset_align: raise ValidationError(self, "Offset 0x%x is not aligned to 0x%x" % (self.offset, offset_align)) - if self.type == APP_TYPE and secure is not SECURE_NONE: + if self.type == APP_TYPE: size_align = get_alignment_size_for_type(self.type) if self.size % size_align: raise ValidationError(self, "Size 0x%x is not aligned to 0x%x" % (self.size, size_align)) @@ -489,6 +571,23 @@ def verify(self): # noqa: C901 % (self.name, self.type, self.subtype) ) + always_rw_data_subtypes = [SUBTYPES[DATA_TYPE]["ota"], SUBTYPES[DATA_TYPE]["coredump"]] + if self.type == TYPES["data"] and self.subtype in always_rw_data_subtypes and self.readonly is True: + raise ValidationError( + self, + "'%s' partition of type %s and subtype %s is always read-write and cannot be read-only" + % (self.name, self.type, self.subtype), + ) + + if self.type == TYPES["data"] and self.subtype == SUBTYPES[DATA_TYPE]["nvs"]: + if self.size < NVS_RW_MIN_PARTITION_SIZE and self.readonly is False: + raise ValidationError( + self, + """'%s' partition of type %s and subtype %s of this size (0x%x) must be flagged as 'readonly' \ +(the size of read/write NVS has to be at least 0x%x)""" + % (self.name, self.type, self.subtype, self.size, NVS_RW_MIN_PARTITION_SIZE), + ) + STRUCT_FORMAT = b"<2sBBLL16sL" @classmethod @@ -574,11 +673,13 @@ def parse_int(v, keywords={}): raise InputError("Value '%s' is not valid. Known keywords: %s" % (v, ", ".join(keywords))) -def main(): # noqa: C901 +def main(): global quiet global md5sum global offset_part_table global secure + global primary_bootloader_offset + global recovery_bootloader_offset parser = argparse.ArgumentParser(description="ESP32 partition table utility") parser.add_argument( @@ -600,6 +701,8 @@ def main(): # noqa: C901 ) parser.add_argument("--quiet", "-q", help="Don't print non-critical status messages to stderr", action="store_true") parser.add_argument("--offset", "-o", help="Set offset partition table", default="0x8000") + parser.add_argument("--primary-bootloader-offset", help="Set primary bootloader offset", default=None) + parser.add_argument("--recovery-bootloader-offset", help="Set recovery bootloader offset", default=None) parser.add_argument( "--secure", help="Require app partitions to be suitable for secure boot", @@ -622,6 +725,15 @@ def main(): # noqa: C901 md5sum = not args.disable_md5sum secure = args.secure offset_part_table = int(args.offset, 0) + if args.primary_bootloader_offset is not None: + primary_bootloader_offset = int(args.primary_bootloader_offset, 0) + if primary_bootloader_offset >= offset_part_table: + raise InputError( + f"Unsupported configuration. Primary bootloader must be below partition table. " + f"Check --primary-bootloader-offset={primary_bootloader_offset:#x} and --offset={offset_part_table:#x}" + ) + if args.recovery_bootloader_offset is not None: + recovery_bootloader_offset = int(args.recovery_bootloader_offset, 0) if args.extra_partition_subtypes: add_extra_subtypes(args.extra_partition_subtypes) @@ -647,7 +759,7 @@ def main(): # noqa: C901 if input_is_binary: output = table.to_csv() - with sys.stdout if args.output == "-" else open(args.output, "w") as f: + with sys.stdout if args.output == "-" else open(args.output, "w", encoding="utf-8") as f: f.write(output) else: output = table.to_binary() diff --git a/tools/partitions/default_32MB.csv b/tools/partitions/default_32MB.csv new file mode 100644 index 00000000000..dd07ac32185 --- /dev/null +++ b/tools/partitions/default_32MB.csv @@ -0,0 +1,7 @@ +# Name, Type, SubType, Offset, Size, Flags +nvs, data, nvs, 0x9000, 0x5000, +otadata, data, ota, 0xe000, 0x2000, +app0, app, ota_0, 0x10000, 0xC80000, +app1, app, ota_1, 0xC90000,0xC80000, +spiffs, data, spiffs, 0x1910000,0x6C0000, +coredump, data, coredump,0x1FF0000,0x10000, diff --git a/tools/partitions/rainmaker_8MB.csv b/tools/partitions/rainmaker_8MB.csv index 6d65333063f..6bad399968c 100644 --- a/tools/partitions/rainmaker_8MB.csv +++ b/tools/partitions/rainmaker_8MB.csv @@ -1,7 +1,7 @@ # Name, Type, SubType, Offset, Size, Flags nvs, data, nvs, 0x9000, 0x5000, otadata, data, ota, 0xe000, 0x2000, -ota_0, app, ota_0, 0x10000, 0x3ED000, -ota_1, app, ota_1, 0x3FD000, 0x3ED000, +ota_0, app, ota_0, 0x10000, 0x3EA000, +ota_1, app, ota_1, 0x400000, 0x3EA000, fctry, data, nvs, 0x7EA000, 0x6000, coredump, data, coredump,0x7F0000, 0x10000, diff --git a/variants/adafruit_sparklemotionstick_esp32/pins_arduino.h b/variants/adafruit_sparklemotionstick_esp32/pins_arduino.h new file mode 100644 index 00000000000..e0d94821736 --- /dev/null +++ b/variants/adafruit_sparklemotionstick_esp32/pins_arduino.h @@ -0,0 +1,40 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include +#include "soc/soc_caps.h" + +// User LED +static const uint8_t LED_BUILTIN = 4; +#define BUILTIN_LED LED_BUILTIN // backward compatibility +#define LED_BUILTIN LED_BUILTIN // allow testing #ifdef LED_BUILTIN + +// Neopixel +static const uint8_t PIN_NEOPIXEL = 18; +// RGB_BUILTIN and RGB_BRIGHTNESS can be used in new Arduino API rgbLedWrite() and digitalWrite() for blinking +#define RGB_BUILTIN (PIN_NEOPIXEL + SOC_GPIO_PIN_COUNT) +#define RGB_BRIGHTNESS 64 + +static const uint8_t TX = 25; // not broken out, defined to fix compilation +static const uint8_t RX = 26; // not broken out, defined to fix compilation + +#define TX1 TX +#define RX1 RX + +static const uint8_t SDA = 13; // not broken out, defined to fix compilation +static const uint8_t SCL = 15; // not broken out, defined to fix compilation + +static const uint8_t SS = 19; // not broken out, defined to fix compilation +static const uint8_t MOSI = 21; // output to drive dotstars +static const uint8_t SCK = 22; // output to drive dotstars +static const uint8_t MISO = 23; // not broken out, defined to fix compilation + +static const uint8_t A0 = 2; // not broken out, defined to fix compilation + +// internal switch +static const uint8_t BUTTON = 0; + +static const uint8_t DAC1 = 25; // not broken out, defined to fix compilation +static const uint8_t DAC2 = 26; // not broken out, defined to fix compilation + +#endif /* Pins_Arduino_h */ diff --git a/variants/alfredo-nou3/pins_arduino.h b/variants/alfredo-nou3/pins_arduino.h index 88bdbea0bb1..8b5a7d51b9f 100644 --- a/variants/alfredo-nou3/pins_arduino.h +++ b/variants/alfredo-nou3/pins_arduino.h @@ -1,6 +1,7 @@ #ifndef Pins_Arduino_h #define Pins_Arduino_h +#include #define USB_VID 0xAFD0 #define USB_PID 0x0003 #define USB_MANUFACTURER "Alfredo" diff --git a/variants/dfrobot_lorawan_esp32s3/pins_arduino.h b/variants/dfrobot_lorawan_esp32s3/pins_arduino.h new file mode 100644 index 00000000000..c690cac069f --- /dev/null +++ b/variants/dfrobot_lorawan_esp32s3/pins_arduino.h @@ -0,0 +1,34 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include + +#define LED_BUILTIN 21 + +static const uint8_t TX = 43; +static const uint8_t RX = 44; + +static const uint8_t SDA = 8; +static const uint8_t SCL = 9; + +#define LORA_ANTPWR 42 //RXEN +#define LORA_RST 41 //RST +#define LORA_BUSY 40 //BUSY +#define LORA_DIO1 4 //DIO + +static const uint8_t LORA_SS = 10; +static const uint8_t LORA_MOSI = 6; +static const uint8_t LORA_MISO = 5; +static const uint8_t LORA_SCK = 7; + +static const uint8_t SS = 17; +static const uint8_t MOSI = 11; +static const uint8_t MISO = 13; +static const uint8_t SCK = 12; + +#define TFT_DC 14 +#define TFT_CS 17 +#define TFT_RST 15 +#define TFT_BL 16 // Backlight pin + +#endif /* Pins_Arduino_h */ diff --git a/variants/esp32s3usbotg/pins_arduino.h b/variants/esp32s3usbotg/pins_arduino.h index 004055cde49..5b873e2d2f1 100644 --- a/variants/esp32s3usbotg/pins_arduino.h +++ b/variants/esp32s3usbotg/pins_arduino.h @@ -2,6 +2,7 @@ #define Pins_Arduino_h #include +#include #define USB_VID 0x303a #define USB_PID 0x1001 diff --git a/variants/lilygo_tlora_pager/pins_arduino.h b/variants/lilygo_tlora_pager/pins_arduino.h new file mode 100644 index 00000000000..fb57b5d493f --- /dev/null +++ b/variants/lilygo_tlora_pager/pins_arduino.h @@ -0,0 +1,102 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include + +#ifndef digitalPinToInterrupt +#define digitalPinToInterrupt(p) (((p) < 48) ? (p) : -1) +#endif + +#define USB_VID 0x303a +#define USB_PID 0x82D4 +#define USB_MANUFACTURER "LILYGO" +#define USB_PRODUCT "T-LoRa-Pager" + +// ST7796 +#define DISP_WIDTH (222) +#define DISP_HEIGHT (480) +#define SD_CS (21) + +static const uint8_t TX = 43; +static const uint8_t RX = 44; + +// BHI260,PCF85063,BQ25896,DRV2605L,ES8311 share I2C Bus +static const uint8_t SDA = 3; +static const uint8_t SCL = 2; + +// Default sd cs pin +static const uint8_t SS = SD_CS; +static const uint8_t MOSI = 34; +static const uint8_t MISO = 33; +static const uint8_t SCK = 35; + +#define KB_INT (6) +#define KB_BACKLIGHT (46) + +// Rotary +#define ROTARY_A (40) +#define ROTARY_B (41) +#define ROTARY_C (7) + +// Interrupt IO port +#define RTC_INT (1) +#define NFC_INT (5) +#define SENSOR_INT (8) +#define NFC_CS (39) + +// ES8311 +#define I2S_WS (18) +#define I2S_SCK (11) +#define I2S_MCLK (10) +#define I2S_SDOUT (45) +#define I2S_SDIN (17) + +// GPS +#define GPS_TX (12) +#define GPS_RX (4) +#define GPS_PPS (13) + +// LoRa, SD, ST25R3916 card share SPI bus +#define LORA_SCK (SCK) // share spi bus +#define LORA_MISO (MISO) // share spi bus +#define LORA_MOSI (MOSI) // share spi bus +#define LORA_CS (36) +#define LORA_RST (47) +#define LORA_BUSY (48) +#define LORA_IRQ (14) + +// SPI interface display +#define DISP_MOSI (MOSI) +#define DISP_MISO (MISO) +#define DISP_SCK (SCK) +#define DISP_RST (-1) +#define DISP_CS (38) +#define DISP_DC (37) +#define DISP_BL (42) + +// External expansion chip IO definition +#define EXPANDS_DRV_EN (0) +#define EXPANDS_AMP_EN (1) +#define EXPANDS_KB_RST (2) +#define EXPANDS_LORA_EN (3) +#define EXPANDS_GPS_EN (4) +#define EXPANDS_NFC_EN (5) +#define EXPANDS_GPS_RST (7) +#define EXPANDS_KB_EN (8) +#define EXPANDS_GPIO_EN (9) +#define EXPANDS_SD_DET (10) +#define EXPANDS_SD_PULLEN (11) +#define EXPANDS_SD_EN (12) + +// Peripheral definition exists +#define USING_AUDIO_CODEC +#define USING_XL9555_EXPANDS +#define USING_PPM_MANAGE +#define USING_BQ_GAUGE +#define USING_INPUT_DEV_ROTARY +#define USING_INPUT_DEV_KEYBOARD +#define USING_ST25R3916 +#define USING_BHI260_SENSOR +#define HAS_SD_CARD_SOCKET + +#endif /* Pins_Arduino_h */ diff --git a/variants/lilygo_twatch_s3/pins_arduino.h b/variants/lilygo_twatch_s3/pins_arduino.h index 59434161d98..05543de27c5 100644 --- a/variants/lilygo_twatch_s3/pins_arduino.h +++ b/variants/lilygo_twatch_s3/pins_arduino.h @@ -44,7 +44,7 @@ static const uint8_t TX = 42; static const uint8_t RX = 41; -//BHI260,PCF85063,AXP2101,DRV2605L,PN532 share I2C Bus +// BMA423,PCF8563,AXP2101,DRV2605L share I2C Bus static const uint8_t SDA = 10; static const uint8_t SCL = 11; @@ -66,4 +66,11 @@ static const uint8_t SCK = 3; #define GPS_TX (TX) #define GPS_RX (RX) +// Peripheral definition exists +#define USING_PCM_AMPLIFIER +#define USING_PDM_MICROPHONE +#define USING_PMU_MANAGE +#define USING_INPUT_DEV_TOUCHPAD +#define USING_IR_REMOTE + #endif /* Pins_Arduino_h */ diff --git a/variants/lilygo_twatch_ultra/pins_arduino.h b/variants/lilygo_twatch_ultra/pins_arduino.h index 57f6c2c3fea..91797e687fa 100644 --- a/variants/lilygo_twatch_ultra/pins_arduino.h +++ b/variants/lilygo_twatch_ultra/pins_arduino.h @@ -12,27 +12,26 @@ #define USB_MANUFACTURER "LILYGO" #define USB_PRODUCT "T-Watch-Ultra" -#define DISP_WIDTH (240) -#define DISP_HEIGHT (296) - -#define DISP_D0 (39) -#define DISP_D1 (40) -#define DISP_D2 (45) -#define DISP_D3 (42) -#define DISP_SCK (41) -#define DISP_RST (6) -#define DISP_CS (38) -#define DISP_TE (37) - -// touch screen -#define TP_INT (12) -#define TP_RST (46) +#define DISP_WIDTH 502 +#define DISP_HEIGHT 410 + +// QSPI interface display +#define DISP_D0 (38) +#define DISP_D1 (39) +#define DISP_D2 (42) +#define DISP_D3 (45) +#define DISP_SCK (40) +#define DISP_CS (41) +#define DISP_RST (37) +#define DISP_TE (6) + // Interrupt IO port +#define TP_INT (12) #define RTC_INT (1) #define PMU_INT (7) #define NFC_INT (5) #define SENSOR_INT (8) -#define NFC_RST (4) +#define NFC_CS (4) // PDM microphone #define MIC_SCK (17) @@ -49,9 +48,9 @@ static const uint8_t TX = 43; static const uint8_t RX = 44; -//BHI260,PCF85063,AXP2101,DRV2605L,PN532 share I2C Bus -static const uint8_t SDA = 2; -static const uint8_t SCL = 3; +// BHI260,PCF85063,AXP2101,DRV2605L share I2C Bus +static const uint8_t SDA = 3; +static const uint8_t SCL = 2; // Default sd cs pin static const uint8_t SS = SD_CS; @@ -59,8 +58,9 @@ static const uint8_t MOSI = 34; static const uint8_t MISO = 33; static const uint8_t SCK = 35; -#define GPS_TX (TX) -#define GPS_RX (RX) +#define GPS_TX (TX) +#define GPS_RX (RX) +#define GPS_PPS (13) #define TP_SDA (SDA) #define TP_SCL (SCL) @@ -74,4 +74,20 @@ static const uint8_t SCK = 35; #define LORA_BUSY (48) #define LORA_IRQ (14) +// External expansion chip IO definition +#define EXPANDS_DRV_EN (6) +#define EXPANDS_DISP_EN (7) +#define EXPANDS_TOUCH_RST (8) +#define EXPANDS_SD_DET (10) + +// Peripheral definition exists +#define USING_XL9555_EXPANDS +#define USING_PCM_AMPLIFIER +#define USING_PDM_MICROPHONE +#define USING_PMU_MANAGE +#define USING_INPUT_DEV_TOUCHPAD +#define USING_ST25R3916 +#define USING_BHI260_SENSOR +#define HAS_SD_CARD_SOCKET + #endif /* Pins_Arduino_h */ diff --git a/variants/lolin_c3_mini/pins_arduino.h b/variants/lolin_c3_mini/pins_arduino.h index c7357975ac7..0236f02267d 100644 --- a/variants/lolin_c3_mini/pins_arduino.h +++ b/variants/lolin_c3_mini/pins_arduino.h @@ -2,10 +2,18 @@ #define Pins_Arduino_h #include +#include "soc/soc_caps.h" -static const uint8_t LED_BUILTIN = 7; +// based on https://www.wemos.cc/en/latest/c3/c3_mini.html +// WS2812 RGB LED on pin 7 +#define PIN_RGB_LED 7 +// BUILTIN_LED can be used in new Arduino API digitalWrite() like in Blink.ino +static const uint8_t LED_BUILTIN = SOC_GPIO_PIN_COUNT + PIN_RGB_LED; #define BUILTIN_LED LED_BUILTIN // backward compatibility #define LED_BUILTIN LED_BUILTIN // allow testing #ifdef LED_BUILTIN +// RGB_BUILTIN and RGB_BRIGHTNESS can be used in new Arduino API rgbLedWrite() +#define RGB_BUILTIN LED_BUILTIN +#define RGB_BRIGHTNESS 64 static const uint8_t TX = 21; static const uint8_t RX = 20; diff --git a/variants/lolin_c3_pico/pins_arduino.h b/variants/lolin_c3_pico/pins_arduino.h index 8d4cfc5c4f0..45087c3f9fc 100644 --- a/variants/lolin_c3_pico/pins_arduino.h +++ b/variants/lolin_c3_pico/pins_arduino.h @@ -4,10 +4,18 @@ #define Pins_Arduino_h #include +#include "soc/soc_caps.h" -static const uint8_t LED_BUILTIN = 7; +// based on https://www.wemos.cc/en/latest/c3/c3_pico.html +// WS2812 RGB LED on pin 7 +#define PIN_RGB_LED 7 +// BUILTIN_LED can be used in new Arduino API digitalWrite() like in Blink.ino +static const uint8_t LED_BUILTIN = SOC_GPIO_PIN_COUNT + PIN_RGB_LED; #define BUILTIN_LED LED_BUILTIN // backward compatibility #define LED_BUILTIN LED_BUILTIN // allow testing #ifdef LED_BUILTIN +// RGB_BUILTIN and RGB_BRIGHTNESS can be used in new Arduino API rgbLedWrite() +#define RGB_BUILTIN LED_BUILTIN +#define RGB_BRIGHTNESS 64 static const uint8_t TX = 21; static const uint8_t RX = 20; @@ -17,7 +25,7 @@ static const uint8_t SCL = 10; static const uint8_t VBAT = 3; -static const uint8_t SCK = 2; +static const uint8_t SCK = 1; static const uint8_t MISO = 0; static const uint8_t MOSI = 4; static const uint8_t SS = 5; diff --git a/variants/um_edges3_d/pins_arduino.h b/variants/um_edges3_d/pins_arduino.h new file mode 100644 index 00000000000..f54ceb52ea7 --- /dev/null +++ b/variants/um_edges3_d/pins_arduino.h @@ -0,0 +1,46 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include +#include "soc/soc_caps.h" + +#define USB_VID 0x303A +#define USB_PID 0x82DC +#define USB_MANUFACTURER "Unexpected Maker" +#define USB_PRODUCT "EdgeS3[D]" +#define USB_SERIAL "" + +static const uint8_t TX = 43; +static const uint8_t RX = 44; + +static const uint8_t SDA = 8; +static const uint8_t SCL = 9; + +static const uint8_t SS = 34; +static const uint8_t MOSI = 35; +static const uint8_t MISO = 37; +static const uint8_t SDO = 35; +static const uint8_t SDI = 37; +static const uint8_t SCK = 36; + +static const uint8_t A0 = 1; +static const uint8_t A1 = 2; +static const uint8_t A2 = 3; +static const uint8_t A3 = 4; +static const uint8_t A4 = 5; +static const uint8_t A5 = 6; +static const uint8_t A6 = 7; +static const uint8_t A7 = 8; +static const uint8_t A8 = 9; + +static const uint8_t T1 = 1; +static const uint8_t T2 = 2; +static const uint8_t T3 = 3; +static const uint8_t T4 = 4; +static const uint8_t T5 = 5; +static const uint8_t T6 = 6; +static const uint8_t T7 = 7; +static const uint8_t T8 = 8; +static const uint8_t T9 = 9; + +#endif /* Pins_Arduino_h */ diff --git a/variants/um_squixl/pins_arduino.h b/variants/um_squixl/pins_arduino.h new file mode 100644 index 00000000000..4546cdb124a --- /dev/null +++ b/variants/um_squixl/pins_arduino.h @@ -0,0 +1,23 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include +#include "soc/soc_caps.h" + +#define USB_VID 0x303A +#define USB_PID 0x82DF +#define USB_MANUFACTURER "Unexpected Maker" +#define USB_PRODUCT "SQUiXL" +#define USB_SERIAL "" + +static const uint8_t SDA = 1; +static const uint8_t SCL = 2; + +static const uint8_t SS = 42; +static const uint8_t MOSI = 46; +static const uint8_t MISO = 41; +static const uint8_t SDO = 46; +static const uint8_t SDI = 41; +static const uint8_t SCK = 45; + +#endif /* Pins_Arduino_h */ diff --git a/variants/yb_esp32s3_drv/pins_arduino.h b/variants/yb_esp32s3_drv/pins_arduino.h new file mode 100644 index 00000000000..06de47e50f4 --- /dev/null +++ b/variants/yb_esp32s3_drv/pins_arduino.h @@ -0,0 +1,60 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include + +#define USB_VID 0x303A +#define USB_PID 0x1001 + +static const uint8_t LED_BUILTIN = 47; +#define BUILTIN_LED LED_BUILTIN // backward compatibility +#define LED_BUILTIN LED_BUILTIN // allow testing #ifdef LED_BUILTIN + +static const uint8_t TX = 43; +static const uint8_t RX = 44; + +static const uint8_t SDA = 8; +static const uint8_t SCL = 9; + +static const uint8_t SS = 10; +static const uint8_t MOSI = 11; +static const uint8_t MISO = 13; +static const uint8_t SCK = 12; + +// 2 connectors (X, Y) with 4 driver channels each +static const uint8_t X1 = 35; +static const uint8_t X2 = 36; +static const uint8_t X3 = 37; +static const uint8_t X4 = 38; +static const uint8_t Y1 = 4; +static const uint8_t Y2 = 5; +static const uint8_t Y3 = 6; +static const uint8_t Y4 = 7; + +static const uint8_t A0 = 1; +static const uint8_t A1 = 2; +static const uint8_t A2 = 3; +static const uint8_t A3 = 8; +static const uint8_t A4 = 9; +static const uint8_t A5 = 10; +static const uint8_t A6 = 11; +static const uint8_t A7 = 12; +static const uint8_t A8 = 13; +static const uint8_t A9 = 14; +static const uint8_t A10 = 15; +static const uint8_t A11 = 16; +static const uint8_t A12 = 17; +static const uint8_t A13 = 18; + +static const uint8_t T1 = 1; +static const uint8_t T2 = 2; +static const uint8_t T3 = 3; +static const uint8_t T8 = 8; +static const uint8_t T9 = 9; +static const uint8_t T10 = 10; +static const uint8_t T11 = 11; +static const uint8_t T12 = 12; +static const uint8_t T13 = 13; +static const uint8_t T14 = 14; + +#endif /* Pins_Arduino_h */