Merge branch 'espressif:master' into master

This commit is contained in:
Tyeth Gundry 2025-07-22 21:48:17 +01:00 committed by GitHub
commit c5d2b1d242
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
263 changed files with 16118 additions and 1274 deletions

80
.github/CODEOWNERS vendored Normal file
View file

@ -0,0 +1,80 @@
# CODEOWNERS for ESP32 Arduino Core
# This file is used to specify the code owners for the ESP32 Arduino Core.
# Read more about CODEOWNERS:
# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners
# Note that order matters. The last matching pattern will be used.
# The default owners are the active developers of the ESP32 Arduino Core.
# Refrain from using @espressif/arduino-esp32 to avoid spamming non-developers with review requests.
* @espressif/arduino-devs
# CI
/.github/ @lucasssvaz @me-no-dev @P-R-O-C-H-Y
/.gitlab/ @lucasssvaz
/tests/ @lucasssvaz @P-R-O-C-H-Y
# Tools
/tools/ @me-no-dev
/tools/pre-commit/ @lucasssvaz
/tools/add_lib.sh @P-R-O-C-H-Y
# Pre-commit
/.* @lucasssvaz # Files in root directory that start with a dot.
# Git Files
/.gitignore @espressif/arduino-devs
/.gitmodules @espressif/arduino-devs
# Documentation
/docs/ @pedrominatel
/.github/ISSUE_TEMPLATE/ @pedrominatel
/.github/PULL_REQUEST_TEMPLATE.md @pedrominatel
/.readthedocs.yaml @pedrominatel
/*.md @pedrominatel
# Boards
/variants/ @P-R-O-C-H-Y
/boards.txt @P-R-O-C-H-Y
# Arduino as Component
/idf_component_examples/ @SuGlider
/idf_component.yml @SuGlider @me-no-dev
/CMakeLists.txt @SuGlider @me-no-dev
/Kconfig.projbuild @SuGlider @me-no-dev
# Build System
/package.json @me-no-dev
/platform.txt @me-no-dev
/programmers.txt @me-no-dev
/package/ @me-no-dev
# Libraries
/libraries/ArduinoOTA/ @me-no-dev
/libraries/AsyncUDP/ @me-no-dev
/libraries/BLE/ @lucasssvaz @SuGlider
/libraries/ESP_I2S/ @me-no-dev
/libraries/ESP_NOW/ @P-R-O-C-H-Y @lucasssvaz
/libraries/ESP_SR/ @me-no-dev
/libraries/ESPmDNS/ @me-no-dev
/libraries/Ethernet/ @me-no-dev
/libraries/Matter/ @SuGlider
/libraries/NetBIOS/ @me-no-dev
/libraries/Network/ @me-no-dev
/libraries/OpenThread/ @SuGlider
/libraries/PPP/ @me-no-dev
/libraries/SPI/ @me-no-dev
/libraries/Update/ @me-no-dev
/libraries/USB/ @SuGlider @me-no-dev
/libraries/WiFi/ @me-no-dev
/libraries/WiFiProv/ @me-no-dev
/libraries/Wire/ @me-no-dev
/libraries/Zigbee/ @P-R-O-C-H-Y
# CI JSON
# Keep this after other libraries and tests to avoid being overridden.
**/ci.json @lucasssvaz
# The CODEOWNERS file should be owned by the developers of the ESP32 Arduino Core.
# Leave this entry as the last one to avoid being overridden.
/.github/CODEOWNERS @espressif/arduino-devs

View file

@ -43,6 +43,7 @@ body:
- latest stable Release (if not listed below)
- latest development Release Candidate (RC-X)
- latest master (checkout manually)
- v3.2.1
- v3.2.0
- v3.1.3
- v3.1.2

View file

@ -4,6 +4,7 @@
# Usage:
# python merge_packages.py package_esp8266com_index.json version/new/package_esp8266com_index.json
# Written by Ivan Grokhotkov, 2015
# Updated by lucasssvaz to handle Chinese version sorting, 2025
#
from __future__ import print_function
@ -36,20 +37,19 @@ def merge_objects(versions, obj):
# Normalize ESP release version string (x.x.x) by adding '-rc<MAXINT>' (x.x.x-rc9223372036854775807)
# to ensure having REL above any RC
# to ensure having REL above any RC. CN version will be sorted after the official version if they happen
# to be mixed (normally, CN and non-CN versions should not be mixed)
# Dummy approach, functional anyway for current ESP package versioning
# (unlike NormalizedVersion/LooseVersion/StrictVersion & similar crap)
def pkgVersionNormalized(versionString):
verStr = str(versionString)
verStr = str(versionString).replace("-cn", "")
verParts = re.split(r"\.|-rc|-alpha", verStr, flags=re.IGNORECASE)
if len(verParts) == 3:
if sys.version_info > (3, 0): # Python 3
verStr = str(versionString) + "-rc" + str(sys.maxsize)
else: # Python 2
verStr = str(versionString) + "-rc" + str(sys.maxint)
if "-cn" in str(versionString):
verStr = verStr + "-rc" + str(sys.maxsize // 2)
else:
verStr = verStr + "-rc" + str(sys.maxsize)
elif len(verParts) != 4:
print("pkgVersionNormalized WARNING: unexpected version format: {0})".format(verStr), file=sys.stderr)

View file

@ -342,12 +342,14 @@ jq_arg=".packages[0].platforms[0].version = \"$RELEASE_TAG\" | \
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"
sed '0,/github\.com\//!s|github\.com/|dl.espressif.cn/github_assets/|g' "$OUTPUT_DIR/$PACKAGE_JSON_DEV" > "$OUTPUT_DIR/$PACKAGE_JSON_DEV_CN"
python "$SCRIPTS_DIR/release_append_cn.py" "$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"
sed '0,/github\.com\//!s|github\.com/|dl.espressif.cn/github_assets/|g' "$OUTPUT_DIR/$PACKAGE_JSON_REL" > "$OUTPUT_DIR/$PACKAGE_JSON_REL_CN"
python "$SCRIPTS_DIR/release_append_cn.py" "$OUTPUT_DIR/$PACKAGE_JSON_REL_CN"
fi
# Figure out the last release or pre-release
@ -456,14 +458,14 @@ 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 "Pages CN URL: $(git_safe_upload_to_pages "$PACKAGE_JSON_DEV_CN" "$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 "Pages CN URL: $(git_safe_upload_to_pages "$PACKAGE_JSON_REL_CN" "$OUTPUT_DIR/$PACKAGE_JSON_REL_CN")"
echo
fi

57
.github/scripts/release_append_cn.py vendored Executable file
View file

@ -0,0 +1,57 @@
#!/usr/bin/env python3
# Arduino IDE provides by default a package file for the ESP32. This causes version conflicts
# when the user tries to use the JSON file with the Chinese mirrors.
#
# The downside is that the Arduino IDE will always warn the user that updates are available as it
# will consider the version from the Chinese mirrors as a pre-release version.
#
# This script is used to append "-cn" to all versions in the package_esp32_index_cn.json file so that
# the user can select the Chinese mirrors without conflicts.
#
# If Arduino ever stops providing the package_esp32_index.json file by default,
# this script can be removed and the tags reverted.
import json
def append_cn_to_versions(obj):
if isinstance(obj, dict):
# Skip tools that are not from the esp32 package
packager = obj.get("packager")
if packager is not None and packager != "esp32":
return
for key, value in obj.items():
if key == "version" and isinstance(value, str):
if not value.endswith("-cn"):
obj[key] = value + "-cn"
else:
append_cn_to_versions(value)
elif isinstance(obj, list):
for item in obj:
append_cn_to_versions(item)
def process_json_file(input_path, output_path=None):
with open(input_path, "r", encoding="utf-8") as f:
data = json.load(f)
append_cn_to_versions(data)
if output_path is None:
output_path = input_path
with open(output_path, "w", encoding="utf-8") as f:
json.dump(data, f, indent=2)
print(f"Updated JSON written to {output_path}")
if __name__ == "__main__":
import sys
if len(sys.argv) < 2:
print("Usage: python release_append_cn.py input.json [output.json]")
else:
input_file = sys.argv[1]
output_file = sys.argv[2] if len(sys.argv) > 2 else None
process_json_file(input_file, output_file)

View file

@ -1,4 +1,5 @@
#!/bin/bash
# Disable shellcheck warning about using 'cat' to read a file.
# shellcheck disable=SC2002
# For reference: add tools for all boards by replacing one line in each board
@ -23,7 +24,15 @@ ESP_ARDUINO_VERSION_MINOR="$2"
ESP_ARDUINO_VERSION_PATCH="$3"
ESP_ARDUINO_VERSION="$ESP_ARDUINO_VERSION_MAJOR.$ESP_ARDUINO_VERSION_MINOR.$ESP_ARDUINO_VERSION_PATCH"
# Get ESP-IDF version from push.yml (this way we can ensure that the version is correct even if the local libs are not up to date)
ESP_IDF_VERSION=$(grep "idf_ver:" .github/workflows/push.yml | sed 's/.*release-v\([^"]*\).*/\1/')
if [ -z "$ESP_IDF_VERSION" ]; then
echo "Error: ESP-IDF version not found in push.yml" >&2
exit 1
fi
echo "New Arduino Version: $ESP_ARDUINO_VERSION"
echo "ESP-IDF Version: $ESP_IDF_VERSION"
echo "Updating platform.txt..."
cat platform.txt | sed "s/version=.*/version=$ESP_ARDUINO_VERSION/g" > __platform.txt && mv __platform.txt platform.txt
@ -31,6 +40,16 @@ cat platform.txt | sed "s/version=.*/version=$ESP_ARDUINO_VERSION/g" > __platfor
echo "Updating package.json..."
cat package.json | sed "s/.*\"version\":.*/ \"version\": \"$ESP_ARDUINO_VERSION\",/g" > __package.json && mv __package.json package.json
echo "Updating docs/conf_common.py..."
cat docs/conf_common.py | \
sed "s/.. |version| replace:: .*/.. |version| replace:: $ESP_ARDUINO_VERSION/g" | \
sed "s/.. |idf_version| replace:: .*/.. |idf_version| replace:: $ESP_IDF_VERSION/g" > docs/__conf_common.py && mv docs/__conf_common.py docs/conf_common.py
echo "Updating .gitlab/workflows/common.yml..."
cat .gitlab/workflows/common.yml | \
sed "s/ESP_IDF_VERSION:.*/ESP_IDF_VERSION: \"$ESP_IDF_VERSION\"/g" | \
sed "s/ESP_ARDUINO_VERSION:.*/ESP_ARDUINO_VERSION: \"$ESP_ARDUINO_VERSION\"/g" > .gitlab/workflows/__common.yml && mv .gitlab/workflows/__common.yml .gitlab/workflows/common.yml
echo "Updating cores/esp32/esp_arduino_version.h..."
cat cores/esp32/esp_arduino_version.h | \
sed "s/#define ESP_ARDUINO_VERSION_MAJOR.*/#define ESP_ARDUINO_VERSION_MAJOR $ESP_ARDUINO_VERSION_MAJOR/g" | \

236
.github/scripts/update_esptool.py vendored Normal file
View file

@ -0,0 +1,236 @@
#!/usr/bin/env python3
# This script is used to re-package the esptool if needed and update the JSON file
# for the Arduino ESP32 platform.
#
# The script has only been tested on macOS.
#
# For regular esptool releases, the generated packages already contain the correct permissions,
# extensions and are uploaded to the GitHub release assets. In this case, the script will only
# update the JSON file with the information from the GitHub release.
#
# The script can be used in two modes:
# 1. Local build: The build artifacts must be already downloaded and extracted in the base_folder.
# This is useful for esptool versions that are not yet released and that are grabbed from the
# GitHub build artifacts.
# 2. Release build: The script will get the release information from GitHub and update the JSON file.
# This is useful for esptool versions that are already released and that are uploaded to the
# GitHub release assets.
#
# For local build, the artifacts must be already downloaded and extracted in the base_folder
# set with the -l option.
# For example, a base folder "esptool" should contain the following folders extracted directly
# from the GitHub build artifacts:
# esptool/esptool-linux-aarch64
# esptool/esptool-linux-amd64
# esptool/esptool-linux-armv7
# esptool/esptool-macos-amd64
# esptool/esptool-macos-arm64
# esptool/esptool-windows-amd64
import argparse
import json
import os
import shutil
import stat
import tarfile
import zipfile
import hashlib
import requests
from pathlib import Path
def compute_sha256(filepath):
sha256 = hashlib.sha256()
with open(filepath, "rb") as f:
for block in iter(lambda: f.read(4096), b""):
sha256.update(block)
return f"SHA-256:{sha256.hexdigest()}"
def get_file_size(filepath):
return os.path.getsize(filepath)
def update_json_for_host(tmp_json_path, version, host, url, archiveFileName, checksum, size):
with open(tmp_json_path) as f:
data = json.load(f)
for pkg in data.get("packages", []):
for tool in pkg.get("tools", []):
if tool.get("name") == "esptool_py":
tool["version"] = version
if url is None:
# If the URL is not set, we need to find the old URL and update it
for system in tool.get("systems", []):
if system.get("host") == host:
url = system.get("url").replace(system.get("archiveFileName"), archiveFileName)
break
else:
print(f"No old URL found for host {host}. Using empty URL.")
url = ""
# Preserve existing systems order and update or append the new system
systems = tool.get("systems", [])
system_updated = False
for i, system in enumerate(systems):
if system.get("host") == host:
systems[i] = {
"host": host,
"url": url,
"archiveFileName": archiveFileName,
"checksum": checksum,
"size": str(size),
}
system_updated = True
break
if not system_updated:
systems.append({
"host": host,
"url": url,
"archiveFileName": archiveFileName,
"checksum": checksum,
"size": str(size),
})
tool["systems"] = systems
with open(tmp_json_path, "w") as f:
json.dump(data, f, indent=2, sort_keys=False, ensure_ascii=False)
f.write("\n")
def update_tools_dependencies(tmp_json_path, version):
with open(tmp_json_path) as f:
data = json.load(f)
for pkg in data.get("packages", []):
for platform in pkg.get("platforms", []):
for dep in platform.get("toolsDependencies", []):
if dep.get("name") == "esptool_py":
dep["version"] = version
with open(tmp_json_path, "w") as f:
json.dump(data, f, indent=2, sort_keys=False, ensure_ascii=False)
f.write("\n")
def create_archives(version, base_folder):
archive_files = []
for dirpath in Path(base_folder).glob("esptool-*"):
if not dirpath.is_dir():
continue
base = dirpath.name[len("esptool-"):]
if "windows" in dirpath.name:
zipfile_name = f"esptool-v{version}-{base}.zip"
print(f"Creating {zipfile_name} from {dirpath} ...")
with zipfile.ZipFile(zipfile_name, "w", zipfile.ZIP_DEFLATED) as zipf:
for root, _, files in os.walk(dirpath):
for file in files:
full_path = os.path.join(root, file)
zipf.write(full_path, os.path.relpath(full_path, start=dirpath))
archive_files.append(zipfile_name)
else:
tarfile_name = f"esptool-v{version}-{base}.tar.gz"
print(f"Creating {tarfile_name} from {dirpath} ...")
for root, dirs, files in os.walk(dirpath):
for name in dirs + files:
os.chmod(os.path.join(root, name), stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR |
stat.S_IRGRP | stat.S_IXGRP |
stat.S_IROTH | stat.S_IXOTH)
with tarfile.open(tarfile_name, "w:gz") as tar:
tar.add(dirpath, arcname=dirpath.name)
archive_files.append(tarfile_name)
return archive_files
def determine_hosts(archive_name):
if "linux-amd64" in archive_name:
return ["x86_64-pc-linux-gnu"]
elif "linux-armv7" in archive_name:
return ["arm-linux-gnueabihf"]
elif "linux-aarch64" in archive_name:
return ["aarch64-linux-gnu"]
elif "macos-amd64" in archive_name:
return ["x86_64-apple-darwin"]
elif "macos-arm64" in archive_name:
return ["arm64-apple-darwin"]
elif "windows-amd64" in archive_name:
return ["x86_64-mingw32", "i686-mingw32"]
else:
return []
def update_json_from_local_build(tmp_json_path, version, base_folder, archive_files):
for archive in archive_files:
print(f"Processing archive: {archive}")
hosts = determine_hosts(archive)
if not hosts:
print(f"Skipping unknown archive type: {archive}")
continue
archive_path = Path(archive)
checksum = compute_sha256(archive_path)
size = get_file_size(archive_path)
for host in hosts:
update_json_for_host(tmp_json_path, version, host, None, archive_path.name, checksum, size)
def update_json_from_release(tmp_json_path, version, release_info):
assets = release_info.get("assets", [])
for asset in assets:
if (asset.get("name").endswith(".tar.gz") or asset.get("name").endswith(".zip")) and "esptool" in asset.get("name"):
asset_fname = asset.get("name")
print(f"Processing asset: {asset_fname}")
hosts = determine_hosts(asset_fname)
if not hosts:
print(f"Skipping unknown archive type: {asset_fname}")
continue
asset_url = asset.get("browser_download_url")
asset_checksum = asset.get("digest").replace("sha256:", "SHA-256:")
asset_size = asset.get("size")
if asset_checksum is None:
asset_checksum = ""
print(f"Asset {asset_fname} has no checksum. Please set the checksum in the JSON file.")
for host in hosts:
update_json_for_host(tmp_json_path, version, host, asset_url, asset_fname, asset_checksum, asset_size)
def get_release_info(version):
url = f"https://api.github.com/repos/espressif/esptool/releases/tags/v{version}"
response = requests.get(url)
response.raise_for_status()
return response.json()
def main():
parser = argparse.ArgumentParser(description="Repack esptool and update JSON metadata.")
parser.add_argument("version", help="Version of the esptool (e.g. 5.0.dev1)")
parser.add_argument("-l", "--local", dest="base_folder", help="Enable local build mode and set the base folder with unpacked artifacts")
args = parser.parse_args()
script_dir = Path(__file__).resolve().parent
json_path = (script_dir / "../../package/package_esp32_index.template.json").resolve()
tmp_json_path = Path(str(json_path) + ".tmp")
shutil.copy(json_path, tmp_json_path)
local_build = args.base_folder is not None
if local_build:
os.chdir(args.base_folder)
os.environ['COPYFILE_DISABLE'] = 'true' # this disables including resource forks in tar files on macOS
# Clear any existing archive files
for file in Path(args.base_folder).glob("esptool-*.*"):
file.unlink()
archive_files = create_archives(args.version, args.base_folder)
update_json_from_local_build(tmp_json_path, args.version, args.base_folder, archive_files)
else:
release_info = get_release_info(args.version)
update_json_from_release(tmp_json_path, args.version, release_info)
print(f"Updating esptool version fields to {args.version}")
update_tools_dependencies(tmp_json_path, args.version)
shutil.move(tmp_json_path, json_path)
print(f"Done. JSON updated at {json_path}")
if __name__ == "__main__":
main()

View file

@ -24,4 +24,5 @@ jobs:
instructions-cla-link: "https://cla-assistant.io/espressif/arduino-esp32"
instructions-contributions-file: "docs/en/contributing.rst"
rule-max-commits: "false"
rule-target-branch: "false"
commit-messages-min-summary-length: "10"

View file

@ -9,7 +9,8 @@
{
"name": "ArduinoBLE",
"exclude_targets": [
"esp32s2"
"esp32s2",
"esp32p4"
],
"sketch_path": [
"~/Arduino/libraries/ArduinoBLE/examples/Central/Scan/Scan.ino"

View file

@ -44,16 +44,17 @@ jobs:
gh api "$artifacts_url" -q '.artifacts[] | [.name, .archive_download_url] | @tsv' | while read artifact
do
IFS=$'\t' read name url <<< "$artifact"
# Only process pr_number and pr_cli_compile artifacts
if [[ "$name" == "pr_number" || "$name" =~ ^pr_cli_compile_[0-9]+$ ]]; then
gh api $url > "$name.zip"
unzip -j "$name.zip" -d "temp_$name"
unzip -o -j "$name.zip" -d "temp_$name"
if [[ "$name" == "pr_number" ]]; then
mv "temp_$name"/* sizes-report
elif [[ "$name" == "pr_cli"* ]]; then
elif [[ "$name" =~ ^pr_cli_compile_[0-9]+$ ]]; then
mv "temp_$name"/* sizes-report/pr
else
mv "temp_$name"/* sizes-report
fi
rm -r "temp_$name"
fi
done
echo "Contents of parent directory:"
ls -R ..
@ -65,7 +66,7 @@ jobs:
path: ./artifacts/sizes-report/pr_num.txt
- name: Report results
uses: P-R-O-C-H-Y/report-size-deltas@2043188c68f483a7b50527c4eacf609d05bb67a5 # sizes_v2
uses: P-R-O-C-H-Y/report-size-deltas@bea91d2c99ca80c88a883b39b1c4012f00ec3d09 # sizes_v2
with:
sketches-reports-source: ${{ env.SKETCHES_REPORTS_PATH }}
github-token: ${{ env.GITHUB_TOKEN }}

25
.gitlab-ci.yml Normal file
View file

@ -0,0 +1,25 @@
workflow:
rules:
# Disable those non-protected push triggered pipelines
- if: '$CI_COMMIT_REF_NAME != "master" && $CI_COMMIT_BRANCH !~ /^release\/v/ && $CI_COMMIT_TAG !~ /^\d+\.\d+(\.\d+)?($|-)/ && $CI_PIPELINE_SOURCE == "push"'
when: never
# when running merged result pipelines, CI_COMMIT_SHA represents the temp commit it created.
# Please use PIPELINE_COMMIT_SHA at all places that require a commit sha of the original commit.
- if: $CI_OPEN_MERGE_REQUESTS != null
variables:
PIPELINE_COMMIT_SHA: $CI_MERGE_REQUEST_SOURCE_BRANCH_SHA
IS_MR_PIPELINE: 1
- if: $CI_OPEN_MERGE_REQUESTS == null
variables:
PIPELINE_COMMIT_SHA: $CI_COMMIT_SHA
IS_MR_PIPELINE: 0
- if: '$CI_PIPELINE_SOURCE == "schedule"'
variables:
IS_SCHEDULED_RUN: "true"
- when: always
# Place the default settings in `.gitlab/workflows/common.yml` instead
include:
- ".gitlab/workflows/common.yml"
- ".gitlab/workflows/sample.yml"

View file

@ -0,0 +1,26 @@
#####################
# Default Variables #
#####################
stages:
- pre_check
- build
- test
- result
variables:
ESP_IDF_VERSION: "5.4"
ESP_ARDUINO_VERSION: "3.2.1"
#############
# `default` #
#############
default:
retry:
max: 2
when:
# In case of a runner failure we could hop to another one, or a network error could go away.
- runner_system_failure
# Job execution timeout may be caused by a network issue.
- job_execution_timeout

View file

@ -0,0 +1,6 @@
hello-world:
stage: test
script:
- echo "Hello, World from GitLab CI!"
rules:
- if: $CI_PIPELINE_SOURCE == "push"

View file

@ -165,6 +165,7 @@ set(ARDUINO_LIBRARY_LittleFS_SRCS libraries/LittleFS/src/LittleFS.cpp)
set(ARDUINO_LIBRARY_NetBIOS_SRCS libraries/NetBIOS/src/NetBIOS.cpp)
set(ARDUINO_LIBRARY_OpenThread_SRCS
libraries/OpenThread/src/OThread.cpp
libraries/OpenThread/src/OThreadCLI.cpp
libraries/OpenThread/src/OThreadCLI_Util.cpp)
@ -301,6 +302,10 @@ set(ARDUINO_LIBRARY_Zigbee_SRCS
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
libraries/Zigbee/src/ep/ZigbeeFanControl.cpp
)
set(ARDUINO_LIBRARY_BLE_SRCS

1667
boards.txt

File diff suppressed because it is too large Load diff

View file

@ -20,6 +20,7 @@
#include <inttypes.h>
#include "Stream.h"
#include <functional>
class HardwareI2C : public Stream {
public:
@ -36,6 +37,7 @@ public:
virtual size_t requestFrom(uint8_t address, size_t len, bool stopBit) = 0;
virtual size_t requestFrom(uint8_t address, size_t len) = 0;
virtual void onReceive(void (*)(int)) = 0;
virtual void onRequest(void (*)(void)) = 0;
// Update base class to use std::function
virtual void onReceive(const std::function<void(int)> &) = 0;
virtual void onRequest(const std::function<void()> &) = 0;
};

View file

@ -180,7 +180,7 @@ bool String::changeBuffer(unsigned int maxStrLen) {
if (maxStrLen < sizeof(sso.buff) - 1) {
if (isSSO() || !buffer()) {
// Already using SSO, nothing to do
uint16_t oldLen = len();
size_t oldLen = len();
setSSO(true);
setLen(oldLen);
} else { // if bufptr && !isSSO()
@ -188,7 +188,7 @@ bool String::changeBuffer(unsigned int maxStrLen) {
char temp[sizeof(sso.buff)];
memcpy(temp, buffer(), maxStrLen);
free(wbuffer());
uint16_t oldLen = len();
size_t oldLen = len();
setSSO(true);
memcpy(wbuffer(), temp, maxStrLen);
setLen(oldLen);
@ -201,7 +201,7 @@ bool String::changeBuffer(unsigned int maxStrLen) {
if (newSize > CAPACITY_MAX) {
return false;
}
uint16_t oldLen = len();
size_t oldLen = len();
char *newbuffer = (char *)realloc(isSSO() ? nullptr : wbuffer(), newSize);
if (newbuffer) {
size_t oldSize = capacity() + 1; // include NULL.

View file

@ -15,7 +15,7 @@
#include "esp32-hal-bt.h"
#if SOC_BT_SUPPORTED
#ifdef CONFIG_BT_BLUEDROID_ENABLED
#if defined(CONFIG_BT_BLUEDROID_ENABLED) && __has_include("esp_bt.h")
#if CONFIG_IDF_TARGET_ESP32
bool btInUse() {

View file

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

View file

@ -56,6 +56,13 @@ static bool i2cDetachBus(void *bus_i2c_num) {
return true;
}
void *i2cBusHandle(uint8_t i2c_num) {
if (i2c_num >= SOC_I2C_NUM) {
return NULL;
}
return bus[i2c_num].bus_handle;
}
bool i2cIsInit(uint8_t i2c_num) {
if (i2c_num >= SOC_I2C_NUM) {
return false;

View file

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

View file

@ -19,6 +19,7 @@
#include "soc/soc_caps.h"
#if SOC_I2C_SUPPORTED
#include "esp_idf_version.h"
#ifdef __cplusplus
extern "C" {
@ -39,6 +40,10 @@ esp_err_t i2cWriteReadNonStop(
);
bool i2cIsInit(uint8_t i2c_num);
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 0)
void *i2cBusHandle(uint8_t i2c_num);
#endif
#ifdef __cplusplus
}
#endif

View file

@ -22,6 +22,9 @@
#include "soc/gpio_sig_map.h"
#include "esp_rom_gpio.h"
#include "hal/ledc_ll.h"
#if SOC_LEDC_GAMMA_CURVE_FADE_SUPPORTED
#include <math.h>
#endif
#ifdef SOC_LEDC_SUPPORT_HS_MODE
#define LEDC_CHANNELS (SOC_LEDC_CHANNEL_NUM << 1)
@ -45,6 +48,93 @@ typedef struct {
ledc_periph_t ledc_handle = {0};
// Helper function to find a timer with matching frequency and resolution
static bool find_matching_timer(uint8_t speed_mode, uint32_t freq, uint8_t resolution, uint8_t *timer_num) {
log_d("Searching for timer with freq=%u, resolution=%u", freq, resolution);
// Check all channels to find one with matching frequency and resolution
for (uint8_t i = 0; i < SOC_GPIO_PIN_COUNT; i++) {
if (!perimanPinIsValid(i)) {
continue;
}
peripheral_bus_type_t type = perimanGetPinBusType(i);
if (type == ESP32_BUS_TYPE_LEDC) {
ledc_channel_handle_t *bus = (ledc_channel_handle_t *)perimanGetPinBus(i, ESP32_BUS_TYPE_LEDC);
if (bus != NULL && (bus->channel / SOC_LEDC_CHANNEL_NUM) == speed_mode && bus->freq_hz == freq && bus->channel_resolution == resolution) {
log_d("Found matching timer %u for freq=%u, resolution=%u", bus->timer_num, freq, resolution);
*timer_num = bus->timer_num;
return true;
}
}
}
log_d("No matching timer found for freq=%u, resolution=%u", freq, resolution);
return false;
}
// Helper function to find an unused timer
static bool find_free_timer(uint8_t speed_mode, uint8_t *timer_num) {
// Check which timers are in use
uint8_t used_timers = 0;
for (uint8_t i = 0; i < SOC_GPIO_PIN_COUNT; i++) {
if (!perimanPinIsValid(i)) {
continue;
}
peripheral_bus_type_t type = perimanGetPinBusType(i);
if (type == ESP32_BUS_TYPE_LEDC) {
ledc_channel_handle_t *bus = (ledc_channel_handle_t *)perimanGetPinBus(i, ESP32_BUS_TYPE_LEDC);
if (bus != NULL && (bus->channel / SOC_LEDC_CHANNEL_NUM) == speed_mode) {
log_d("Timer %u is in use by channel %u", bus->timer_num, bus->channel);
used_timers |= (1 << bus->timer_num);
}
}
}
// Find first unused timer
for (uint8_t i = 0; i < SOC_LEDC_TIMER_NUM; i++) {
if (!(used_timers & (1 << i))) {
log_d("Found free timer %u", i);
*timer_num = i;
return true;
}
}
log_e("No free timers available");
return false;
}
// Helper function to remove a channel from a timer and clear timer if no channels are using it
static void remove_channel_from_timer(uint8_t speed_mode, uint8_t timer_num, uint8_t channel) {
log_d("Removing channel %u from timer %u in speed_mode %u", channel, timer_num, speed_mode);
// Check if any other channels are using this timer
bool timer_in_use = false;
for (uint8_t i = 0; i < SOC_GPIO_PIN_COUNT; i++) {
if (!perimanPinIsValid(i)) {
continue;
}
peripheral_bus_type_t type = perimanGetPinBusType(i);
if (type == ESP32_BUS_TYPE_LEDC) {
ledc_channel_handle_t *bus = (ledc_channel_handle_t *)perimanGetPinBus(i, ESP32_BUS_TYPE_LEDC);
if (bus != NULL && (bus->channel / SOC_LEDC_CHANNEL_NUM) == speed_mode && bus->timer_num == timer_num && bus->channel != channel) {
log_d("Timer %u is still in use by channel %u", timer_num, bus->channel);
timer_in_use = true;
break;
}
}
}
if (!timer_in_use) {
log_d("No other channels using timer %u, deconfiguring timer", timer_num);
// Stop the timer
ledc_timer_pause(speed_mode, timer_num);
// Deconfigure the timer
ledc_timer_config_t ledc_timer;
memset((void *)&ledc_timer, 0, sizeof(ledc_timer_config_t));
ledc_timer.speed_mode = speed_mode;
ledc_timer.timer_num = timer_num;
ledc_timer.deconfigure = true;
ledc_timer_config(&ledc_timer);
}
}
static bool fade_initialized = false;
static ledc_clk_cfg_t clock_source = LEDC_DEFAULT_CLK;
@ -81,6 +171,8 @@ static bool ledcDetachBus(void *bus) {
}
pinMatrixOutDetach(handle->pin, false, false);
if (!channel_found) {
uint8_t group = (handle->channel / SOC_LEDC_CHANNEL_NUM);
remove_channel_from_timer(group, handle->timer_num, handle->channel % SOC_LEDC_CHANNEL_NUM);
ledc_handle.used_channels &= ~(1UL << handle->channel);
}
free(handle);
@ -117,15 +209,25 @@ bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t c
return false;
}
uint8_t group = (channel / 8), timer = ((channel / 2) % 4);
uint8_t group = (channel / SOC_LEDC_CHANNEL_NUM);
uint8_t timer = 0;
bool channel_used = ledc_handle.used_channels & (1UL << channel);
if (channel_used) {
log_i("Channel %u is already set up, given frequency and resolution will be ignored", channel);
if (ledc_set_pin(pin, group, channel % 8) != ESP_OK) {
if (ledc_set_pin(pin, group, channel % SOC_LEDC_CHANNEL_NUM) != ESP_OK) {
log_e("Attaching pin to already used channel failed!");
return false;
}
} else {
// Find a timer with matching frequency and resolution, or a free timer
if (!find_matching_timer(group, freq, resolution, &timer)) {
if (!find_free_timer(group, &timer)) {
log_w("No free timers available for speed mode %u", group);
return false;
}
// Configure the timer if we're using a new one
ledc_timer_config_t ledc_timer;
memset((void *)&ledc_timer, 0, sizeof(ledc_timer_config_t));
ledc_timer.speed_mode = group;
@ -138,13 +240,14 @@ bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t c
log_e("ledc setup failed!");
return false;
}
}
uint32_t duty = ledc_get_duty(group, (channel % 8));
uint32_t duty = ledc_get_duty(group, (channel % SOC_LEDC_CHANNEL_NUM));
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.channel = (channel % SOC_LEDC_CHANNEL_NUM);
ledc_channel.timer_sel = timer;
ledc_channel.intr_type = LEDC_INTR_DISABLE;
ledc_channel.gpio_num = pin;
@ -157,6 +260,8 @@ bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t c
ledc_channel_handle_t *handle = (ledc_channel_handle_t *)malloc(sizeof(ledc_channel_handle_t));
handle->pin = pin;
handle->channel = channel;
handle->timer_num = timer;
handle->freq_hz = freq;
#ifndef SOC_LEDC_SUPPORT_FADE_STOP
handle->lock = NULL;
#endif
@ -172,7 +277,7 @@ bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t c
ledc_handle.used_channels |= 1UL << channel;
}
if (!perimanSetPinBus(pin, ESP32_BUS_TYPE_LEDC, (void *)handle, group, channel)) {
if (!perimanSetPinBus(pin, ESP32_BUS_TYPE_LEDC, (void *)handle, channel, timer)) {
ledcDetachBus((void *)handle);
return false;
}
@ -189,14 +294,40 @@ bool ledcAttach(uint8_t pin, uint32_t freq, uint8_t resolution) {
}
uint8_t channel = __builtin_ctz(free_channel); // Convert the free_channel bit to channel number
return ledcAttachChannel(pin, freq, resolution, channel);
// Try the first available channel
if (ledcAttachChannel(pin, freq, resolution, channel)) {
return true;
}
#ifdef SOC_LEDC_SUPPORT_HS_MODE
// If first attempt failed and HS mode is supported, try to find a free channel in group 1
if ((channel / SOC_LEDC_CHANNEL_NUM) == 0) { // First attempt was in group 0
log_d("LEDC: Group 0 channel %u failed, trying to find a free channel in group 1", channel);
// Find free channels specifically in group 1
uint32_t group1_mask = ((1UL << SOC_LEDC_CHANNEL_NUM) - 1) << SOC_LEDC_CHANNEL_NUM;
int group1_free_channel = (~ledc_handle.used_channels) & group1_mask;
if (group1_free_channel != 0) {
uint8_t group1_channel = __builtin_ctz(group1_free_channel);
if (ledcAttachChannel(pin, freq, resolution, group1_channel)) {
return true;
}
}
}
#endif
log_e(
"No free timers available for freq=%u, resolution=%u. To attach a new channel, use the same frequency and resolution as an already attached channel to "
"share its timer.",
freq, resolution
);
return false;
}
bool ledcWrite(uint8_t pin, uint32_t duty) {
ledc_channel_handle_t *bus = (ledc_channel_handle_t *)perimanGetPinBus(pin, ESP32_BUS_TYPE_LEDC);
if (bus != NULL) {
uint8_t group = (bus->channel / 8), channel = (bus->channel % 8);
uint8_t group = (bus->channel / SOC_LEDC_CHANNEL_NUM), channel = (bus->channel % SOC_LEDC_CHANNEL_NUM);
//Fixing if all bits in resolution is set = LEDC FULL ON
uint32_t max_duty = (1 << bus->channel_resolution) - 1;
@ -205,8 +336,14 @@ bool ledcWrite(uint8_t pin, uint32_t duty) {
duty = max_duty + 1;
}
ledc_set_duty(group, channel, duty);
ledc_update_duty(group, channel);
if (ledc_set_duty(group, channel, duty) != ESP_OK) {
log_e("ledc_set_duty failed");
return false;
}
if (ledc_update_duty(group, channel) != ESP_OK) {
log_e("ledc_update_duty failed");
return false;
}
return true;
}
@ -219,7 +356,11 @@ bool ledcWriteChannel(uint8_t channel, uint32_t duty) {
log_e("Channel %u is not available (maximum %u) or not used!", channel, LEDC_CHANNELS);
return false;
}
uint8_t group = (channel / 8), timer = ((channel / 2) % 4);
uint8_t group = (channel / SOC_LEDC_CHANNEL_NUM);
ledc_timer_t timer;
// Get the actual timer being used by this channel
ledc_ll_get_channel_timer(LEDC_LL_GET_HW(), group, (channel % SOC_LEDC_CHANNEL_NUM), &timer);
//Fixing if all bits in resolution is set = LEDC FULL ON
uint32_t resolution = 0;
@ -231,8 +372,14 @@ bool ledcWriteChannel(uint8_t channel, uint32_t duty) {
duty = max_duty + 1;
}
ledc_set_duty(group, channel, duty);
ledc_update_duty(group, channel);
if (ledc_set_duty(group, channel, duty) != ESP_OK) {
log_e("ledc_set_duty failed");
return false;
}
if (ledc_update_duty(group, channel) != ESP_OK) {
log_e("ledc_update_duty failed");
return false;
}
return true;
}
@ -241,7 +388,7 @@ uint32_t ledcRead(uint8_t pin) {
ledc_channel_handle_t *bus = (ledc_channel_handle_t *)perimanGetPinBus(pin, ESP32_BUS_TYPE_LEDC);
if (bus != NULL) {
uint8_t group = (bus->channel / 8), channel = (bus->channel % 8);
uint8_t group = (bus->channel / SOC_LEDC_CHANNEL_NUM), channel = (bus->channel % SOC_LEDC_CHANNEL_NUM);
return ledc_get_duty(group, channel);
}
return 0;
@ -253,8 +400,8 @@ uint32_t ledcReadFreq(uint8_t pin) {
if (!ledcRead(pin)) {
return 0;
}
uint8_t group = (bus->channel / 8), timer = ((bus->channel / 2) % 4);
return ledc_get_freq(group, timer);
uint8_t group = (bus->channel / SOC_LEDC_CHANNEL_NUM);
return ledc_get_freq(group, bus->timer_num);
}
return 0;
}
@ -268,12 +415,12 @@ uint32_t ledcWriteTone(uint8_t pin, uint32_t freq) {
return 0;
}
uint8_t group = (bus->channel / 8), timer = ((bus->channel / 2) % 4);
uint8_t group = (bus->channel / SOC_LEDC_CHANNEL_NUM);
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.timer_num = bus->timer_num;
ledc_timer.duty_resolution = 10;
ledc_timer.freq_hz = freq;
ledc_timer.clk_cfg = clock_source;
@ -284,7 +431,7 @@ uint32_t ledcWriteTone(uint8_t pin, uint32_t freq) {
}
bus->channel_resolution = 10;
uint32_t res_freq = ledc_get_freq(group, timer);
uint32_t res_freq = ledc_get_freq(group, bus->timer_num);
ledcWrite(pin, 0x1FF);
return res_freq;
}
@ -325,12 +472,12 @@ uint32_t ledcChangeFrequency(uint8_t pin, uint32_t freq, uint8_t resolution) {
log_e("LEDC pin %u - resolution is zero or it is too big (maximum %u)", pin, LEDC_MAX_BIT_WIDTH);
return 0;
}
uint8_t group = (bus->channel / 8), timer = ((bus->channel / 2) % 4);
uint8_t group = (bus->channel / SOC_LEDC_CHANNEL_NUM);
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.timer_num = bus->timer_num;
ledc_timer.duty_resolution = resolution;
ledc_timer.freq_hz = freq;
ledc_timer.clk_cfg = clock_source;
@ -340,7 +487,7 @@ uint32_t ledcChangeFrequency(uint8_t pin, uint32_t freq, uint8_t resolution) {
return 0;
}
bus->channel_resolution = resolution;
return ledc_get_freq(group, timer);
return ledc_get_freq(group, bus->timer_num);
}
return 0;
}
@ -351,12 +498,14 @@ bool ledcOutputInvert(uint8_t pin, bool out_invert) {
gpio_set_level(pin, out_invert);
#ifdef CONFIG_IDF_TARGET_ESP32P4
esp_rom_gpio_connect_out_signal(pin, LEDC_LS_SIG_OUT_PAD_OUT0_IDX + ((bus->channel) % 8), out_invert, 0);
esp_rom_gpio_connect_out_signal(pin, LEDC_LS_SIG_OUT_PAD_OUT0_IDX + ((bus->channel) % SOC_LEDC_CHANNEL_NUM), out_invert, 0);
#else
#ifdef SOC_LEDC_SUPPORT_HS_MODE
esp_rom_gpio_connect_out_signal(pin, ((bus->channel / 8 == 0) ? LEDC_HS_SIG_OUT0_IDX : LEDC_LS_SIG_OUT0_IDX) + ((bus->channel) % 8), out_invert, 0);
esp_rom_gpio_connect_out_signal(
pin, ((bus->channel / SOC_LEDC_CHANNEL_NUM == 0) ? LEDC_HS_SIG_OUT0_IDX : LEDC_LS_SIG_OUT0_IDX) + ((bus->channel) % SOC_LEDC_CHANNEL_NUM), out_invert, 0
);
#else
esp_rom_gpio_connect_out_signal(pin, LEDC_LS_SIG_OUT0_IDX + ((bus->channel) % 8), out_invert, 0);
esp_rom_gpio_connect_out_signal(pin, LEDC_LS_SIG_OUT0_IDX + ((bus->channel) % SOC_LEDC_CHANNEL_NUM), out_invert, 0);
#endif
#endif // ifdef CONFIG_IDF_TARGET_ESP32P4
return true;
@ -403,7 +552,7 @@ static bool ledcFadeConfig(uint8_t pin, uint32_t start_duty, uint32_t target_dut
}
#endif
#endif
uint8_t group = (bus->channel / 8), channel = (bus->channel % 8);
uint8_t group = (bus->channel / SOC_LEDC_CHANNEL_NUM), channel = (bus->channel % SOC_LEDC_CHANNEL_NUM);
// Initialize fade service.
if (!fade_initialized) {
@ -460,6 +609,161 @@ bool ledcFadeWithInterruptArg(uint8_t pin, uint32_t start_duty, uint32_t target_
return ledcFadeConfig(pin, start_duty, target_duty, max_fade_time_ms, userFunc, arg);
}
#ifdef SOC_LEDC_GAMMA_CURVE_FADE_SUPPORTED
// Default gamma factor for gamma correction (common value for LEDs)
static float ledcGammaFactor = 2.8;
// Gamma correction LUT support
static const float *ledcGammaLUT = NULL;
static uint16_t ledcGammaLUTSize = 0;
// Global variable to store current resolution for gamma callback
static uint8_t ledcGammaResolution = 13;
bool ledcSetGammaTable(const float *gamma_table, uint16_t size) {
if (gamma_table == NULL || size == 0) {
log_e("Invalid gamma table or size");
return false;
}
ledcGammaLUT = gamma_table;
ledcGammaLUTSize = size;
log_i("Custom gamma LUT set with %u entries", size);
return true;
}
void ledcClearGammaTable(void) {
ledcGammaLUT = NULL;
ledcGammaLUTSize = 0;
log_i("Gamma LUT cleared, using mathematical calculation");
}
void ledcSetGammaFactor(float factor) {
ledcGammaFactor = factor;
}
// Gamma correction calculator function
static uint32_t ledcGammaCorrection(uint32_t duty) {
if (duty == 0) {
return 0;
}
uint32_t max_duty = (1U << ledcGammaResolution) - 1;
if (duty >= (1U << ledcGammaResolution)) {
return max_duty;
}
// Use LUT if provided, otherwise use mathematical calculation
if (ledcGammaLUT != NULL && ledcGammaLUTSize > 0) {
// LUT-based gamma correction
uint32_t lut_index = (duty * (ledcGammaLUTSize - 1)) / max_duty;
if (lut_index >= ledcGammaLUTSize) {
lut_index = ledcGammaLUTSize - 1;
}
float corrected_normalized = ledcGammaLUT[lut_index];
return (uint32_t)(corrected_normalized * max_duty);
} else {
// Mathematical gamma correction
double normalized = (double)duty / (1U << ledcGammaResolution);
double corrected = pow(normalized, ledcGammaFactor);
return (uint32_t)(corrected * (1U << ledcGammaResolution));
}
}
static bool ledcFadeGammaConfig(uint8_t pin, uint32_t start_duty, uint32_t target_duty, int max_fade_time_ms, void (*userFunc)(void *), void *arg) {
ledc_channel_handle_t *bus = (ledc_channel_handle_t *)perimanGetPinBus(pin, ESP32_BUS_TYPE_LEDC);
if (bus != NULL) {
#ifndef SOC_LEDC_SUPPORT_FADE_STOP
#if !CONFIG_DISABLE_HAL_LOCKS
if (bus->lock == NULL) {
bus->lock = xSemaphoreCreateBinary();
if (bus->lock == NULL) {
log_e("xSemaphoreCreateBinary failed");
return false;
}
xSemaphoreGive(bus->lock);
}
//acquire lock
if (xSemaphoreTake(bus->lock, 0) != pdTRUE) {
log_e("LEDC Fade is still running on pin %u! SoC does not support stopping fade.", pin);
return false;
}
#endif
#endif
uint8_t group = (bus->channel / SOC_LEDC_CHANNEL_NUM), channel = (bus->channel % SOC_LEDC_CHANNEL_NUM);
// Initialize fade service.
if (!fade_initialized) {
ledc_fade_func_install(0);
fade_initialized = true;
}
bus->fn = (voidFuncPtr)userFunc;
bus->arg = arg;
ledc_cbs_t callbacks = {.fade_cb = ledcFnWrapper};
ledc_cb_register(group, channel, &callbacks, (void *)bus);
// Prepare gamma curve fade parameters
ledc_fade_param_config_t fade_params[SOC_LEDC_GAMMA_CURVE_FADE_RANGE_MAX];
uint32_t actual_fade_ranges = 0;
// Use a moderate number of linear segments for smooth gamma curve
const uint32_t linear_fade_segments = 12;
// Set the global resolution for gamma correction
ledcGammaResolution = bus->channel_resolution;
// Fill multi-fade parameter list using ESP-IDF API
esp_err_t err = ledc_fill_multi_fade_param_list(
group, channel, start_duty, target_duty, linear_fade_segments, max_fade_time_ms, ledcGammaCorrection, SOC_LEDC_GAMMA_CURVE_FADE_RANGE_MAX, fade_params,
&actual_fade_ranges
);
if (err != ESP_OK) {
log_e("ledc_fill_multi_fade_param_list failed: %s", esp_err_to_name(err));
return false;
}
// Apply the gamma-corrected start duty
uint32_t gamma_start_duty = ledcGammaCorrection(start_duty);
// Set multi-fade parameters
err = ledc_set_multi_fade(group, channel, gamma_start_duty, fade_params, actual_fade_ranges);
if (err != ESP_OK) {
log_e("ledc_set_multi_fade failed: %s", esp_err_to_name(err));
return false;
}
// Start the gamma curve fade
err = ledc_fade_start(group, channel, LEDC_FADE_NO_WAIT);
if (err != ESP_OK) {
log_e("ledc_fade_start failed: %s", esp_err_to_name(err));
return false;
}
log_d("Gamma curve fade started on pin %u: %u -> %u over %dms", pin, start_duty, target_duty, max_fade_time_ms);
} else {
log_e("Pin %u is not attached to LEDC. Call ledcAttach first!", pin);
return false;
}
return true;
}
bool ledcFadeGamma(uint8_t pin, uint32_t start_duty, uint32_t target_duty, int max_fade_time_ms) {
return ledcFadeGammaConfig(pin, start_duty, target_duty, max_fade_time_ms, NULL, NULL);
}
bool ledcFadeGammaWithInterrupt(uint8_t pin, uint32_t start_duty, uint32_t target_duty, int max_fade_time_ms, voidFuncPtr userFunc) {
return ledcFadeGammaConfig(pin, start_duty, target_duty, max_fade_time_ms, (voidFuncPtrArg)userFunc, NULL);
}
bool ledcFadeGammaWithInterruptArg(uint8_t pin, uint32_t start_duty, uint32_t target_duty, int max_fade_time_ms, void (*userFunc)(void *), void *arg) {
return ledcFadeGammaConfig(pin, start_duty, target_duty, max_fade_time_ms, userFunc, arg);
}
#endif /* SOC_LEDC_GAMMA_CURVE_FADE_SUPPORTED */
static uint8_t analog_resolution = 8;
static int analog_frequency = 1000;
void analogWrite(uint8_t pin, int value) {

View file

@ -51,6 +51,8 @@ typedef struct {
uint8_t pin; // Pin assigned to channel
uint8_t channel; // Channel number
uint8_t channel_resolution; // Resolution of channel
uint8_t timer_num; // Timer number used by this channel
uint32_t freq_hz; // Frequency configured for this channel
voidFuncPtr fn;
void *arg;
#ifndef SOC_LEDC_SUPPORT_FADE_STOP
@ -230,6 +232,85 @@ bool ledcFadeWithInterrupt(uint8_t pin, uint32_t start_duty, uint32_t target_dut
*/
bool ledcFadeWithInterruptArg(uint8_t pin, uint32_t start_duty, uint32_t target_duty, int max_fade_time_ms, void (*userFunc)(void *), void *arg);
//Gamma Curve Fade functions - only available on supported chips
#ifdef SOC_LEDC_GAMMA_CURVE_FADE_SUPPORTED
/**
* @brief Set a custom gamma correction lookup table for gamma curve fading.
* The LUT should contain normalized values (0.0 to 1.0) representing
* the gamma-corrected brightness curve.
*
* @param gamma_table Pointer to array of float values (0.0 to 1.0)
* @param size Number of entries in the lookup table
*
* @return true if gamma table was successfully set, false otherwise.
*
* @note The LUT array must remain valid for as long as gamma fading is used.
* Larger tables provide smoother transitions but use more memory.
*/
bool ledcSetGammaTable(const float *gamma_table, uint16_t size);
/**
* @brief Clear the current gamma correction lookup table.
* After calling this, gamma correction will use mathematical
* calculation with the default gamma factor (2.8).
*/
void ledcClearGammaTable(void);
/**
* @brief Set the gamma factor for gamma correction.
*
* @param factor Gamma factor to use for gamma correction.
*/
void ledcSetGammaFactor(float factor);
/**
* @brief Setup and start a gamma curve fade on a given LEDC pin.
* Gamma correction makes LED brightness changes appear more gradual to human eyes.
*
* @param pin GPIO pin
* @param start_duty initial duty cycle of the fade
* @param target_duty target duty cycle of the fade
* @param max_fade_time_ms maximum fade time in milliseconds
*
* @return true if gamma fade was successfully set and started, false otherwise.
*
* @note This function is only available on ESP32 variants that support gamma curve fading.
*/
bool ledcFadeGamma(uint8_t pin, uint32_t start_duty, uint32_t target_duty, int max_fade_time_ms);
/**
* @brief Setup and start a gamma curve fade on a given LEDC pin with a callback function.
*
* @param pin GPIO pin
* @param start_duty initial duty cycle of the fade
* @param target_duty target duty cycle of the fade
* @param max_fade_time_ms maximum fade time in milliseconds
* @param userFunc callback function to be called after fade is finished
*
* @return true if gamma fade was successfully set and started, false otherwise.
*
* @note This function is only available on ESP32 variants that support gamma curve fading.
*/
bool ledcFadeGammaWithInterrupt(uint8_t pin, uint32_t start_duty, uint32_t target_duty, int max_fade_time_ms, void (*userFunc)(void));
/**
* @brief Setup and start a gamma curve fade on a given LEDC pin with a callback function and argument.
*
* @param pin GPIO pin
* @param start_duty initial duty cycle of the fade
* @param target_duty target duty cycle of the fade
* @param max_fade_time_ms maximum fade time in milliseconds
* @param userFunc callback function to be called after fade is finished
* @param arg argument to be passed to the callback function
*
* @return true if gamma fade was successfully set and started, false otherwise.
*
* @note This function is only available on ESP32 variants that support gamma curve fading.
*/
bool ledcFadeGammaWithInterruptArg(uint8_t pin, uint32_t start_duty, uint32_t target_duty, int max_fade_time_ms, void (*userFunc)(void *), void *arg);
#endif // SOC_LEDC_GAMMA_CURVE_FADE_SUPPORTED
#ifdef __cplusplus
}
#endif

View file

@ -25,7 +25,7 @@
#include "esp_ota_ops.h"
#endif //CONFIG_APP_ROLLBACK_ENABLE
#include "esp_private/startup_internal.h"
#if defined(CONFIG_BT_BLUEDROID_ENABLED) && SOC_BT_SUPPORTED
#if defined(CONFIG_BT_BLUEDROID_ENABLED) && SOC_BT_SUPPORTED && __has_include("esp_bt.h")
#include "esp_bt.h"
#endif //CONFIG_BT_BLUEDROID_ENABLED
#include <sys/time.h>

View file

@ -60,6 +60,7 @@
#elif CONFIG_IDF_TARGET_ESP32P4
#include "esp32p4/rom/ets_sys.h"
#include "esp32p4/rom/gpio.h"
#include "hal/spi_ll.h"
#else
#error Target CONFIG_IDF_TARGET is not supported
#endif
@ -79,16 +80,15 @@ struct spi_struct_t {
#if CONFIG_IDF_TARGET_ESP32S2
// ESP32S2
#define SPI_COUNT (3)
#define SPI_COUNT (2)
#define SPI_CLK_IDX(p) ((p == 0) ? SPICLK_OUT_MUX_IDX : ((p == 1) ? FSPICLK_OUT_MUX_IDX : ((p == 2) ? SPI3_CLK_OUT_MUX_IDX : 0)))
#define SPI_MISO_IDX(p) ((p == 0) ? SPIQ_OUT_IDX : ((p == 1) ? FSPIQ_OUT_IDX : ((p == 2) ? SPI3_Q_OUT_IDX : 0)))
#define SPI_MOSI_IDX(p) ((p == 0) ? SPID_IN_IDX : ((p == 1) ? FSPID_IN_IDX : ((p == 2) ? SPI3_D_IN_IDX : 0)))
#define SPI_CLK_IDX(p) ((p == 0) ? FSPICLK_OUT_MUX_IDX : ((p == 1) ? SPI3_CLK_OUT_MUX_IDX : 0))
#define SPI_MISO_IDX(p) ((p == 0) ? FSPIQ_OUT_IDX : ((p == 1) ? SPI3_Q_OUT_IDX : 0))
#define SPI_MOSI_IDX(p) ((p == 0) ? FSPID_IN_IDX : ((p == 1) ? SPI3_D_IN_IDX : 0))
#define SPI_SPI_SS_IDX(n) ((n == 0) ? SPICS0_OUT_IDX : ((n == 1) ? SPICS1_OUT_IDX : 0))
#define SPI_HSPI_SS_IDX(n) ((n == 0) ? SPI3_CS0_OUT_IDX : ((n == 1) ? SPI3_CS1_OUT_IDX : ((n == 2) ? SPI3_CS2_OUT_IDX : SPI3_CS0_OUT_IDX)))
#define SPI_FSPI_SS_IDX(n) ((n == 0) ? FSPICS0_OUT_IDX : ((n == 1) ? FSPICS1_OUT_IDX : ((n == 2) ? FSPICS2_OUT_IDX : FSPICS0_OUT_IDX)))
#define SPI_SS_IDX(p, n) ((p == 0) ? SPI_SPI_SS_IDX(n) : ((p == 1) ? SPI_SPI_SS_IDX(n) : ((p == 2) ? SPI_HSPI_SS_IDX(n) : 0)))
#define SPI_HSPI_SS_IDX(n) ((n == 0) ? SPI3_CS0_OUT_IDX : ((n == 1) ? SPI3_CS1_OUT_IDX : ((n == 2) ? SPI3_CS2_OUT_IDX : 0)))
#define SPI_FSPI_SS_IDX(n) ((n == 0) ? FSPICS0_OUT_IDX : ((n == 1) ? FSPICS1_OUT_IDX : ((n == 2) ? FSPICS2_OUT_IDX : 0)))
#define SPI_SS_IDX(p, n) ((p == 0) ? SPI_FSPI_SS_IDX(n) : ((p == 1) ? SPI_HSPI_SS_IDX(n) : 0))
#elif CONFIG_IDF_TARGET_ESP32S3
// ESP32S3
@ -98,8 +98,8 @@ struct spi_struct_t {
#define SPI_MISO_IDX(p) ((p == 0) ? FSPIQ_OUT_IDX : ((p == 1) ? SPI3_Q_OUT_IDX : 0))
#define SPI_MOSI_IDX(p) ((p == 0) ? FSPID_IN_IDX : ((p == 1) ? SPI3_D_IN_IDX : 0))
#define SPI_HSPI_SS_IDX(n) ((n == 0) ? SPI3_CS0_OUT_IDX : ((n == 1) ? SPI3_CS1_OUT_IDX : 0))
#define SPI_FSPI_SS_IDX(n) ((n == 0) ? FSPICS0_OUT_IDX : ((n == 1) ? FSPICS1_OUT_IDX : 0))
#define SPI_HSPI_SS_IDX(n) ((n == 0) ? SPI3_CS0_OUT_IDX : ((n == 1) ? SPI3_CS1_OUT_IDX : ((n == 2) ? SPI3_CS2_OUT_IDX : 0)))
#define SPI_FSPI_SS_IDX(n) ((n == 0) ? FSPICS0_OUT_IDX : ((n == 1) ? FSPICS1_OUT_IDX : ((n == 2) ? FSPICS2_OUT_IDX : 0)))
#define SPI_SS_IDX(p, n) ((p == 0) ? SPI_FSPI_SS_IDX(n) : ((p == 1) ? SPI_HSPI_SS_IDX(n) : 0))
#elif CONFIG_IDF_TARGET_ESP32P4
@ -151,11 +151,7 @@ struct spi_struct_t {
#define SPI_MUTEX_UNLOCK()
// 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, 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
#if CONFIG_IDF_TARGET_ESP32S2 ||CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32P4
{(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
@ -179,11 +175,7 @@ static spi_t _spi_bus_array[] = {
#define SPI_MUTEX_UNLOCK() xSemaphoreGive(spi->lock)
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, 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
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32P4
{(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, false}
@ -621,6 +613,7 @@ void spiStopBus(spi_t *spi) {
spi_t *spiStartBus(uint8_t spi_num, uint32_t clockDiv, uint8_t dataMode, uint8_t bitOrder) {
if (spi_num >= SPI_COUNT) {
log_e("SPI bus index %d is out of range", spi_num);
return NULL;
}
@ -647,9 +640,6 @@ spi_t *spiStartBus(uint8_t spi_num, uint32_t clockDiv, uint8_t dataMode, uint8_t
} else if (spi_num == HSPI) {
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI3_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI3_RST);
} else {
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI01_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI01_RST);
}
#elif CONFIG_IDF_TARGET_ESP32S3
if (spi_num == FSPI) {
@ -670,6 +660,31 @@ spi_t *spiStartBus(uint8_t spi_num, uint32_t clockDiv, uint8_t dataMode, uint8_t
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI01_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI01_RST);
}
#elif CONFIG_IDF_TARGET_ESP32P4
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-variable"
if (spi_num == FSPI) {
PERIPH_RCC_ACQUIRE_ATOMIC(PERIPH_GPSPI2_MODULE, ref_count) {
if (ref_count == 0) {
PERIPH_RCC_ATOMIC() {
spi_ll_enable_bus_clock(SPI2_HOST, true);
spi_ll_reset_register(SPI2_HOST);
spi_ll_enable_clock(SPI2_HOST, true);
}
}
}
} else if (spi_num == HSPI) {
PERIPH_RCC_ACQUIRE_ATOMIC(PERIPH_GPSPI3_MODULE, ref_count) {
if (ref_count == 0) {
PERIPH_RCC_ATOMIC() {
spi_ll_enable_bus_clock(SPI3_HOST, true);
spi_ll_reset_register(SPI3_HOST);
spi_ll_enable_clock(SPI3_HOST, true);
}
}
}
}
#pragma GCC diagnostic pop
#elif defined(__PERIPH_CTRL_ALLOW_LEGACY_API)
periph_ll_reset(PERIPH_SPI2_MODULE);
periph_ll_enable_clk_clear_rst(PERIPH_SPI2_MODULE);

View file

@ -27,19 +27,13 @@ extern "C" {
#include <stdbool.h>
#define SPI_HAS_TRANSACTION
#ifdef CONFIG_IDF_TARGET_ESP32S2
#define FSPI 1 //SPI 1 bus. ESP32S2: for external memory only (can use the same data lines but different SS)
#define HSPI 2 //SPI 2 bus. ESP32S2: external memory or device - it can be matrixed to any pins
#define SPI2 2 // Another name for ESP32S2 SPI 2
#define SPI3 3 //SPI 3 bus. ESP32S2: device only - it can be matrixed to any pins
#elif CONFIG_IDF_TARGET_ESP32
#ifdef CONFIG_IDF_TARGET_ESP32
#define FSPI 1 //SPI 1 bus attached to the flash (can use the same data lines but different SS)
#define HSPI 2 //SPI 2 bus normally mapped to pins 12 - 15, but can be matrixed to any pins
#define VSPI 3 //SPI 3 bus normally attached to pins 5, 18, 19 and 23, but can be matrixed to any pins
#else
#define FSPI 0
#define HSPI 1
#define FSPI 0 // ESP32C2, C3, C6, H2, S2, S3, P4 - SPI 2 bus
#define HSPI 1 // ESP32S2, S3, P4 - SPI 3 bus
#endif
// This defines are not representing the real Divider of the ESP32

View file

@ -466,9 +466,6 @@ __attribute__((weak)) int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint
__attribute__((weak)) int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void *buffer, uint16_t bufsize) {
return -1;
}
__attribute__((weak)) bool tud_msc_is_writable_cb(uint8_t lun) {
return false;
}
#endif
#if CFG_TUD_NCM
__attribute__((weak)) bool tud_network_recv_cb(const uint8_t *src, uint16_t size) {

View file

@ -32,10 +32,11 @@
#include "driver/gpio.h"
#include "hal/gpio_hal.h"
#include "esp_rom_gpio.h"
#include "esp_private/gpio.h"
#include "driver/rtc_io.h"
#include "driver/lp_io.h"
#include "soc/uart_periph.h"
#include "soc/uart_pins.h"
#include "esp_private/uart_share_hw_ctrl.h"
static int s_uart_debug_nr = 0; // UART number for debug output
@ -294,6 +295,128 @@ static bool _uartDetachBus_RTS(void *busptr) {
return _uartDetachPins(bus->num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, bus->_rtsPin);
}
static bool _uartTrySetIomuxPin(uart_port_t uart_num, int io_num, uint32_t idx) {
// Store a pointer to the default pin, to optimize access to its fields.
const uart_periph_sig_t *upin = &uart_periph_signal[uart_num].pins[idx];
// In theory, if default_gpio is -1, iomux_func should also be -1, but let's be safe and test both.
if (upin->iomux_func == -1 || upin->default_gpio == -1 || upin->default_gpio != io_num) {
return false;
}
// Assign the correct function to the GPIO.
if (upin->iomux_func == -1) {
log_e("IO#%d has bad IOMUX internal information. Switching to GPIO Matrix UART function.", io_num);
return false;
}
if (uart_num < SOC_UART_HP_NUM) {
gpio_iomux_out(io_num, upin->iomux_func, false);
// If the pin is input, we also have to redirect the signal, in order to bypass the GPIO matrix.
if (upin->input) {
gpio_iomux_in(io_num, upin->signal);
}
}
#if (SOC_UART_LP_NUM >= 1) && (SOC_RTCIO_PIN_COUNT >= 1)
else {
if (upin->input) {
rtc_gpio_set_direction(io_num, RTC_GPIO_MODE_INPUT_ONLY);
} else {
rtc_gpio_set_direction(io_num, RTC_GPIO_MODE_OUTPUT_ONLY);
}
rtc_gpio_init(io_num);
rtc_gpio_iomux_func_sel(io_num, upin->iomux_func);
}
#endif
return true;
}
static esp_err_t _uartInternalSetPin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int rts_io_num, int cts_io_num) {
// Since an IO cannot route peripheral signals via IOMUX and GPIO matrix at the same time,
// if tx and rx share the same IO, both signals need to be routed to IOs through GPIO matrix
bool tx_rx_same_io = (tx_io_num == rx_io_num);
// In the following statements, if the io_num is negative, no need to configure anything.
if (tx_io_num >= 0) {
#if CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND || CONFIG_PM_SLP_DISABLE_GPIO
// In such case, IOs are going to switch to sleep configuration (isolate) when entering sleep for power saving reason
// But TX IO in isolate state could write garbled data to the other end
// Therefore, we should disable the switch of the TX pin to sleep configuration
gpio_sleep_sel_dis(tx_io_num);
#endif
if (tx_rx_same_io || !_uartTrySetIomuxPin(uart_num, tx_io_num, SOC_UART_TX_PIN_IDX)) {
if (uart_num < SOC_UART_HP_NUM) {
gpio_func_sel(tx_io_num, PIN_FUNC_GPIO);
esp_rom_gpio_connect_out_signal(tx_io_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_TX_PIN_IDX), 0, 0);
// output enable is set inside esp_rom_gpio_connect_out_signal func after the signal is connected
// (output enabled too early may cause unnecessary level change at the pad)
}
#if SOC_LP_GPIO_MATRIX_SUPPORTED
else {
rtc_gpio_init(tx_io_num); // set as a LP_GPIO pin
lp_gpio_connect_out_signal(tx_io_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_TX_PIN_IDX), 0, 0);
// output enable is set inside lp_gpio_connect_out_signal func after the signal is connected
}
#endif
}
}
if (rx_io_num >= 0) {
#if CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND || CONFIG_PM_SLP_DISABLE_GPIO
// In such case, IOs are going to switch to sleep configuration (isolate) when entering sleep for power saving reason
// But RX IO in isolate state could receive garbled data into FIFO, which is not desired
// Therefore, we should disable the switch of the RX pin to sleep configuration
gpio_sleep_sel_dis(rx_io_num);
#endif
if (tx_rx_same_io || !_uartTrySetIomuxPin(uart_num, rx_io_num, SOC_UART_RX_PIN_IDX)) {
if (uart_num < SOC_UART_HP_NUM) {
gpio_input_enable(rx_io_num);
esp_rom_gpio_connect_in_signal(rx_io_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_RX_PIN_IDX), 0);
}
#if SOC_LP_GPIO_MATRIX_SUPPORTED
else {
rtc_gpio_mode_t mode = (tx_rx_same_io ? RTC_GPIO_MODE_INPUT_OUTPUT : RTC_GPIO_MODE_INPUT_ONLY);
rtc_gpio_set_direction(rx_io_num, mode);
if (!tx_rx_same_io) { // set the same pin again as a LP_GPIO will overwrite connected out_signal, not desired, so skip
rtc_gpio_init(rx_io_num); // set as a LP_GPIO pin
}
lp_gpio_connect_in_signal(rx_io_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_RX_PIN_IDX), 0);
}
#endif
}
}
if (rts_io_num >= 0 && !_uartTrySetIomuxPin(uart_num, rts_io_num, SOC_UART_RTS_PIN_IDX)) {
if (uart_num < SOC_UART_HP_NUM) {
gpio_func_sel(rts_io_num, PIN_FUNC_GPIO);
esp_rom_gpio_connect_out_signal(rts_io_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_RTS_PIN_IDX), 0, 0);
// output enable is set inside esp_rom_gpio_connect_out_signal func after the signal is connected
}
#if SOC_LP_GPIO_MATRIX_SUPPORTED
else {
rtc_gpio_init(rts_io_num); // set as a LP_GPIO pin
lp_gpio_connect_out_signal(rts_io_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_RTS_PIN_IDX), 0, 0);
// output enable is set inside lp_gpio_connect_out_signal func after the signal is connected
}
#endif
}
if (cts_io_num >= 0 && !_uartTrySetIomuxPin(uart_num, cts_io_num, SOC_UART_CTS_PIN_IDX)) {
if (uart_num < SOC_UART_HP_NUM) {
gpio_pullup_en(cts_io_num);
gpio_input_enable(cts_io_num);
esp_rom_gpio_connect_in_signal(cts_io_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_CTS_PIN_IDX), 0);
}
#if SOC_LP_GPIO_MATRIX_SUPPORTED
else {
rtc_gpio_set_direction(cts_io_num, RTC_GPIO_MODE_INPUT_ONLY);
rtc_gpio_init(cts_io_num); // set as a LP_GPIO pin
lp_gpio_connect_in_signal(cts_io_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_CTS_PIN_IDX), 0);
}
#endif
}
return ESP_OK;
}
// Attach function for UART
// connects the IO Pad, set Paripheral Manager and internal UART structure data
static bool _uartAttachPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin) {
@ -306,7 +429,7 @@ static bool _uartAttachPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t
//log_v("attaching UART%d pins: prev,new RX(%d,%d) TX(%d,%d) CTS(%d,%d) RTS(%d,%d)", uart_num,
// uart->_rxPin, rxPin, uart->_txPin, txPin, uart->_ctsPin, ctsPin, uart->_rtsPin, rtsPin); vTaskDelay(10);
// IDF uart_set_pin() checks if the pin is used within LP UART and if it is a valid RTC IO pin
// IDF _uartInternalSetPin() checks if the pin is used within LP UART and if it is a valid RTC IO pin
// No need for Arduino Layer to check it again
bool retCode = true;
if (rxPin >= 0) {
@ -315,7 +438,7 @@ static bool _uartAttachPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t
perimanClearPinBus(rxPin);
}
// connect RX Pad
bool ret = ESP_OK == uart_set_pin(uart->num, UART_PIN_NO_CHANGE, rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
bool ret = ESP_OK == _uartInternalSetPin(uart->num, UART_PIN_NO_CHANGE, rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
#if SOC_UART_LP_NUM >= 1
if (ret && uart_num >= SOC_UART_HP_NUM) { // it is a LP UART NUM
ret &= lp_uart_config_io(uart->num, rxPin, RTC_GPIO_MODE_INPUT_ONLY, SOC_UART_RX_PIN_IDX);
@ -338,7 +461,7 @@ static bool _uartAttachPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t
perimanClearPinBus(txPin);
}
// connect TX Pad
bool ret = ESP_OK == uart_set_pin(uart->num, txPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
bool ret = ESP_OK == _uartInternalSetPin(uart->num, txPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
#if SOC_UART_LP_NUM >= 1
if (ret && uart_num >= SOC_UART_HP_NUM) { // it is a LP UART NUM
ret &= lp_uart_config_io(uart->num, txPin, RTC_GPIO_MODE_OUTPUT_ONLY, SOC_UART_TX_PIN_IDX);
@ -361,7 +484,7 @@ static bool _uartAttachPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t
perimanClearPinBus(ctsPin);
}
// connect CTS Pad
bool ret = ESP_OK == uart_set_pin(uart->num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, ctsPin);
bool ret = ESP_OK == _uartInternalSetPin(uart->num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, ctsPin);
#if SOC_UART_LP_NUM >= 1
if (ret && uart_num >= SOC_UART_HP_NUM) { // it is a LP UART NUM
ret &= lp_uart_config_io(uart->num, ctsPin, RTC_GPIO_MODE_INPUT_ONLY, SOC_UART_CTS_PIN_IDX);
@ -384,7 +507,7 @@ static bool _uartAttachPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t
perimanClearPinBus(rtsPin);
}
// connect RTS Pad
bool ret = ESP_OK == uart_set_pin(uart->num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, rtsPin, UART_PIN_NO_CHANGE);
bool ret = ESP_OK == _uartInternalSetPin(uart->num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, rtsPin, UART_PIN_NO_CHANGE);
#if SOC_UART_LP_NUM >= 1
if (ret && uart_num >= SOC_UART_HP_NUM) { // it is a LP UART NUM
ret &= lp_uart_config_io(uart->num, rtsPin, RTC_GPIO_MODE_OUTPUT_ONLY, SOC_UART_RTS_PIN_IDX);
@ -1383,39 +1506,9 @@ unsigned long uartDetectBaudrate(uart_t *uart) {
}
/*
These functions are for testing purpose only and can be used in Arduino Sketches
Those are used in the UART examples
*/
/*
This is intended to make an internal loopback connection using IOMUX
The function uart_internal_loopback() shall be used right after Arduino Serial.begin(...)
This code "replaces" the physical wiring for connecting TX <--> RX in a loopback
*/
// gets the right TX or RX SIGNAL, based on the UART number from gpio_sig_map.h
#ifdef CONFIG_IDF_TARGET_ESP32P4
#define UART_TX_SIGNAL(uartNumber) \
(uartNumber == UART_NUM_0 \
? UART0_TXD_PAD_OUT_IDX \
: (uartNumber == UART_NUM_1 \
? UART1_TXD_PAD_OUT_IDX \
: (uartNumber == UART_NUM_2 ? UART2_TXD_PAD_OUT_IDX : (uartNumber == UART_NUM_3 ? UART3_TXD_PAD_OUT_IDX : UART4_TXD_PAD_OUT_IDX))))
#define UART_RX_SIGNAL(uartNumber) \
(uartNumber == UART_NUM_0 \
? UART0_RXD_PAD_IN_IDX \
: (uartNumber == UART_NUM_1 \
? UART1_RXD_PAD_IN_IDX \
: (uartNumber == UART_NUM_2 ? UART2_RXD_PAD_IN_IDX : (uartNumber == UART_NUM_3 ? UART3_RXD_PAD_IN_IDX : UART4_RXD_PAD_IN_IDX))))
#else
#if SOC_UART_HP_NUM > 2
#define UART_TX_SIGNAL(uartNumber) (uartNumber == UART_NUM_0 ? U0TXD_OUT_IDX : (uartNumber == UART_NUM_1 ? U1TXD_OUT_IDX : U2TXD_OUT_IDX))
#define UART_RX_SIGNAL(uartNumber) (uartNumber == UART_NUM_0 ? U0RXD_IN_IDX : (uartNumber == UART_NUM_1 ? U1RXD_IN_IDX : U2RXD_IN_IDX))
#else
#define UART_TX_SIGNAL(uartNumber) (uartNumber == UART_NUM_0 ? U0TXD_OUT_IDX : U1TXD_OUT_IDX)
#define UART_RX_SIGNAL(uartNumber) (uartNumber == UART_NUM_0 ? U0RXD_IN_IDX : U1RXD_IN_IDX)
#endif
#endif // ifdef CONFIG_IDF_TARGET_ESP32P4
* These functions are for testing purposes only and can be used in Arduino Sketches.
* They are utilized in the UART examples and CI.
*/
/*
This function internally binds defined UARTs TX signal with defined RX pin of any UART (same or different).
@ -1427,7 +1520,14 @@ void uart_internal_loopback(uint8_t uartNum, int8_t rxPin) {
log_e("UART%d is not supported for loopback or RX pin %d is invalid.", uartNum, rxPin);
return;
}
esp_rom_gpio_connect_out_signal(rxPin, UART_TX_SIGNAL(uartNum), false, false);
#if 0 // leave this code here for future reference and need
// forces rxPin to use GPIO Matrix and setup the pin to receive UART TX Signal - IDF 5.4.1 Change with uart_release_pin()
gpio_func_sel((gpio_num_t)rxPin, PIN_FUNC_GPIO);
gpio_pullup_en((gpio_num_t)rxPin);
gpio_input_enable((gpio_num_t)rxPin);
esp_rom_gpio_connect_in_signal(rxPin, uart_periph_signal[uartNum].pins[SOC_UART_RX_PIN_IDX].signal, false);
#endif
esp_rom_gpio_connect_out_signal(rxPin, uart_periph_signal[uartNum].pins[SOC_UART_TX_PIN_IDX].signal, false, false);
}
/*

View file

@ -23,7 +23,7 @@ extern "C" {
/** Minor version number (x.X.x) */
#define ESP_ARDUINO_VERSION_MINOR 2
/** Patch version number (x.x.X) */
#define ESP_ARDUINO_VERSION_PATCH 0
#define ESP_ARDUINO_VERSION_PATCH 1
/**
* Macro to convert ARDUINO version number into an integer

View file

@ -2,6 +2,12 @@
from esp_docs.conf_docs import * # noqa: F403,F401
# Used for substituting variables in the documentation
rst_prolog = """
.. |version| replace:: 3.2.1
.. |idf_version| replace:: 5.4
"""
languages = ["en"]
# idf_targets = [
@ -27,6 +33,7 @@ html_static_path = ["../_static"]
extensions += [ # noqa: F405
"sphinx_copybutton",
"sphinx_tabs.tabs",
"sphinx_substitution_extensions", # For allowing substitutions inside code blocks
"esp_docs.esp_extensions.dummy_build_system",
]

View file

@ -347,20 +347,147 @@ This function will return ``true`` if the peripheral was initialized correctly.
onReceive
^^^^^^^^^
The ``onReceive`` function is used to define the callback for the data received from the master.
The ``onReceive`` function is used to define the callback for data received from the master device.
.. code-block:: arduino
void onReceive( void (*)(int) );
void onReceive(const std::function<void(int)>& callback);
**Function Signature:**
The callback function must have the signature ``void(int numBytes)`` where ``numBytes`` indicates how many bytes were received from the master.
**Usage Examples:**
.. code-block:: arduino
// Method 1: Regular function
void handleReceive(int numBytes) {
Serial.printf("Received %d bytes: ", numBytes);
while (Wire.available()) {
char c = Wire.read();
Serial.print(c);
}
Serial.println();
}
Wire.onReceive(handleReceive);
// Method 2: Lambda function
Wire.onReceive([](int numBytes) {
Serial.printf("Master sent %d bytes\n", numBytes);
while (Wire.available()) {
uint8_t data = Wire.read();
// Process received data
Serial.printf("Data: 0x%02X\n", data);
}
});
// Method 3: Lambda with capture (for accessing variables)
int deviceId = 42;
Wire.onReceive([deviceId](int numBytes) {
Serial.printf("Device %d received %d bytes\n", deviceId, numBytes);
// Process data...
});
// Method 4: Using std::function variable
std::function<void(int)> receiveHandler = [](int bytes) {
Serial.printf("Handling %d received bytes\n", bytes);
};
Wire.onReceive(receiveHandler);
// Method 5: Class member function (using lambda wrapper)
class I2CDevice {
private:
int deviceAddress;
public:
I2CDevice(int addr) : deviceAddress(addr) {}
void handleReceive(int numBytes) {
Serial.printf("Device 0x%02X received %d bytes\n", deviceAddress, numBytes);
}
void setup() {
Wire.onReceive([this](int bytes) {
this->handleReceive(bytes);
});
}
};
.. note::
The ``onReceive`` callback is triggered when the I2C master sends data to this slave device.
Use ``Wire.available()`` and ``Wire.read()`` inside the callback to retrieve the received data.
onRequest
^^^^^^^^^
The ``onRequest`` function is used to define the callback for the data to be send to the master.
The ``onRequest`` function is used to define the callback for responding to master read requests.
.. code-block:: arduino
void onRequest( void (*)(void) );
void onRequest(const std::function<void()>& callback);
**Function Signature:**
The callback function must have the signature ``void()`` with no parameters. This callback is triggered when the master requests data from this slave device.
**Usage Examples:**
.. code-block:: arduino
// Method 1: Regular function
void handleRequest() {
static int counter = 0;
Wire.printf("Response #%d", counter++);
}
Wire.onRequest(handleRequest);
// Method 2: Lambda function
Wire.onRequest([]() {
// Send sensor data to master
int sensorValue = analogRead(A0);
Wire.write(sensorValue >> 8); // High byte
Wire.write(sensorValue & 0xFF); // Low byte
});
// Method 3: Lambda with capture (for accessing variables)
int deviceStatus = 1;
String deviceName = "Sensor1";
Wire.onRequest([&deviceStatus, &deviceName]() {
Wire.write(deviceStatus);
Wire.write(deviceName.c_str(), deviceName.length());
});
// Method 4: Using std::function variable
std::function<void()> requestHandler = []() {
Wire.write("Hello Master!");
};
Wire.onRequest(requestHandler);
// Method 5: Class member function (using lambda wrapper)
class TemperatureSensor {
private:
float temperature;
public:
void updateTemperature() {
temperature = 25.5; // Read from actual sensor
}
void sendTemperature() {
// Convert float to bytes and send
uint8_t* tempBytes = (uint8_t*)&temperature;
Wire.write(tempBytes, sizeof(float));
}
void setup() {
Wire.onRequest([this]() {
this->sendTemperature();
});
}
};
.. note::
The ``onRequest`` callback is triggered when the I2C master requests data from this slave device.
Use ``Wire.write()`` inside the callback to send response data back to the master.
slaveWrite
^^^^^^^^^^

View file

@ -222,7 +222,7 @@ Documentation
-------------
If you are contributing to the documentation, please follow the instructions described in the
`documentation guidelines <guides/docs_contributing>`_ to properly format and test your changes.
`documentation guidelines <guides/docs_contributing.html>`_ to properly format and test your changes.
Testing and CI
--------------
@ -435,7 +435,7 @@ Documentation Checks
^^^^^^^^^^^^^^^^^^^^
The CI also checks the documentation for any compilation errors. This is important to ensure that the documentation layout is not broken.
To build the documentation locally, please refer to the `documentation guidelines <guides/docs_contributing>`_.
To build the documentation locally, please refer to the `documentation guidelines <guides/docs_contributing.html>`_.
Code Style Checks
^^^^^^^^^^^^^^^^^

View file

@ -14,9 +14,9 @@ For a simplified method, see `Installing using Boards Manager <https://docs.espr
If you plan to use these modified settings multiple times, for different projects and targets, you can recompile the Arduino core with the new settings using the Arduino Static Library Builder.
For more information, see the `Lib Builder documentation <lib_builder.html>`_.
.. note:: Latest Arduino Core ESP32 version (3.0.X) is now compatible with `ESP-IDF v5.1 <https://github.com/espressif/esp-idf/tree/release/v5.1>`_. Please consider this compatibility when using Arduino as a component in ESP-IDF.
.. note:: Latest Arduino Core ESP32 version (|version|) is now compatible with ESP-IDF v\ |idf_version|\ . Please consider this compatibility when using Arduino as a component in ESP-IDF.
For easiest use of Arduino framework as a ESP-IDF component, you can use the `IDF Component Manager <https://docs.espressif.com/projects/esp-idf/en/v5.1.4/esp32/api-guides/tools/idf-component-manager.html>`_ to add the Arduino component to your project.
For easiest use of Arduino framework as a ESP-IDF component, you can use the `IDF Component Manager <https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-component-manager.html>`_ to add the Arduino component to your project.
This will automatically clone the repository and its submodules. You can find the Arduino component in the `ESP Registry <https://components.espressif.com/components/espressif/arduino-esp32>`_ together with dependencies list and examples.
Installation
@ -32,14 +32,16 @@ Installing using IDF Component Manager
To add the Arduino component to your project using the IDF Component Manager, run the following command in your project directory:
.. code-block:: bash
:substitutions:
idf.py add-dependency "espressif/arduino-esp32^3.0.2"
idf.py add-dependency "espressif/arduino-esp32^|version|"
Or you can start a new project from a template with the Arduino component:
.. code-block:: bash
:substitutions:
idf.py create-project-from-example "espressif/arduino-esp32^3.0.2:hello_world"
idf.py create-project-from-example "espressif/arduino-esp32^|version|:hello_world"
Manual installation of Arduino framework
****************************************

View file

@ -9,9 +9,9 @@ Welcome to the compatibility guide for library developers aiming to support mult
Code Adaptations
----------------
To ensure compatibility with both versions of the ESP32 Arduino core, developers should utilize conditional compilation directives in their code. Below is an example of how to conditionally include code based on the ESP32 Arduino core version::
To ensure compatibility with both versions of the ESP32 Arduino core, developers should utilize conditional compilation directives in their code. Below is an example of how to conditionally include code based on the ESP32 Arduino core version:
.. code-block:: cpp
.. code-block:: cpp
#ifdef ESP_ARDUINO_VERSION_MAJOR
#if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 0)
@ -26,9 +26,9 @@ To ensure compatibility with both versions of the ESP32 Arduino core, developers
Version Print
-------------
To easily print the ESP32 Arduino core version at runtime, developers can use the `ESP_ARDUINO_VERSION_STR` macro. Below is an example of how to print the ESP32 Arduino core version::
To easily print the ESP32 Arduino core version at runtime, developers can use the `ESP_ARDUINO_VERSION_STR` macro. Below is an example of how to print the ESP32 Arduino core version:
.. code-block:: cpp
.. code-block:: cpp
Serial.printf(" ESP32 Arduino core version: %s\n", ESP_ARDUINO_VERSION_STR);

View file

@ -49,11 +49,11 @@ Before starting your collaboration, you need to get the documentation source cod
Requirements
************
To properly work with the documentation, you need to install some packages in your system.
To build the documentation properly, you need to install some packages in your system. Note that depending on
your system, you may need to use a virtual environment to install the packages.
.. code-block::
pip install -U Sphinx
pip install -r requirements.txt
The requirements file is under the ``docs`` folder.
@ -62,17 +62,14 @@ Using Visual Studio Code
************************
If you are using the Visual Studio Code, you can install some extensions to help you while writing documentation.
For reStructuredText, you can install the `reStructuredText Pack <https://marketplace.visualstudio.com/items?itemName=lextudio.restructuredtext-pack>`_ extension.
`reStructuredText Pack <https://marketplace.visualstudio.com/items?itemName=lextudio.restructuredtext-pack>`_
We also recommend you install to grammar check extension to help you to review English grammar.
`Grammarly <https://marketplace.visualstudio.com/items?itemName=znck.grammarly>`_
We also recommend you to install some grammar check extension to help you to review English grammar.
Building
********
To build the documentation and generate the HTML files, you can use the following command inside the ``docs`` folder. After a successful build, you can check the files inside the `_build/en/generic/html` folder.
To build the documentation and generate the HTML files, you can use the following command inside the ``docs`` folder. After a successful build, you can check the files inside the ``_build/en/generic/html`` folder.
.. code-block::

View file

@ -3,6 +3,7 @@ Welcome to ESP32 Arduino Core's documentation
#############################################
Here you will find all the relevant information about the project.
This documentation is valid for the Arduino Core for ESP32 version |version| based on ESP-IDF |idf_version|.
.. note::
This is a work in progress documentation and we will appreciate your help! We are looking for contributors!

View file

@ -70,6 +70,8 @@ To start the installation process using the Boards Manager, follow these steps:
:figclass: align-center
- Open Boards Manager from Tools > Board menu and install *esp32* platform (and do not forget to select your ESP32 board from Tools > Board menu after installation).
Users in China must select the package version with the "-cn" suffix and perform updates manually.
Automatic updates are not supported in this region, as they target the default package without the "-cn" suffix, resulting in download failures.
.. figure:: ../_static/install_guide_boards_manager_esp32.png
:align: center

View file

@ -293,8 +293,9 @@ You have two options to run the Docker image to build the libraries. Manually or
To run the Docker image manually, use the following command from the root of the ``arduino-esp32`` repository:
.. code-block:: bash
:substitutions:
docker run --rm -it -v $PWD:/arduino-esp32 -e TERM=xterm-256color espressif/esp32-arduino-lib-builder:release-v5.1
docker run --rm -it -v $PWD:/arduino-esp32 -e TERM=xterm-256color espressif/esp32-arduino-lib-builder:release-v|idf_version|
This will start the Lib Builder UI for compiling the libraries. The above command explained:
@ -304,7 +305,7 @@ This will start the Lib Builder UI for compiling the libraries. The above comman
- ``-t`` Allocate a pseudo-TTY;
- ``-e TERM=xterm-256color``: Optional. Sets the terminal type to ``xterm-256color`` to display colors correctly;
- ``-v $PWD:/arduino-esp32``: Optional. Mounts the current folder at ``/arduino-esp32`` inside the container. If not provided, the container will not copy the compiled libraries to the host machine;
- ``espressif/esp32-arduino-lib-builder:release-v5.1``: uses Docker image ``espressif/esp32-arduino-lib-builder`` with tag ``release-v5.1``.
- :substitution-code:`espressif/esp32-arduino-lib-builder:release-v|idf_version|`: uses Docker image ``espressif/esp32-arduino-lib-builder`` with tag :substitution-code:`release-v|idf_version|`.
The ``latest`` tag is implicitly added by Docker when no tag is specified. It is recommended to use a specific version tag to ensure reproducibility of the build process.
.. warning::
@ -324,24 +325,27 @@ By default the docker container will run the user interface script. If you want
For example, to run a terminal inside the container, you can run:
.. code-block:: bash
:substitutions:
docker run -it espressif/esp32-arduino-lib-builder:release-v5.1 /bin/bash
docker run -it espressif/esp32-arduino-lib-builder:release-v|idf_version| /bin/bash
Running the Docker image using the provided run script will depend on the host OS.
Use the following command from the root of the ``arduino-esp32`` repository to execute the image in a Linux or macOS environment for
the ``release-v5.1`` tag:
the :substitution-code:`release-v|idf_version|` tag:
.. code-block:: bash
:substitutions:
curl -LJO https://raw.githubusercontent.com/espressif/esp32-arduino-lib-builder/refs/heads/release/v5.1/tools/docker/run.sh
curl -LJO https://raw.githubusercontent.com/espressif/esp32-arduino-lib-builder/refs/heads/release/v|idf_version|/tools/docker/run.sh
chmod +x run.sh
./run.sh $PWD
For Windows, use the following command in PowerShell from the root of the ``arduino-esp32`` repository:
.. code-block:: powershell
:substitutions:
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/espressif/esp32-arduino-lib-builder/refs/heads/release/v5.1/tools/docker/run.ps1" -OutFile "run.ps1"
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/espressif/esp32-arduino-lib-builder/refs/heads/release/v|idf_version|/tools/docker/run.ps1" -OutFile "run.ps1"
.\run.ps1 $pwd
As the script is unsigned, you may need to change the execution policy of the current session before running the script.

View file

@ -91,3 +91,15 @@ The Arduino ESP32 offers some unique APIs, described in this section:
:glob:
api/*
Zigbee APIs
-----------
.. toctree::
:maxdepth: 1
:glob:
zigbee/zigbee
zigbee/zigbee_core
zigbee/zigbee_ep
zigbee/ep_*

View file

@ -0,0 +1,280 @@
############
ZigbeeAnalog
############
About
-----
The ``ZigbeeAnalog`` class provides analog input and output endpoints for Zigbee networks. This endpoint implements the Zigbee Home Automation (HA) standard for analog signal processing and control.
Analog Input (AI) is meant to be used for sensors that provide an analog signal, such as temperature, humidity, pressure to be sent to the coordinator.
Analog Output (AO) is meant to be used for actuators that require an analog signal, such as dimmers, valves, etc. to be controlled by the coordinator.
Common API
----------
Constructor
***********
ZigbeeAnalog
^^^^^^^^^^^^
Creates a new Zigbee analog endpoint.
.. code-block:: arduino
ZigbeeAnalog(uint8_t endpoint);
* ``endpoint`` - Endpoint number (1-254)
Cluster Management
******************
addAnalogInput
^^^^^^^^^^^^^^
Adds analog input cluster to the endpoint.
.. code-block:: arduino
bool addAnalogInput();
This function will return ``true`` if successful, ``false`` otherwise.
addAnalogOutput
^^^^^^^^^^^^^^^
Adds analog output cluster to the endpoint.
.. code-block:: arduino
bool addAnalogOutput();
This function will return ``true`` if successful, ``false`` otherwise.
Analog Input API
----------------
Configuration Methods
*********************
setAnalogInputApplication
^^^^^^^^^^^^^^^^^^^^^^^^^
Sets the application type for the analog input.
.. code-block:: arduino
bool setAnalogInputApplication(uint32_t application_type);
* ``application_type`` - Application type constant (see esp_zigbee_zcl_analog_input.h for values)
This function will return ``true`` if successful, ``false`` otherwise.
setAnalogInputDescription
^^^^^^^^^^^^^^^^^^^^^^^^^
Sets a custom description for the analog input.
.. code-block:: arduino
bool setAnalogInputDescription(const char *description);
* ``description`` - Description string
This function will return ``true`` if successful, ``false`` otherwise.
setAnalogInputResolution
^^^^^^^^^^^^^^^^^^^^^^^^
Sets the resolution for the analog input.
.. code-block:: arduino
bool setAnalogInputResolution(float resolution);
* ``resolution`` - Resolution value
This function will return ``true`` if successful, ``false`` otherwise.
setAnalogInputMinMax
^^^^^^^^^^^^^^^^^^^^
Sets the minimum and maximum values for the analog input.
.. code-block:: arduino
bool setAnalogInputMinMax(float min, float max);
* ``min`` - Minimum value
* ``max`` - Maximum value
This function will return ``true`` if successful, ``false`` otherwise.
Value Control
*************
setAnalogInput
^^^^^^^^^^^^^^
Sets the analog input value.
.. code-block:: arduino
bool setAnalogInput(float analog);
* ``analog`` - Analog input value
This function will return ``true`` if successful, ``false`` otherwise.
Reporting Methods
*****************
setAnalogInputReporting
^^^^^^^^^^^^^^^^^^^^^^^
Sets the reporting configuration for analog input.
.. code-block:: arduino
bool setAnalogInputReporting(uint16_t min_interval, uint16_t max_interval, float delta);
* ``min_interval`` - Minimum reporting interval in seconds
* ``max_interval`` - Maximum reporting interval in seconds
* ``delta`` - Minimum change in value to trigger a report
This function will return ``true`` if successful, ``false`` otherwise.
reportAnalogInput
^^^^^^^^^^^^^^^^^
Manually reports the current analog input value.
.. code-block:: arduino
bool reportAnalogInput();
This function will return ``true`` if successful, ``false`` otherwise.
Analog Output API
-----------------
Configuration Methods
*********************
setAnalogOutputApplication
^^^^^^^^^^^^^^^^^^^^^^^^^^
Sets the application type for the analog output.
.. code-block:: arduino
bool setAnalogOutputApplication(uint32_t application_type);
* ``application_type`` - Application type constant (see esp_zigbee_zcl_analog_output.h for values)
This function will return ``true`` if successful, ``false`` otherwise.
setAnalogOutputDescription
^^^^^^^^^^^^^^^^^^^^^^^^^^
Sets a custom description for the analog output.
.. code-block:: arduino
bool setAnalogOutputDescription(const char *description);
* ``description`` - Description string
This function will return ``true`` if successful, ``false`` otherwise.
setAnalogOutputResolution
^^^^^^^^^^^^^^^^^^^^^^^^^
Sets the resolution for the analog output.
.. code-block:: arduino
bool setAnalogOutputResolution(float resolution);
* ``resolution`` - Resolution value
This function will return ``true`` if successful, ``false`` otherwise.
setAnalogOutputMinMax
^^^^^^^^^^^^^^^^^^^^^
Sets the minimum and maximum values for the analog output.
.. code-block:: arduino
bool setAnalogOutputMinMax(float min, float max);
* ``min`` - Minimum value
* ``max`` - Maximum value
This function will return ``true`` if successful, ``false`` otherwise.
Value Control
*************
setAnalogOutput
^^^^^^^^^^^^^^^
Sets the analog output value.
.. code-block:: arduino
bool setAnalogOutput(float analog);
* ``analog`` - Analog output value
This function will return ``true`` if successful, ``false`` otherwise.
getAnalogOutput
^^^^^^^^^^^^^^^
Gets the current analog output value.
.. code-block:: arduino
float getAnalogOutput();
This function will return current analog output value.
Reporting Methods
*****************
reportAnalogOutput
^^^^^^^^^^^^^^^^^^
Manually reports the current analog output value.
.. code-block:: arduino
bool reportAnalogOutput();
This function will return ``true`` if successful, ``false`` otherwise.
Event Handling
**************
onAnalogOutputChange
^^^^^^^^^^^^^^^^^^^^
Sets a callback function to be called when the analog output value changes.
.. code-block:: arduino
void onAnalogOutputChange(void (*callback)(float analog));
* ``callback`` - Function to call when analog output changes
Example
-------
Analog Input/Output
*******************
.. literalinclude:: ../../../libraries/Zigbee/examples/Zigbee_Analog_Input_Output/Zigbee_Analog_Input_Output.ino
:language: arduino

View file

@ -0,0 +1,137 @@
############
ZigbeeBinary
############
About
-----
The ``ZigbeeBinary`` class provides an endpoint for binary input/output sensors in Zigbee networks. This endpoint implements the Zigbee Home Automation (HA) standard for binary sensors, supporting various application types for HVAC, security, and general binary sensing.
Binary Input (BI) is meant to be used for sensors that provide a binary signal, such as door/window sensors, motion detectors, etc. to be sent to the network.
.. note::
Binary Output (BO) is not supported yet.
API Reference
-------------
Constructor
***********
ZigbeeBinary
^^^^^^^^^^^^
Creates a new Zigbee binary sensor endpoint.
.. code-block:: arduino
ZigbeeBinary(uint8_t endpoint);
* ``endpoint`` - Endpoint number (1-254)
Binary Input Application Types
******************************
HVAC Application Types
^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: arduino
#define BINARY_INPUT_APPLICATION_TYPE_HVAC_BOILER_STATUS 0x00000003
#define BINARY_INPUT_APPLICATION_TYPE_HVAC_CHILLER_STATUS 0x00000013
#define BINARY_INPUT_APPLICATION_TYPE_HVAC_OCCUPANCY 0x00000031
#define BINARY_INPUT_APPLICATION_TYPE_HVAC_FAN_STATUS 0x00000035
#define BINARY_INPUT_APPLICATION_TYPE_HVAC_FILTER_STATUS 0x00000036
#define BINARY_INPUT_APPLICATION_TYPE_HVAC_HEATING_ALARM 0x0000003E
#define BINARY_INPUT_APPLICATION_TYPE_HVAC_COOLING_ALARM 0x0000001D
#define BINARY_INPUT_APPLICATION_TYPE_HVAC_UNIT_ENABLE 0x00000090
#define BINARY_INPUT_APPLICATION_TYPE_HVAC_OTHER 0x0000FFFF
Security Application Types
^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: arduino
#define BINARY_INPUT_APPLICATION_TYPE_SECURITY_GLASS_BREAKAGE_DETECTION_0 0x01000000
#define BINARY_INPUT_APPLICATION_TYPE_SECURITY_INTRUSION_DETECTION 0x01000001
#define BINARY_INPUT_APPLICATION_TYPE_SECURITY_MOTION_DETECTION 0x01000002
#define BINARY_INPUT_APPLICATION_TYPE_SECURITY_GLASS_BREAKAGE_DETECTION_1 0x01000003
#define BINARY_INPUT_APPLICATION_TYPE_SECURITY_ZONE_ARMED 0x01000004
#define BINARY_INPUT_APPLICATION_TYPE_SECURITY_GLASS_BREAKAGE_DETECTION_2 0x01000005
#define BINARY_INPUT_APPLICATION_TYPE_SECURITY_SMOKE_DETECTION 0x01000006
#define BINARY_INPUT_APPLICATION_TYPE_SECURITY_CARBON_DIOXIDE_DETECTION 0x01000007
#define BINARY_INPUT_APPLICATION_TYPE_SECURITY_HEAT_DETECTION 0x01000008
#define BINARY_INPUT_APPLICATION_TYPE_SECURITY_OTHER 0x0100FFFF
API Methods
***********
addBinaryInput
^^^^^^^^^^^^^^
Adds a binary input cluster to the endpoint.
.. code-block:: arduino
bool addBinaryInput();
This function will return ``true`` if successful, ``false`` otherwise.
setBinaryInputApplication
^^^^^^^^^^^^^^^^^^^^^^^^^
Sets the application type for the binary input.
.. code-block:: arduino
bool setBinaryInputApplication(uint32_t application_type);
* ``application_type`` - Application type constant (see above)
This function will return ``true`` if successful, ``false`` otherwise.
setBinaryInputDescription
^^^^^^^^^^^^^^^^^^^^^^^^^
Sets a custom description for the binary input.
.. code-block:: arduino
bool setBinaryInputDescription(const char *description);
* ``description`` - Description string
This function will return ``true`` if successful, ``false`` otherwise.
setBinaryInput
^^^^^^^^^^^^^^
Sets the binary input value.
.. code-block:: arduino
bool setBinaryInput(bool input);
* ``input`` - Binary value (true/false)
This function will return ``true`` if successful, ``false`` otherwise.
reportBinaryInput
^^^^^^^^^^^^^^^^^
Manually reports the current binary input value.
.. code-block:: arduino
bool reportBinaryInput();
This function will return ``true`` if successful, ``false`` otherwise.
Example
-------
Binary Input Implementation
****************************
.. literalinclude:: ../../../libraries/Zigbee/examples/Zigbee_Binary_Input/Zigbee_Binary_Input.ino
:language: arduino

View file

@ -0,0 +1,105 @@
#########################
ZigbeeCarbonDioxideSensor
#########################
About
-----
The ``ZigbeeCarbonDioxideSensor`` class provides a CO2 sensor endpoint for Zigbee networks. This endpoint implements the Zigbee Home Automation (HA) standard for carbon dioxide measurement devices.
API Reference
-------------
Constructor
***********
ZigbeeCarbonDioxideSensor
^^^^^^^^^^^^^^^^^^^^^^^^^
Creates a new Zigbee CO2 sensor endpoint.
.. code-block:: arduino
ZigbeeCarbonDioxideSensor(uint8_t endpoint);
* ``endpoint`` - Endpoint number (1-254)
API Methods
***********
setCarbonDioxide
^^^^^^^^^^^^^^^^
Sets the CO2 concentration measurement value.
.. code-block:: arduino
bool setCarbonDioxide(float carbon_dioxide);
* ``carbon_dioxide`` - CO2 concentration value in ppm
This function will return ``true`` if successful, ``false`` otherwise.
setMinMaxValue
^^^^^^^^^^^^^^
Sets the minimum and maximum measurement values.
.. code-block:: arduino
bool setMinMaxValue(float min, float max);
* ``min`` - Minimum CO2 concentration value in ppm
* ``max`` - Maximum CO2 concentration value in ppm
This function will return ``true`` if successful, ``false`` otherwise.
setTolerance
^^^^^^^^^^^^
Sets the tolerance value for measurements.
.. code-block:: arduino
bool setTolerance(float tolerance);
* ``tolerance`` - Tolerance value in ppm
This function will return ``true`` if successful, ``false`` otherwise.
setReporting
^^^^^^^^^^^^
Sets the reporting configuration for CO2 measurements.
.. code-block:: arduino
bool setReporting(uint16_t min_interval, uint16_t max_interval, uint16_t delta);
* ``min_interval`` - Minimum reporting interval in seconds
* ``max_interval`` - Maximum reporting interval in seconds
* ``delta`` - Minimum change required to trigger a report in ppm
**Note:** Delta reporting is currently not supported by the carbon dioxide sensor.
This function will return ``true`` if successful, ``false`` otherwise.
report
^^^^^^
Manually reports the current CO2 concentration value.
.. code-block:: arduino
bool report();
This function will return ``true`` if successful, ``false`` otherwise.
Example
-------
CO2 Sensor Implementation
*************************
.. literalinclude:: ../../../libraries/Zigbee/examples/Zigbee_CarbonDioxide_Sensor/Zigbee_CarbonDioxide_Sensor.ino
:language: arduino

View file

@ -0,0 +1,223 @@
########################
ZigbeeColorDimmableLight
########################
About
-----
The ``ZigbeeColorDimmableLight`` class provides an endpoint for color dimmable lights in Zigbee networks. This endpoint implements the Zigbee Home Automation (HA) standard for color lighting devices, supporting RGB color control, dimming, and scene management.
**Features:**
* On/off control
* Brightness level control (0-100%)
* RGB color control
* HSV color support
* Scene and group support
* Automatic state restoration
* Integration with common endpoint features (binding, OTA, etc.)
* Zigbee HA standard compliance
**Use Cases:**
* Smart RGB light bulbs
* Color-changing LED strips
* Mood lighting systems
* Entertainment lighting
* Architectural lighting
* Smart home color lighting
API Reference
-------------
Constructor
***********
ZigbeeColorDimmableLight
^^^^^^^^^^^^^^^^^^^^^^^^
Creates a new Zigbee color dimmable light endpoint.
.. code-block:: arduino
ZigbeeColorDimmableLight(uint8_t endpoint);
* ``endpoint`` - Endpoint number (1-254)
Callback Functions
******************
onLightChange
^^^^^^^^^^^^^
Sets the callback function for light state changes.
.. code-block:: arduino
void onLightChange(void (*callback)(bool, uint8_t, uint8_t, uint8_t, uint8_t));
* ``callback`` - Function pointer to the light change callback (state, red, green, blue, level)
Control Methods
***************
setLightState
^^^^^^^^^^^^^
Sets the light on/off state.
.. code-block:: arduino
bool setLightState(bool state);
* ``state`` - Light state (true = on, false = off)
This function will return ``true`` if successful, ``false`` otherwise.
setLightLevel
^^^^^^^^^^^^^
Sets the light brightness level.
.. code-block:: arduino
bool setLightLevel(uint8_t level);
* ``level`` - Brightness level (0-100, where 0 is off, 100 is full brightness)
This function will return ``true`` if successful, ``false`` otherwise.
setLightColor (RGB)
^^^^^^^^^^^^^^^^^^^
Sets the light color using RGB values.
.. code-block:: arduino
bool setLightColor(uint8_t red, uint8_t green, uint8_t blue);
bool setLightColor(espRgbColor_t rgb_color);
* ``red`` - Red component (0-255)
* ``green`` - Green component (0-255)
* ``blue`` - Blue component (0-255)
* ``rgb_color`` - RGB color structure
This function will return ``true`` if successful, ``false`` otherwise.
setLightColor (HSV)
^^^^^^^^^^^^^^^^^^^
Sets the light color using HSV values.
.. code-block:: arduino
bool setLightColor(espHsvColor_t hsv_color);
* ``hsv_color`` - HSV color structure
This function will return ``true`` if successful, ``false`` otherwise.
setLight
^^^^^^^^
Sets all light parameters at once.
.. code-block:: arduino
bool setLight(bool state, uint8_t level, uint8_t red, uint8_t green, uint8_t blue);
* ``state`` - Light state (true/false)
* ``level`` - Brightness level (0-100)
* ``red`` - Red component (0-255)
* ``green`` - Green component (0-255)
* ``blue`` - Blue component (0-255)
This function will return ``true`` if successful, ``false`` otherwise.
State Retrieval Methods
***********************
getLightState
^^^^^^^^^^^^^
Gets the current light state.
.. code-block:: arduino
bool getLightState();
This function will return current light state (true = on, false = off).
getLightLevel
^^^^^^^^^^^^^
Gets the current brightness level.
.. code-block:: arduino
uint8_t getLightLevel();
This function will return current brightness level (0-100).
getLightColor
^^^^^^^^^^^^^
Gets the current RGB color.
.. code-block:: arduino
espRgbColor_t getLightColor();
This function will return current RGB color structure.
getLightRed
^^^^^^^^^^^
Gets the current red component.
.. code-block:: arduino
uint8_t getLightRed();
This function will return current red component (0-255).
getLightGreen
^^^^^^^^^^^^^
Gets the current green component.
.. code-block:: arduino
uint8_t getLightGreen();
This function will return current green component (0-255).
getLightBlue
^^^^^^^^^^^^
Gets the current blue component.
.. code-block:: arduino
uint8_t getLightBlue();
This function will return current blue component (0-255).
Utility Methods
***************
restoreLight
^^^^^^^^^^^^
Restores the light to its last known state.
.. code-block:: arduino
void restoreLight();
Example
-------
Color Dimmable Light Implementation
***********************************
.. literalinclude:: ../../../libraries/Zigbee/examples/Zigbee_Color_Dimmable_Light/Zigbee_Color_Dimmable_Light.ino
:language: arduino

View file

@ -0,0 +1,186 @@
#######################
ZigbeeColorDimmerSwitch
#######################
About
-----
The ``ZigbeeColorDimmerSwitch`` class provides a color dimmer switch endpoint for Zigbee networks. This endpoint implements the Zigbee Home Automation (HA) standard for advanced lighting control switches that can control both dimming and color of lights.
**Features:**
* On/off control for bound lights
* Brightness level control (0-100%)
* Color control (RGB, HSV)
* Color temperature control
* Scene and group support
* Special effects and timed operations
* Integration with common endpoint features (binding, OTA, etc.)
* Zigbee HA standard compliance
**Use Cases:**
* Smart lighting switches
* Color control remotes
* Advanced lighting controllers
* Smart home lighting automation
* Entertainment lighting control
API Reference
-------------
Constructor
***********
ZigbeeColorDimmerSwitch
^^^^^^^^^^^^^^^^^^^^^^^
Creates a new Zigbee color dimmer switch endpoint.
.. code-block:: arduino
ZigbeeColorDimmerSwitch(uint8_t endpoint);
* ``endpoint`` - Endpoint number (1-254)
Basic Control Commands
**********************
lightToggle
^^^^^^^^^^^
Toggles the state of bound lights (on to off, or off to on).
.. code-block:: arduino
void lightToggle();
void lightToggle(uint16_t group_addr);
void lightToggle(uint8_t endpoint, uint16_t short_addr);
void lightToggle(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr);
* ``group_addr`` - Group address to control (optional)
* ``endpoint`` - Target device endpoint (optional)
* ``short_addr`` - Target device short address (optional)
* ``ieee_addr`` - Target device IEEE address (optional)
lightOn
^^^^^^^
Turns on bound lights.
.. code-block:: arduino
void lightOn();
void lightOn(uint16_t group_addr);
void lightOn(uint8_t endpoint, uint16_t short_addr);
void lightOn(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr);
* ``group_addr`` - Group address to control (optional)
* ``endpoint`` - Target device endpoint (optional)
* ``short_addr`` - Target device short address (optional)
* ``ieee_addr`` - Target device IEEE address (optional)
lightOff
^^^^^^^^
Turns off bound lights.
.. code-block:: arduino
void lightOff();
void lightOff(uint16_t group_addr);
void lightOff(uint8_t endpoint, uint16_t short_addr);
void lightOff(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr);
* ``group_addr`` - Group address to control (optional)
* ``endpoint`` - Target device endpoint (optional)
* ``short_addr`` - Target device short address (optional)
* ``ieee_addr`` - Target device IEEE address (optional)
Dimmer Control Commands
***********************
setLightLevel
^^^^^^^^^^^^^
Sets the brightness level of bound lights.
.. code-block:: arduino
void setLightLevel(uint8_t level);
void setLightLevel(uint8_t level, uint16_t group_addr);
void setLightLevel(uint8_t level, uint8_t endpoint, uint16_t short_addr);
void setLightLevel(uint8_t level, uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr);
* ``level`` - Brightness level (0-100, where 0 is off, 100 is full brightness)
* ``group_addr`` - Group address to control (optional)
* ``endpoint`` - Target device endpoint (optional)
* ``short_addr`` - Target device short address (optional)
* ``ieee_addr`` - Target device IEEE address (optional)
Color Control Commands
**********************
setLightColor
^^^^^^^^^^^^^
Sets the color of bound lights using RGB values.
.. code-block:: arduino
void setLightColor(uint8_t red, uint8_t green, uint8_t blue);
void setLightColor(uint8_t red, uint8_t green, uint8_t blue, uint16_t group_addr);
void setLightColor(uint8_t red, uint8_t green, uint8_t blue, uint8_t endpoint, uint16_t short_addr);
void setLightColor(uint8_t red, uint8_t green, uint8_t blue, uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr);
* ``red`` - Red component (0-255)
* ``green`` - Green component (0-255)
* ``blue`` - Blue component (0-255)
* ``group_addr`` - Group address to control (optional)
* ``endpoint`` - Target device endpoint (optional)
* ``short_addr`` - Target device short address (optional)
* ``ieee_addr`` - Target device IEEE address (optional)
Advanced Control Commands
*************************
lightOffWithEffect
^^^^^^^^^^^^^^^^^^
Turns off lights with a specific effect.
.. code-block:: arduino
void lightOffWithEffect(uint8_t effect_id, uint8_t effect_variant);
* ``effect_id`` - Effect identifier
* ``effect_variant`` - Effect variant
lightOnWithTimedOff
^^^^^^^^^^^^^^^^^^^
Turns on lights with automatic turn-off after specified time.
.. code-block:: arduino
void lightOnWithTimedOff(uint8_t on_off_control, uint16_t time_on, uint16_t time_off);
* ``on_off_control`` - Control byte
* ``time_on`` - Time to stay on (in 1/10th seconds)
* ``time_off`` - Time to stay off (in 1/10th seconds)
lightOnWithSceneRecall
^^^^^^^^^^^^^^^^^^^^^^
Turns on lights with scene recall.
.. code-block:: arduino
void lightOnWithSceneRecall();
Example
-------
Color Dimmer Switch Implementation
**********************************
.. literalinclude:: ../../../libraries/Zigbee/examples/Zigbee_Color_Dimmer_Switch/Zigbee_Color_Dimmer_Switch.ino
:language: arduino

View file

@ -0,0 +1,95 @@
###################
ZigbeeContactSwitch
###################
About
-----
The ``ZigbeeContactSwitch`` class provides a contact switch endpoint for Zigbee networks. This endpoint implements the Zigbee Home Automation (HA) standard for door/window contact sensors and other binary contact devices.
**Features:**
* Contact state detection (open/closed)
* Configurable application types
* Automatic reporting capabilities
* Integration with common endpoint features (binding, OTA, etc.)
* Zigbee HA standard compliance
**Use Cases:**
* Door and window sensors
* Security system contacts
* Cabinet and drawer sensors
* Industrial contact monitoring
* Smart home security applications
API Reference
-------------
Constructor
***********
ZigbeeContactSwitch
^^^^^^^^^^^^^^^^^^^
Creates a new Zigbee contact switch endpoint.
.. code-block:: arduino
ZigbeeContactSwitch(uint8_t endpoint);
* ``endpoint`` - Endpoint number (1-254)
API Methods
***********
setClosed
^^^^^^^^^
Sets the contact switch to closed state.
.. code-block:: arduino
bool setClosed();
This function will return ``true`` if successful, ``false`` otherwise.
setOpen
^^^^^^^
Sets the contact switch to open state.
.. code-block:: arduino
bool setOpen();
This function will return ``true`` if successful, ``false`` otherwise.
setIASClientEndpoint
^^^^^^^^^^^^^^^^^^^^
Sets the IAS Client endpoint number (default is 1).
.. code-block:: arduino
void setIASClientEndpoint(uint8_t ep_number);
* ``ep_number`` - IAS Client endpoint number
report
^^^^^^
Manually reports the current contact state.
.. code-block:: arduino
bool report();
This function will return ``true`` if successful, ``false`` otherwise.
Example
-------
Contact Switch Implementation
*****************************
.. literalinclude:: ../../../libraries/Zigbee/examples/Zigbee_Contact_Switch/Zigbee_Contact_Switch.ino
:language: arduino

View file

@ -0,0 +1,138 @@
###################
ZigbeeDimmableLight
###################
About
-----
The ``ZigbeeDimmableLight`` class provides a dimmable light endpoint for Zigbee networks. This endpoint implements the Zigbee Home Automation (HA) standard for dimmable lighting control with both on/off and brightness level control.
**Features:**
* On/off control
* Brightness level control (0-100%)
* State and level change callbacks
* Integration with common endpoint features (binding, OTA, etc.)
* Zigbee HA standard compliance
**Use Cases:**
* Dimmable smart bulbs
* LED strips with brightness control
* Any device requiring both on/off and dimming functionality
API Reference
-------------
Constructor
***********
ZigbeeDimmableLight
^^^^^^^^^^^^^^^^^^^
Creates a new Zigbee dimmable light endpoint.
.. code-block:: arduino
ZigbeeDimmableLight(uint8_t endpoint);
* ``endpoint`` - Endpoint number (1-254)
Light Control
*************
setLightState
^^^^^^^^^^^^^
Sets only the light state (on or off) without changing the brightness level.
.. code-block:: arduino
bool setLightState(bool state);
* ``state`` - ``true`` to turn on, ``false`` to turn off
This function will return ``true`` if successful, ``false`` otherwise.
setLightLevel
^^^^^^^^^^^^^
Sets only the brightness level (0-100) without changing the on/off state.
.. code-block:: arduino
bool setLightLevel(uint8_t level);
* ``level`` - Brightness level (0-100, where 0 is off, 100 is full brightness)
This function will return ``true`` if successful, ``false`` otherwise.
setLight
^^^^^^^^
Sets both the light state and brightness level simultaneously.
.. code-block:: arduino
bool setLight(bool state, uint8_t level);
* ``state`` - ``true`` to turn on, ``false`` to turn off
* ``level`` - Brightness level (0-100)
This function will return ``true`` if successful, ``false`` otherwise.
getLightState
^^^^^^^^^^^^^
Gets the current light state.
.. code-block:: arduino
bool getLightState();
This function will return current light state (``true`` = on, ``false`` = off).
getLightLevel
^^^^^^^^^^^^^
Gets the current brightness level.
.. code-block:: arduino
uint8_t getLightLevel();
This function will return current brightness level (0-100).
restoreLight
^^^^^^^^^^^^
Restores the light state and triggers any registered callbacks.
.. code-block:: arduino
void restoreLight();
Event Handling
**************
onLightChange
^^^^^^^^^^^^^
Sets a callback function to be called when the light state or level changes.
.. code-block:: arduino
void onLightChange(void (*callback)(bool, uint8_t));
* ``callback`` - Function to call when light state or level changes
**Callback Parameters:**
* ``bool state`` - New light state (true = on, false = off)
* ``uint8_t level`` - New brightness level (0-100)
Example
-------
Dimmable Light Implementation
*****************************
.. literalinclude:: ../../../libraries/Zigbee/examples/Zigbee_Dimmable_Light/Zigbee_Dimmable_Light.ino
:language: arduino

View file

@ -0,0 +1,95 @@
######################
ZigbeeDoorWindowHandle
######################
About
-----
The ``ZigbeeDoorWindowHandle`` class provides a door/window handle endpoint for Zigbee networks. This endpoint implements the Zigbee Home Automation (HA) standard for handle position sensors and other handle-related devices.
**Features:**
* Handle position detection
* Multiple position states support
* Configurable application types
* Automatic reporting capabilities
API Reference
-------------
Constructor
***********
ZigbeeDoorWindowHandle
^^^^^^^^^^^^^^^^^^^^^^
Creates a new Zigbee door/window handle endpoint.
.. code-block:: arduino
ZigbeeDoorWindowHandle(uint8_t endpoint);
* ``endpoint`` - Endpoint number (1-254)
API Methods
***********
setClosed
^^^^^^^^^
Sets the door/window handle to closed position.
.. code-block:: arduino
bool setClosed();
This function will return ``true`` if successful, ``false`` otherwise.
setOpen
^^^^^^^
Sets the door/window handle to open position.
.. code-block:: arduino
bool setOpen();
This function will return ``true`` if successful, ``false`` otherwise.
setTilted
^^^^^^^^^
Sets the door/window handle to tilted position.
.. code-block:: arduino
bool setTilted();
This function will return ``true`` if successful, ``false`` otherwise.
setIASClientEndpoint
^^^^^^^^^^^^^^^^^^^^
Sets the IAS Client endpoint number (default is 1).
.. code-block:: arduino
void setIASClientEndpoint(uint8_t ep_number);
* ``ep_number`` - IAS Client endpoint number
report
^^^^^^
Manually reports the current handle position.
.. code-block:: arduino
bool report();
This function will return ``true`` if successful, ``false`` otherwise.
Example
-------
*To be added*

View file

@ -0,0 +1,254 @@
###########################
ZigbeeElectricalMeasurement
###########################
About
-----
The ``ZigbeeElectricalMeasurement`` class provides an endpoint for electrical measurement devices in Zigbee networks. This endpoint implements the Zigbee Home Automation (HA) standard for power monitoring and electrical measurement.
**Features:**
* AC and DC electrical measurements
* Voltage, current, and power monitoring
* Power factor measurement
* Multi-phase support
* Configurable measurement ranges
* Automatic reporting capabilities
* Integration with common endpoint features (binding, OTA, etc.)
* Zigbee HA standard compliance
**Use Cases:**
* Smart power monitoring
* Energy monitoring systems
* Solar panel monitoring
* Battery monitoring systems
* Electrical load monitoring
Common API
----------
Constructor
***********
ZigbeeElectricalMeasurement
^^^^^^^^^^^^^^^^^^^^^^^^^^^
Creates a new Zigbee electrical measurement endpoint.
.. code-block:: arduino
ZigbeeElectricalMeasurement(uint8_t endpoint);
* ``endpoint`` - Endpoint number (1-254)
DC Electrical Measurement
*************************
addDCMeasurement
^^^^^^^^^^^^^^^^
Adds a DC measurement type to the endpoint.
.. code-block:: arduino
bool addDCMeasurement(ZIGBEE_DC_MEASUREMENT_TYPE measurement_type);
* ``measurement_type`` - DC measurement type constant (ZIGBEE_DC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_DC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_DC_MEASUREMENT_TYPE_POWER)
This function will return ``true`` if successful, ``false`` otherwise.
setDCMeasurement
^^^^^^^^^^^^^^^^
Sets the DC measurement value for a specific measurement type.
.. code-block:: arduino
bool setDCMeasurement(ZIGBEE_DC_MEASUREMENT_TYPE measurement_type, int16_t value);
* ``measurement_type`` - DC measurement type constant (ZIGBEE_DC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_DC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_DC_MEASUREMENT_TYPE_POWER)
* ``value`` - Measurement value
This function will return ``true`` if successful, ``false`` otherwise.
setDCMinMaxValue
^^^^^^^^^^^^^^^^
Sets the minimum and maximum values for a DC measurement type.
.. code-block:: arduino
bool setDCMinMaxValue(ZIGBEE_DC_MEASUREMENT_TYPE measurement_type, int16_t min, int16_t max);
* ``measurement_type`` - DC measurement type constant (ZIGBEE_DC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_DC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_DC_MEASUREMENT_TYPE_POWER)
* ``min`` - Minimum value
* ``max`` - Maximum value
This function will return ``true`` if successful, ``false`` otherwise.
setDCMultiplierDivisor
^^^^^^^^^^^^^^^^^^^^^^
Sets the multiplier and divisor for scaling DC measurements.
.. code-block:: arduino
bool setDCMultiplierDivisor(ZIGBEE_DC_MEASUREMENT_TYPE measurement_type, uint16_t multiplier, uint16_t divisor);
* ``measurement_type`` - DC measurement type constant (ZIGBEE_DC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_DC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_DC_MEASUREMENT_TYPE_POWER)
* ``multiplier`` - Multiplier value
* ``divisor`` - Divisor value
This function will return ``true`` if successful, ``false`` otherwise.
setDCReporting
^^^^^^^^^^^^^^
Sets the reporting configuration for DC measurements.
.. code-block:: arduino
bool setDCReporting(ZIGBEE_DC_MEASUREMENT_TYPE measurement_type, uint16_t min_interval, uint16_t max_interval, int16_t delta);
* ``measurement_type`` - DC measurement type constant (ZIGBEE_DC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_DC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_DC_MEASUREMENT_TYPE_POWER)
* ``min_interval`` - Minimum reporting interval in seconds
* ``max_interval`` - Maximum reporting interval in seconds
* ``delta`` - Minimum change required to trigger a report
This function will return ``true`` if successful, ``false`` otherwise.
reportDC
^^^^^^^^
Manually reports a DC measurement value.
.. code-block:: arduino
bool reportDC(ZIGBEE_DC_MEASUREMENT_TYPE measurement_type);
* ``measurement_type`` - DC measurement type constant (ZIGBEE_DC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_DC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_DC_MEASUREMENT_TYPE_POWER)
This function will return ``true`` if successful, ``false`` otherwise.
AC Electrical Measurement
*************************
addACMeasurement
^^^^^^^^^^^^^^^^
Adds an AC measurement type for a specific phase.
.. code-block:: arduino
bool addACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE measurement_type, ZIGBEE_AC_PHASE_TYPE phase_type);
* ``measurement_type`` - AC measurement type constant (ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_MEASUREMENT_TYPE_POWER_FACTOR, ZIGBEE_AC_MEASUREMENT_TYPE_FREQUENCY)
* ``phase_type`` - Phase type constant (ZIGBEE_AC_PHASE_TYPE_NON_SPECIFIC, ZIGBEE_AC_PHASE_TYPE_A, ZIGBEE_AC_PHASE_TYPE_B, ZIGBEE_AC_PHASE_TYPE_C)
This function will return ``true`` if successful, ``false`` otherwise.
setACMeasurement
^^^^^^^^^^^^^^^^
Sets the AC measurement value for a specific measurement type and phase.
.. code-block:: arduino
bool setACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE measurement_type, ZIGBEE_AC_PHASE_TYPE phase_type, int32_t value);
* ``measurement_type`` - AC measurement type constant (ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_MEASUREMENT_TYPE_POWER_FACTOR, ZIGBEE_AC_MEASUREMENT_TYPE_FREQUENCY)
* ``phase_type`` - Phase type constant (ZIGBEE_AC_PHASE_TYPE_NON_SPECIFIC, ZIGBEE_AC_PHASE_TYPE_A, ZIGBEE_AC_PHASE_TYPE_B, ZIGBEE_AC_PHASE_TYPE_C)
* ``value`` - Measurement value
This function will return ``true`` if successful, ``false`` otherwise.
setACMinMaxValue
^^^^^^^^^^^^^^^^
Sets the minimum and maximum values for an AC measurement type and phase.
.. code-block:: arduino
bool setACMinMaxValue(ZIGBEE_AC_MEASUREMENT_TYPE measurement_type, ZIGBEE_AC_PHASE_TYPE phase_type, int32_t min, int32_t max);
* ``measurement_type`` - AC measurement type constant (ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_MEASUREMENT_TYPE_POWER_FACTOR, ZIGBEE_AC_MEASUREMENT_TYPE_FREQUENCY)
* ``phase_type`` - Phase type constant (ZIGBEE_AC_PHASE_TYPE_NON_SPECIFIC, ZIGBEE_AC_PHASE_TYPE_A, ZIGBEE_AC_PHASE_TYPE_B, ZIGBEE_AC_PHASE_TYPE_C)
* ``min`` - Minimum value
* ``max`` - Maximum value
This function will return ``true`` if successful, ``false`` otherwise.
setACMultiplierDivisor
^^^^^^^^^^^^^^^^^^^^^^
Sets the multiplier and divisor for scaling AC measurements.
.. code-block:: arduino
bool setACMultiplierDivisor(ZIGBEE_AC_MEASUREMENT_TYPE measurement_type, uint16_t multiplier, uint16_t divisor);
* ``measurement_type`` - AC measurement type constant (ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_MEASUREMENT_TYPE_POWER_FACTOR, ZIGBEE_AC_MEASUREMENT_TYPE_FREQUENCY)
* ``multiplier`` - Multiplier value
* ``divisor`` - Divisor value
This function will return ``true`` if successful, ``false`` otherwise.
setACPowerFactor
^^^^^^^^^^^^^^^^
Sets the power factor for a specific phase.
.. code-block:: arduino
bool setACPowerFactor(ZIGBEE_AC_PHASE_TYPE phase_type, int8_t power_factor);
* ``phase_type`` - Phase type constant (ZIGBEE_AC_PHASE_TYPE_NON_SPECIFIC, ZIGBEE_AC_PHASE_TYPE_A, ZIGBEE_AC_PHASE_TYPE_B, ZIGBEE_AC_PHASE_TYPE_C)
* ``power_factor`` - Power factor value (-100 to 100)
This function will return ``true`` if successful, ``false`` otherwise.
setACReporting
^^^^^^^^^^^^^^
Sets the reporting configuration for AC measurements.
.. code-block:: arduino
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);
* ``measurement_type`` - AC measurement type constant (ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_MEASUREMENT_TYPE_POWER_FACTOR, ZIGBEE_AC_MEASUREMENT_TYPE_FREQUENCY)
* ``phase_type`` - Phase type constant (ZIGBEE_AC_PHASE_TYPE_NON_SPECIFIC, ZIGBEE_AC_PHASE_TYPE_A, ZIGBEE_AC_PHASE_TYPE_B, ZIGBEE_AC_PHASE_TYPE_C)
* ``min_interval`` - Minimum reporting interval in seconds
* ``max_interval`` - Maximum reporting interval in seconds
* ``delta`` - Minimum change required to trigger a report
This function will return ``true`` if successful, ``false`` otherwise.
reportAC
^^^^^^^^
Manually reports an AC measurement value.
.. code-block:: arduino
bool reportAC(ZIGBEE_AC_MEASUREMENT_TYPE measurement_type, ZIGBEE_AC_PHASE_TYPE phase_type);
* ``measurement_type`` - AC measurement type constant (ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_MEASUREMENT_TYPE_POWER_FACTOR, ZIGBEE_AC_MEASUREMENT_TYPE_FREQUENCY)
* ``phase_type`` - Phase type constant (ZIGBEE_AC_PHASE_TYPE_NON_SPECIFIC, ZIGBEE_AC_PHASE_TYPE_A, ZIGBEE_AC_PHASE_TYPE_B, ZIGBEE_AC_PHASE_TYPE_C)
This function will return ``true`` if successful, ``false`` otherwise.
Example
-------
DC Electrical Measurement
*************************
.. literalinclude:: ../../../libraries/Zigbee/examples/Zigbee_Electrical_DC_Sensor/Zigbee_Electrical_DC_Sensor.ino
:language: arduino
AC Electrical Measurement
*************************
.. literalinclude:: ../../../libraries/Zigbee/examples/Zigbee_Electrical_AC_Sensor_MultiPhase/Zigbee_Electrical_AC_Sensor_MultiPhase.ino
:language: arduino

View file

@ -0,0 +1,119 @@
################
ZigbeeFlowSensor
################
About
-----
The ``ZigbeeFlowSensor`` class provides a flow sensor endpoint for Zigbee networks. This endpoint implements the Zigbee Home Automation (HA) standard for liquid and gas flow measurement devices.
**Features:**
* Flow rate measurement in m³/h
* Configurable measurement range
* Tolerance and reporting configuration
* Automatic reporting capabilities
* Integration with common endpoint features (binding, OTA, etc.)
* Zigbee HA standard compliance
**Use Cases:**
* Water flow monitoring
* Gas flow measurement
* Industrial process monitoring
* Smart home water management
* HVAC system flow monitoring
* Agricultural irrigation systems
API Reference
-------------
Constructor
***********
ZigbeeFlowSensor
^^^^^^^^^^^^^^^^
Creates a new Zigbee flow sensor endpoint.
.. code-block:: arduino
ZigbeeFlowSensor(uint8_t endpoint);
* ``endpoint`` - Endpoint number (1-254)
API Methods
***********
setFlow
^^^^^^^
Sets the flow rate measurement value.
.. code-block:: arduino
bool setFlow(float value);
* ``value`` - Flow rate value in 0.1 m³/h
This function will return ``true`` if successful, ``false`` otherwise.
setMinMaxValue
^^^^^^^^^^^^^^
Sets the minimum and maximum measurement values.
.. code-block:: arduino
bool setMinMaxValue(float min, float max);
* ``min`` - Minimum flow rate value in 0.1 m³/h
* ``max`` - Maximum flow rate value in 0.1 m³/h
This function will return ``true`` if successful, ``false`` otherwise.
setTolerance
^^^^^^^^^^^^
Sets the tolerance value for measurements.
.. code-block:: arduino
bool setTolerance(float tolerance);
* ``tolerance`` - Tolerance value in 0.01 m³/h
This function will return ``true`` if successful, ``false`` otherwise.
setReporting
^^^^^^^^^^^^
Sets the reporting configuration for flow rate measurements.
.. code-block:: arduino
bool setReporting(uint16_t min_interval, uint16_t max_interval, float delta);
* ``min_interval`` - Minimum reporting interval in seconds
* ``max_interval`` - Maximum reporting interval in seconds
* ``delta`` - Minimum change required to trigger a report in 0.1 m³/h
This function will return ``true`` if successful, ``false`` otherwise.
report
^^^^^^
Manually reports the current flow rate value.
.. code-block:: arduino
bool report();
This function will return ``true`` if successful, ``false`` otherwise.
Example
-------
Flow + PressureSensor Implementation
************************************
.. literalinclude:: ../../../libraries/Zigbee/examples/Zigbee_Pressure_Flow_Sensor/Zigbee_Pressure_Flow_Sensor.ino
:language: arduino

View file

@ -0,0 +1,35 @@
#############
ZigbeeGateway
#############
About
-----
The ``ZigbeeGateway`` class provides a gateway endpoint for Zigbee networks. This endpoint implements the Zigbee Home Automation (HA) standard for network coordination and gateway functionality.
Gateway is a device that can be used to bridge Zigbee network to other networks (e.g. Wi-Fi, Ethernet, etc.).
API Reference
-------------
Constructor
***********
ZigbeeGateway
^^^^^^^^^^^^^
Creates a new Zigbee gateway endpoint.
.. code-block:: arduino
ZigbeeGateway(uint8_t endpoint);
* ``endpoint`` - Endpoint number (1-254)
Example
-------
Gateway Implementation
**********************
.. literalinclude:: ../../../libraries/Zigbee/examples/Zigbee_Gateway/Zigbee_Gateway.ino
:language: arduino

View file

@ -0,0 +1,109 @@
#######################
ZigbeeIlluminanceSensor
#######################
About
-----
The ``ZigbeeIlluminanceSensor`` class provides an endpoint for illuminance sensors in Zigbee networks. This endpoint implements the Zigbee Home Automation (HA) standard for light level measurement devices, supporting ambient light monitoring.
**Features:**
* Illuminance measurement in lux
* Configurable measurement range
* Tolerance and reporting configuration
* Automatic reporting capabilities
API Reference
-------------
Constructor
***********
ZigbeeIlluminanceSensor
^^^^^^^^^^^^^^^^^^^^^^^
Creates a new Zigbee illuminance sensor endpoint.
.. code-block:: arduino
ZigbeeIlluminanceSensor(uint8_t endpoint);
* ``endpoint`` - Endpoint number (1-254)
API Methods
***********
setIlluminance
^^^^^^^^^^^^^^
Sets the illuminance measurement value.
.. code-block:: arduino
bool setIlluminance(uint16_t value);
* ``value`` - Illuminance value in lux
This function will return ``true`` if successful, ``false`` otherwise.
setMinMaxValue
^^^^^^^^^^^^^^
Sets the minimum and maximum measurement values.
.. code-block:: arduino
bool setMinMaxValue(uint16_t min, uint16_t max);
* ``min`` - Minimum illuminance value in lux
* ``max`` - Maximum illuminance value in lux
This function will return ``true`` if successful, ``false`` otherwise.
setTolerance
^^^^^^^^^^^^
Sets the tolerance value for measurements.
.. code-block:: arduino
bool setTolerance(uint16_t tolerance);
* ``tolerance`` - Tolerance value in lux
This function will return ``true`` if successful, ``false`` otherwise.
setReporting
^^^^^^^^^^^^
Sets the reporting configuration for illuminance measurements.
.. code-block:: arduino
bool setReporting(uint16_t min_interval, uint16_t max_interval, uint16_t delta);
* ``min_interval`` - Minimum reporting interval in seconds
* ``max_interval`` - Maximum reporting interval in seconds
* ``delta`` - Minimum change required to trigger a report in lux
This function will return ``true`` if successful, ``false`` otherwise.
report
^^^^^^
Manually reports the current illuminance value.
.. code-block:: arduino
bool report();
This function will return ``true`` if successful, ``false`` otherwise.
Example
-------
Illuminance Sensor Implementation
*********************************
.. literalinclude:: ../../../libraries/Zigbee/examples/Zigbee_Illuminance_Sensor/Zigbee_Illuminance_Sensor.ino
:language: arduino

View file

@ -0,0 +1,88 @@
###########
ZigbeeLight
###########
About
-----
The ``ZigbeeLight`` class provides a simple on/off light endpoint for Zigbee networks. This endpoint implements the Zigbee Home Automation (HA) standard for basic lighting control.
**Features:**
* Simple on/off control
* State change callbacks
API Reference
-------------
Constructor
***********
ZigbeeLight
^^^^^^^^^^^
Creates a new Zigbee light endpoint.
.. code-block:: arduino
ZigbeeLight(uint8_t endpoint);
* ``endpoint`` - Endpoint number (1-254)
Light Control
*************
setLight
^^^^^^^^
Sets the light state (on or off).
.. code-block:: arduino
bool setLight(bool state);
* ``state`` - ``true`` to turn on, ``false`` to turn off
This function will return ``true`` if successful, ``false`` otherwise.
getLightState
^^^^^^^^^^^^^
Gets the current light state.
.. code-block:: arduino
bool getLightState();
This function will return current light state (``true`` = on, ``false`` = off).
restoreLight
^^^^^^^^^^^^
Restores the light state and triggers any registered callbacks.
.. code-block:: arduino
void restoreLight();
Event Handling
**************
onLightChange
^^^^^^^^^^^^^
Sets a callback function to be called when the light state changes.
.. code-block:: arduino
void onLightChange(void (*callback)(bool));
* ``callback`` - Function to call when light state changes
Example
-------
Basic Light Implementation
**************************
.. literalinclude:: ../../../libraries/Zigbee/examples/Zigbee_On_Off_Light/Zigbee_On_Off_Light.ino
:language: arduino

View file

@ -0,0 +1,81 @@
#####################
ZigbeeOccupancySensor
#####################
About
-----
The ``ZigbeeOccupancySensor`` class provides an endpoint for occupancy sensors in Zigbee networks. This endpoint implements the Zigbee Home Automation (HA) standard for occupancy detection devices, supporting various sensor types for detecting presence.
**Features:**
* Occupancy detection (occupied/unoccupied)
* Multiple sensor type support (PIR, ultrasonic, etc.)
* Automatic reporting capabilities
* Integration with common endpoint features (binding, OTA, etc.)
* Zigbee HA standard compliance
API Reference
-------------
Constructor
***********
ZigbeeOccupancySensor
^^^^^^^^^^^^^^^^^^^^^
Creates a new Zigbee occupancy sensor endpoint.
.. code-block:: arduino
ZigbeeOccupancySensor(uint8_t endpoint);
* ``endpoint`` - Endpoint number (1-254)
API Methods
***********
setOccupancy
^^^^^^^^^^^^
Sets the occupancy state.
.. code-block:: arduino
bool setOccupancy(bool occupied);
* ``occupied`` - Occupancy state (true = occupied, false = unoccupied)
This function will return ``true`` if successful, ``false`` otherwise.
setSensorType
^^^^^^^^^^^^^
Sets the sensor type.
.. code-block:: arduino
bool setSensorType(uint8_t sensor_type);
* ``sensor_type`` - Sensor type identifier (see esp_zb_zcl_occupancy_sensing_occupancy_sensor_type_t)
This function will return ``true`` if successful, ``false`` otherwise.
report
^^^^^^
Manually reports the current occupancy state.
.. code-block:: arduino
bool report();
This function will return ``true`` if successful, ``false`` otherwise.
Example
-------
Occupancy Sensor Implementation
*******************************
.. literalinclude:: ../../../libraries/Zigbee/examples/Zigbee_Occupancy_Sensor/Zigbee_Occupancy_Sensor.ino
:language: arduino

View file

@ -0,0 +1,109 @@
################
ZigbeePM25Sensor
################
About
-----
The ``ZigbeePM25Sensor`` class provides a PM2.5 air quality sensor endpoint for Zigbee networks. This endpoint implements the Zigbee Home Automation (HA) standard for particulate matter measurement devices.
**Features:**
* PM2.5 concentration measurement in μg/m³
* Configurable measurement range
* Tolerance and reporting configuration
* Automatic reporting capabilities
API Reference
-------------
Constructor
***********
ZigbeePM25Sensor
^^^^^^^^^^^^^^^^
Creates a new Zigbee PM2.5 sensor endpoint.
.. code-block:: arduino
ZigbeePM25Sensor(uint8_t endpoint);
* ``endpoint`` - Endpoint number (1-254)
API Methods
***********
setPM25
^^^^^^^
Sets the PM2.5 concentration measurement value.
.. code-block:: arduino
bool setPM25(float pm25);
* ``pm25`` - PM2.5 concentration value in 0.1 μg/m³
This function will return ``true`` if successful, ``false`` otherwise.
setMinMaxValue
^^^^^^^^^^^^^^
Sets the minimum and maximum measurement values.
.. code-block:: arduino
bool setMinMaxValue(float min, float max);
* ``min`` - Minimum PM2.5 concentration value in 0.1 μg/m³
* ``max`` - Maximum PM2.5 concentration value in 0.1 μg/m³
This function will return ``true`` if successful, ``false`` otherwise.
setTolerance
^^^^^^^^^^^^
Sets the tolerance value for measurements.
.. code-block:: arduino
bool setTolerance(float tolerance);
* ``tolerance`` - Tolerance value in 0.1 μg/m³
This function will return ``true`` if successful, ``false`` otherwise.
setReporting
^^^^^^^^^^^^
Sets the reporting configuration for PM2.5 measurements.
.. code-block:: arduino
bool setReporting(uint16_t min_interval, uint16_t max_interval, float delta);
* ``min_interval`` - Minimum reporting interval in seconds
* ``max_interval`` - Maximum reporting interval in seconds
* ``delta`` - Minimum change required to trigger a report in 0.1 μg/m³
This function will return ``true`` if successful, ``false`` otherwise.
report
^^^^^^
Manually reports the current PM2.5 concentration value.
.. code-block:: arduino
bool report();
This function will return ``true`` if successful, ``false`` otherwise.
Example
-------
PM2.5 Sensor Implementation
***************************
.. literalinclude:: ../../../libraries/Zigbee/examples/Zigbee_PM25_Sensor/Zigbee_PM25_Sensor.ino
:language: arduino

View file

@ -0,0 +1,88 @@
#################
ZigbeePowerOutlet
#################
About
-----
The ``ZigbeePowerOutlet`` class provides a smart power outlet endpoint for Zigbee networks. This endpoint implements the Zigbee Home Automation (HA) standard for power control, allowing remote on/off control of electrical devices.
**Features:**
* On/off power control
* State change callbacks
API Reference
-------------
Constructor
***********
ZigbeePowerOutlet
^^^^^^^^^^^^^^^^^
Creates a new Zigbee power outlet endpoint.
.. code-block:: arduino
ZigbeePowerOutlet(uint8_t endpoint);
* ``endpoint`` - Endpoint number (1-254)
Power Control
*************
setState
^^^^^^^^
Sets the power outlet state (on or off).
.. code-block:: arduino
bool setState(bool state);
* ``state`` - ``true`` to turn on, ``false`` to turn off
This function will return ``true`` if successful, ``false`` otherwise.
getPowerOutletState
^^^^^^^^^^^^^^^^^^^
Gets the current power outlet state.
.. code-block:: arduino
bool getPowerOutletState();
This function will return current power state (``true`` = on, ``false`` = off).
restoreState
^^^^^^^^^^^^
Restores the power outlet state and triggers any registered callbacks.
.. code-block:: arduino
void restoreState();
Event Handling
**************
onPowerOutletChange
^^^^^^^^^^^^^^^^^^^
Sets a callback function to be called when the power outlet state changes.
.. code-block:: arduino
void onPowerOutletChange(void (*callback)(bool));
* ``callback`` - Function to call when power outlet state changes
Example
-------
Smart Power Outlet Implementation
*********************************
.. literalinclude:: ../../../libraries/Zigbee/examples/Zigbee_Power_Outlet/Zigbee_Power_Outlet.ino
:language: arduino

View file

@ -0,0 +1,109 @@
####################
ZigbeePressureSensor
####################
About
-----
The ``ZigbeePressureSensor`` class provides an endpoint for pressure sensors in Zigbee networks. This endpoint implements the Zigbee Home Automation (HA) standard for pressure measurement devices, supporting atmospheric pressure, barometric pressure, and other pressure measurements.
**Features:**
* Pressure measurement in hPa (hectopascals)
* Configurable measurement range
* Tolerance and reporting configuration
* Automatic reporting capabilities
API Reference
-------------
Constructor
***********
ZigbeePressureSensor
^^^^^^^^^^^^^^^^^^^^
Creates a new Zigbee pressure sensor endpoint.
.. code-block:: arduino
ZigbeePressureSensor(uint8_t endpoint);
* ``endpoint`` - Endpoint number (1-254)
API Methods
***********
setPressure
^^^^^^^^^^^
Sets the pressure measurement value.
.. code-block:: arduino
bool setPressure(int16_t value);
* ``value`` - Pressure value in hPa
This function will return ``true`` if successful, ``false`` otherwise.
setMinMaxValue
^^^^^^^^^^^^^^
Sets the minimum and maximum measurement values.
.. code-block:: arduino
bool setMinMaxValue(int16_t min, int16_t max);
* ``min`` - Minimum pressure value in hPa
* ``max`` - Maximum pressure value in hPa
This function will return ``true`` if successful, ``false`` otherwise.
setTolerance
^^^^^^^^^^^^
Sets the tolerance value for measurements.
.. code-block:: arduino
bool setTolerance(uint16_t tolerance);
* ``tolerance`` - Tolerance value in hPa
This function will return ``true`` if successful, ``false`` otherwise.
setReporting
^^^^^^^^^^^^
Sets the reporting configuration for pressure measurements.
.. code-block:: arduino
bool setReporting(uint16_t min_interval, uint16_t max_interval, uint16_t delta);
* ``min_interval`` - Minimum reporting interval in seconds
* ``max_interval`` - Maximum reporting interval in seconds
* ``delta`` - Minimum change required to trigger a report in hPa
This function will return ``true`` if successful, ``false`` otherwise.
report
^^^^^^
Manually reports the current pressure value.
.. code-block:: arduino
bool report();
This function will return ``true`` if successful, ``false`` otherwise.
Example
-------
Pressure + Flow Sensor Implementation
*************************************
.. literalinclude:: ../../../libraries/Zigbee/examples/Zigbee_Pressure_Flow_Sensor/Zigbee_Pressure_Flow_Sensor.ino
:language: arduino

View file

@ -0,0 +1,34 @@
###################
ZigbeeRangeExtender
###################
About
-----
The ``ZigbeeRangeExtender`` class provides a range extender endpoint for Zigbee networks. This endpoint implements the Zigbee Home Automation (HA) standard for range extender devices that help extend the coverage of Zigbee networks by acting as repeaters.
API Reference
-------------
Constructor
***********
ZigbeeRangeExtender
^^^^^^^^^^^^^^^^^^^
Creates a new Zigbee range extender endpoint.
.. code-block:: arduino
ZigbeeRangeExtender(uint8_t endpoint);
* ``endpoint`` - Endpoint number (1-254)
Example
-------
Range Extender Implementation
*****************************
.. literalinclude:: ../../../libraries/Zigbee/examples/Zigbee_Range_Extender/Zigbee_Range_Extender.ino
:language: arduino

View file

@ -0,0 +1,136 @@
############
ZigbeeSwitch
############
About
-----
The ``ZigbeeSwitch`` class provides a switch endpoint for Zigbee networks. This endpoint implements the Zigbee Home Automation (HA) standard for controlling other devices (typically lights) through on/off commands.
**Features:**
* On/off control commands for bound devices
* Group control support
* Direct device addressing
API Reference
-------------
Constructor
***********
ZigbeeSwitch
^^^^^^^^^^^^
Creates a new Zigbee switch endpoint.
.. code-block:: arduino
ZigbeeSwitch(uint8_t endpoint);
* ``endpoint`` - Endpoint number (1-254)
Basic Control Commands
**********************
lightToggle
^^^^^^^^^^^
Toggles the state of bound lights (on to off, or off to on).
.. code-block:: arduino
void lightToggle();
void lightToggle(uint16_t group_addr);
void lightToggle(uint8_t endpoint, uint16_t short_addr);
void lightToggle(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr);
* ``group_addr`` - Group address to control (optional)
* ``endpoint`` - Target device endpoint (optional)
* ``short_addr`` - Target device short address (optional)
* ``ieee_addr`` - Target device IEEE address (optional)
lightOn
^^^^^^^
Turns on bound lights.
.. code-block:: arduino
void lightOn();
void lightOn(uint16_t group_addr);
void lightOn(uint8_t endpoint, uint16_t short_addr);
void lightOn(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr);
* ``group_addr`` - Group address to control (optional)
* ``endpoint`` - Target device endpoint (optional)
* ``short_addr`` - Target device short address (optional)
* ``ieee_addr`` - Target device IEEE address (optional)
lightOff
^^^^^^^^
Turns off bound lights.
.. code-block:: arduino
void lightOff();
void lightOff(uint16_t group_addr);
void lightOff(uint8_t endpoint, uint16_t short_addr);
void lightOff(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr);
* ``group_addr`` - Group address to control (optional)
* ``endpoint`` - Target device endpoint (optional)
* ``short_addr`` - Target device short address (optional)
* ``ieee_addr`` - Target device IEEE address (optional)
Advanced Control Commands
*************************
lightOffWithEffect
^^^^^^^^^^^^^^^^^^
Turns off lights with a specific effect.
.. code-block:: arduino
void lightOffWithEffect(uint8_t effect_id, uint8_t effect_variant);
* ``effect_id`` - Effect identifier
* ``effect_variant`` - Effect variant
lightOnWithTimedOff
^^^^^^^^^^^^^^^^^^^
Turns on lights with automatic turn-off after specified time.
.. code-block:: arduino
void lightOnWithTimedOff(uint8_t on_off_control, uint16_t time_on, uint16_t time_off);
* ``on_off_control`` - Control byte
* ``time_on`` - Time to stay on (in 1/10th seconds)
* ``time_off`` - Time to stay off (in 1/10th seconds)
lightOnWithSceneRecall
^^^^^^^^^^^^^^^^^^^^^^
Turns on lights by recalling a scene.
.. code-block:: arduino
void lightOnWithSceneRecall();
Example
-------
Basic Switch Implementation
***************************
.. literalinclude:: ../../../libraries/Zigbee/examples/Zigbee_On_Off_Switch/Zigbee_On_Off_Switch.ino
:language: arduino
Multi Switch Implementation
***************************
.. literalinclude:: ../../../libraries/Zigbee/examples/Zigbee_On_Off_MultiSwitch/Zigbee_On_Off_MultiSwitch.ino
:language: arduino

View file

@ -0,0 +1,184 @@
################
ZigbeeTempSensor
################
About
-----
The ``ZigbeeTempSensor`` class provides a temperature and humidity sensor endpoint for Zigbee networks. This endpoint implements the Zigbee Home Automation (HA) standard for environmental monitoring with configurable reporting intervals and thresholds.
**Features:**
* Temperature measurement and reporting
* Optional humidity measurement
* Configurable reporting intervals
* Min/max value and tolerance settings
API Reference
-------------
Constructor
***********
ZigbeeTempSensor
^^^^^^^^^^^^^^^^
Creates a new Zigbee temperature sensor endpoint.
.. code-block:: arduino
ZigbeeTempSensor(uint8_t endpoint);
* ``endpoint`` - Endpoint number (1-254)
Temperature Control
*******************
setTemperature
^^^^^^^^^^^^^^
Sets the temperature value in 0.01°C resolution.
.. code-block:: arduino
bool setTemperature(float value);
* ``value`` - Temperature value in degrees Celsius
This function will return ``true`` if successful, ``false`` otherwise.
setMinMaxValue
^^^^^^^^^^^^^^
Sets the minimum and maximum temperature values for the sensor.
.. code-block:: arduino
bool setMinMaxValue(float min, float max);
* ``min`` - Minimum temperature value in degrees Celsius
* ``max`` - Maximum temperature value in degrees Celsius
This function will return ``true`` if successful, ``false`` otherwise.
setTolerance
^^^^^^^^^^^^
Sets the tolerance value for temperature reporting.
.. code-block:: arduino
bool setTolerance(float tolerance);
* ``tolerance`` - Tolerance value in degrees Celsius
This function will return ``true`` if successful, ``false`` otherwise.
setReporting
^^^^^^^^^^^^
Sets the reporting interval for temperature measurements.
.. code-block:: arduino
bool setReporting(uint16_t min_interval, uint16_t max_interval, float delta);
* ``min_interval`` - Minimum reporting interval in seconds
* ``max_interval`` - Maximum reporting interval in seconds
* ``delta`` - Minimum change in temperature to trigger report (in 0.01°C)
This function will return ``true`` if successful, ``false`` otherwise.
reportTemperature
^^^^^^^^^^^^^^^^^
Manually reports the current temperature value.
.. code-block:: arduino
bool reportTemperature();
This function will return ``true`` if successful, ``false`` otherwise.
Humidity Control (Optional)
***************************
addHumiditySensor
^^^^^^^^^^^^^^^^^
Adds humidity measurement capability to the temperature sensor.
.. code-block:: arduino
void addHumiditySensor(float min, float max, float tolerance);
* ``min`` - Minimum humidity value in percentage
* ``max`` - Maximum humidity value in percentage
* ``tolerance`` - Tolerance value in percentage
setHumidity
^^^^^^^^^^^
Sets the humidity value in 0.01% resolution.
.. code-block:: arduino
bool setHumidity(float value);
* ``value`` - Humidity value in percentage (0-100)
This function will return ``true`` if successful, ``false`` otherwise.
setHumidityReporting
^^^^^^^^^^^^^^^^^^^^
Sets the reporting interval for humidity measurements.
.. code-block:: arduino
bool setHumidityReporting(uint16_t min_interval, uint16_t max_interval, float delta);
* ``min_interval`` - Minimum reporting interval in seconds
* ``max_interval`` - Maximum reporting interval in seconds
* ``delta`` - Minimum change in humidity to trigger report (in 0.01%)
This function will return ``true`` if successful, ``false`` otherwise.
reportHumidity
^^^^^^^^^^^^^^
Manually reports the current humidity value.
.. code-block:: arduino
bool reportHumidity();
This function will return ``true`` if successful, ``false`` otherwise.
Combined Reporting
******************
report
^^^^^^
Reports both temperature and humidity values if humidity sensor is enabled.
.. code-block:: arduino
bool report();
This function will return ``true`` if successful, ``false`` otherwise.
Example
-------
Temperature Sensor Implementation
*********************************
.. literalinclude:: ../../../libraries/Zigbee/examples/Zigbee_Temperature_Sensor/Zigbee_Temperature_Sensor.ino
:language: arduino
Temperature + Humidity Sleepy Sensor Implementation
***************************************************
.. literalinclude:: ../../../libraries/Zigbee/examples/Zigbee_Temp_Hum_Sensor_Sleepy/Zigbee_Temp_Hum_Sensor_Sleepy.ino
:language: arduino

View file

@ -0,0 +1,238 @@
################
ZigbeeThermostat
################
About
-----
The ``ZigbeeThermostat`` class provides a thermostat endpoint for Zigbee networks that receives temperature data from temperature sensors. This endpoint implements the Zigbee Home Automation (HA) standard for thermostats that can bind to temperature sensors and receive temperature readings.
**Features:**
* Automatic discovery and binding to temperature sensors
* Temperature data reception from bound sensors
* Configurable temperature reporting intervals
* Sensor settings retrieval (min/max temperature, tolerance)
* Multiple addressing modes (group, specific endpoint, IEEE address)
API Reference
-------------
Constructor
***********
ZigbeeThermostat
^^^^^^^^^^^^^^^^
Creates a new Zigbee thermostat endpoint.
.. code-block:: arduino
ZigbeeThermostat(uint8_t endpoint);
* ``endpoint`` - Endpoint number (1-254)
Event Handling
**************
onTempReceive
^^^^^^^^^^^^^
Sets a callback function for receiving temperature data.
.. code-block:: arduino
void onTempReceive(void (*callback)(float temperature));
* ``callback`` - Function to call when temperature data is received
* ``temperature`` - Temperature value in degrees Celsius
onTempReceiveWithSource
^^^^^^^^^^^^^^^^^^^^^^^
Sets a callback function for receiving temperature data with source information.
.. code-block:: arduino
void onTempReceiveWithSource(void (*callback)(float temperature, uint8_t src_endpoint, esp_zb_zcl_addr_t src_address));
* ``callback`` - Function to call when temperature data is received
* ``temperature`` - Temperature value in degrees Celsius
* ``src_endpoint`` - Source endpoint that sent the temperature data
* ``src_address`` - Source address information
onConfigReceive
^^^^^^^^^^^^^^^
Sets a callback function for receiving sensor configuration data.
.. code-block:: arduino
void onConfigReceive(void (*callback)(float min_temp, float max_temp, float tolerance));
* ``callback`` - Function to call when sensor configuration is received
* ``min_temp`` - Minimum temperature supported by the sensor
* ``max_temp`` - Maximum temperature supported by the sensor
* ``tolerance`` - Temperature tolerance of the sensor
Temperature Data Retrieval
**************************
getTemperature
^^^^^^^^^^^^^^
Requests temperature data from all bound sensors.
.. code-block:: arduino
void getTemperature();
getTemperature (Group)
^^^^^^^^^^^^^^^^^^^^^^
Requests temperature data from a specific group.
.. code-block:: arduino
void getTemperature(uint16_t group_addr);
* ``group_addr`` - Group address to send the request to
getTemperature (Endpoint + Short Address)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Requests temperature data from a specific endpoint using short address.
.. code-block:: arduino
void getTemperature(uint8_t endpoint, uint16_t short_addr);
* ``endpoint`` - Target endpoint number
* ``short_addr`` - Short address of the target device
getTemperature (Endpoint + IEEE Address)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Requests temperature data from a specific endpoint using IEEE address.
.. code-block:: arduino
void getTemperature(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr);
* ``endpoint`` - Target endpoint number
* ``ieee_addr`` - IEEE address of the target device
Sensor Settings Retrieval
*************************
getSensorSettings
^^^^^^^^^^^^^^^^^
Requests sensor settings from all bound sensors.
.. code-block:: arduino
void getSensorSettings();
getSensorSettings (Group)
^^^^^^^^^^^^^^^^^^^^^^^^^
Requests sensor settings from a specific group.
.. code-block:: arduino
void getSensorSettings(uint16_t group_addr);
* ``group_addr`` - Group address to send the request to
getSensorSettings (Endpoint + Short Address)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Requests sensor settings from a specific endpoint using short address.
.. code-block:: arduino
void getSensorSettings(uint8_t endpoint, uint16_t short_addr);
* ``endpoint`` - Target endpoint number
* ``short_addr`` - Short address of the target device
getSensorSettings (Endpoint + IEEE Address)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Requests sensor settings from a specific endpoint using IEEE address.
.. code-block:: arduino
void getSensorSettings(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr);
* ``endpoint`` - Target endpoint number
* ``ieee_addr`` - IEEE address of the target device
Temperature Reporting Configuration
***********************************
setTemperatureReporting
^^^^^^^^^^^^^^^^^^^^^^^
Configures temperature reporting for all bound sensors.
.. code-block:: arduino
void setTemperatureReporting(uint16_t min_interval, uint16_t max_interval, float delta);
* ``min_interval`` - Minimum reporting interval in seconds
* ``max_interval`` - Maximum reporting interval in seconds
* ``delta`` - Minimum change in temperature to trigger a report
setTemperatureReporting (Group)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Configures temperature reporting for a specific group.
.. code-block:: arduino
void setTemperatureReporting(uint16_t group_addr, uint16_t min_interval, uint16_t max_interval, float delta);
* ``group_addr`` - Group address to configure
* ``min_interval`` - Minimum reporting interval in seconds
* ``max_interval`` - Maximum reporting interval in seconds
* ``delta`` - Minimum change in temperature to trigger a report
setTemperatureReporting (Endpoint + Short Address)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Configures temperature reporting for a specific endpoint using short address.
.. code-block:: arduino
void setTemperatureReporting(uint8_t endpoint, uint16_t short_addr, uint16_t min_interval, uint16_t max_interval, float delta);
* ``endpoint`` - Target endpoint number
* ``short_addr`` - Short address of the target device
* ``min_interval`` - Minimum reporting interval in seconds
* ``max_interval`` - Maximum reporting interval in seconds
* ``delta`` - Minimum change in temperature to trigger a report
setTemperatureReporting (Endpoint + IEEE Address)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Configures temperature reporting for a specific endpoint using IEEE address.
.. code-block:: arduino
void setTemperatureReporting(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr, uint16_t min_interval, uint16_t max_interval, float delta);
* ``endpoint`` - Target endpoint number
* ``ieee_addr`` - IEEE address of the target device
* ``min_interval`` - Minimum reporting interval in seconds
* ``max_interval`` - Maximum reporting interval in seconds
* ``delta`` - Minimum change in temperature to trigger a report
Example
-------
Thermostat Implementation
*************************
.. literalinclude:: ../../../libraries/Zigbee/examples/Zigbee_Thermostat/Zigbee_Thermostat.ino
:language: arduino

View file

@ -0,0 +1,87 @@
#####################
ZigbeeVibrationSensor
#####################
About
-----
The ``ZigbeeVibrationSensor`` class provides a vibration sensor endpoint for Zigbee networks. This endpoint implements the Zigbee Home Automation (HA) standard for vibration detection devices.
**Features:**
* Vibration detection and measurement
* Configurable sensitivity levels
* Multiple detection modes
* Automatic reporting capabilities
* Integration with common endpoint features (binding, OTA, etc.)
* Zigbee HA standard compliance
**Use Cases:**
* Security system vibration detection
* Industrial equipment monitoring
* Structural health monitoring
* Smart home security applications
* Machine condition monitoring
API Reference
-------------
Constructor
***********
ZigbeeVibrationSensor
^^^^^^^^^^^^^^^^^^^^^
Creates a new Zigbee vibration sensor endpoint.
.. code-block:: arduino
ZigbeeVibrationSensor(uint8_t endpoint);
* ``endpoint`` - Endpoint number (1-254)
API Methods
***********
setVibration
^^^^^^^^^^^^
Sets the vibration detection state.
.. code-block:: arduino
bool setVibration(bool sensed);
* ``sensed`` - Vibration state (true = sensed, false = not sensed)
This function will return ``true`` if successful, ``false`` otherwise.
setIASClientEndpoint
^^^^^^^^^^^^^^^^^^^^
Sets the IAS Client endpoint number (default is 1).
.. code-block:: arduino
void setIASClientEndpoint(uint8_t ep_number);
* ``ep_number`` - IAS Client endpoint number
report
^^^^^^
Manually reports the current vibration state.
.. code-block:: arduino
void report();
This function does not return a value.
Example
-------
Vibration Sensor Implementation
*******************************
.. literalinclude:: ../../../libraries/Zigbee/examples/Zigbee_Vibration_Sensor/Zigbee_Vibration_Sensor.ino
:language: arduino

View file

@ -0,0 +1,119 @@
#####################
ZigbeeWindSpeedSensor
#####################
About
-----
The ``ZigbeeWindSpeedSensor`` class provides a wind speed sensor endpoint for Zigbee networks. This endpoint implements the Zigbee Home Automation (HA) standard for wind speed measurement devices.
**Features:**
* Wind speed measurement in m/s
* Configurable measurement range
* Tolerance and reporting configuration
* Automatic reporting capabilities
* Integration with common endpoint features (binding, OTA, etc.)
* Zigbee HA standard compliance
**Use Cases:**
* Weather stations
* Wind turbine monitoring
* Agricultural weather monitoring
* Marine applications
* Smart home weather systems
* Industrial wind monitoring
API Reference
-------------
Constructor
***********
ZigbeeWindSpeedSensor
^^^^^^^^^^^^^^^^^^^^^
Creates a new Zigbee wind speed sensor endpoint.
.. code-block:: arduino
ZigbeeWindSpeedSensor(uint8_t endpoint);
* ``endpoint`` - Endpoint number (1-254)
API Methods
***********
setWindSpeed
^^^^^^^^^^^^
Sets the wind speed measurement value.
.. code-block:: arduino
bool setWindSpeed(float value);
* ``value`` - Wind speed value in 0.01 m/s
This function will return ``true`` if successful, ``false`` otherwise.
setMinMaxValue
^^^^^^^^^^^^^^
Sets the minimum and maximum measurement values.
.. code-block:: arduino
bool setMinMaxValue(float min, float max);
* ``min`` - Minimum wind speed value in 0.01 m/s
* ``max`` - Maximum wind speed value in 0.01 m/s
This function will return ``true`` if successful, ``false`` otherwise.
setTolerance
^^^^^^^^^^^^
Sets the tolerance value for measurements.
.. code-block:: arduino
bool setTolerance(float tolerance);
* ``tolerance`` - Tolerance value in 0.01 m/s
This function will return ``true`` if successful, ``false`` otherwise.
setReporting
^^^^^^^^^^^^
Sets the reporting configuration for wind speed measurements.
.. code-block:: arduino
bool setReporting(uint16_t min_interval, uint16_t max_interval, float delta);
* ``min_interval`` - Minimum reporting interval in seconds
* ``max_interval`` - Maximum reporting interval in seconds
* ``delta`` - Minimum change required to trigger a report in 0.01 m/s
This function will return ``true`` if successful, ``false`` otherwise.
reportWindSpeed
^^^^^^^^^^^^^^^
Manually reports the current wind speed value.
.. code-block:: arduino
bool reportWindSpeed();
This function will return ``true`` if successful, ``false`` otherwise.
Example
-------
Wind Speed Sensor Implementation
********************************
.. literalinclude:: ../../../libraries/Zigbee/examples/Zigbee_Wind_Speed_Sensor/Zigbee_Wind_Speed_Sensor.ino
:language: arduino

View file

@ -0,0 +1,233 @@
####################
ZigbeeWindowCovering
####################
About
-----
The ``ZigbeeWindowCovering`` class provides a window covering endpoint for Zigbee networks. This endpoint implements the Zigbee Home Automation (HA) standard for motorized blinds, shades, and other window coverings.
**Features:**
* Position control (lift and tilt)
* Multiple window covering types support
* Configurable operation modes and limits
* Status reporting and callbacks
* Safety features and limits
**Supported Window Covering Types:**
* ROLLERSHADE - Lift support
* ROLLERSHADE_2_MOTOR - Lift support
* ROLLERSHADE_EXTERIOR - Lift support
* ROLLERSHADE_EXTERIOR_2_MOTOR - Lift support
* DRAPERY - Lift support
* AWNING - Lift support
* SHUTTER - Tilt support
* BLIND_TILT_ONLY - Tilt support
* BLIND_LIFT_AND_TILT - Lift and Tilt support
* PROJECTOR_SCREEN - Lift support
API Reference
-------------
Constructor
***********
ZigbeeWindowCovering
^^^^^^^^^^^^^^^^^^^^
Creates a new Zigbee window covering endpoint.
.. code-block:: arduino
ZigbeeWindowCovering(uint8_t endpoint);
* ``endpoint`` - Endpoint number (1-254)
Position Control
****************
setLiftPosition
^^^^^^^^^^^^^^^
Sets the window covering lift position.
.. code-block:: arduino
bool setLiftPosition(uint16_t lift_position);
* ``lift_position`` - Lift position
This function will return ``true`` if successful, ``false`` otherwise.
setLiftPercentage
^^^^^^^^^^^^^^^^^
Sets the window covering lift position as a percentage.
.. code-block:: arduino
bool setLiftPercentage(uint8_t lift_percentage);
* ``lift_percentage`` - Lift percentage (0-100, where 0 is fully closed, 100 is fully open)
This function will return ``true`` if successful, ``false`` otherwise.
setTiltPosition
^^^^^^^^^^^^^^^
Sets the window covering tilt position in degrees.
.. code-block:: arduino
bool setTiltPosition(uint16_t tilt_position);
* ``tilt_position`` - Tilt position in degrees
This function will return ``true`` if successful, ``false`` otherwise.
setTiltPercentage
^^^^^^^^^^^^^^^^^
Sets the window covering tilt position as a percentage.
.. code-block:: arduino
bool setTiltPercentage(uint8_t tilt_percentage);
* ``tilt_percentage`` - Tilt percentage (0-100)
This function will return ``true`` if successful, ``false`` otherwise.
Configuration
*************
setCoveringType
^^^^^^^^^^^^^^^
Sets the window covering type.
.. code-block:: arduino
bool setCoveringType(ZigbeeWindowCoveringType covering_type);
* ``covering_type`` - Window covering type (see supported types above)
This function will return ``true`` if successful, ``false`` otherwise.
setConfigStatus
^^^^^^^^^^^^^^^
Sets the window covering configuration status.
.. code-block:: arduino
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);
* ``operational`` - Operational status
* ``online`` - Online status
* ``commands_reversed`` - Commands reversed flag
* ``lift_closed_loop`` - Lift closed loop flag
* ``tilt_closed_loop`` - Tilt closed loop flag
* ``lift_encoder_controlled`` - Lift encoder controlled flag
* ``tilt_encoder_controlled`` - Tilt encoder controlled flag
This function will return ``true`` if successful, ``false`` otherwise.
setMode
^^^^^^^
Sets the window covering operation mode.
.. code-block:: arduino
bool setMode(bool motor_reversed, bool calibration_mode, bool maintenance_mode, bool leds_on);
* ``motor_reversed`` - Motor reversed flag
* ``calibration_mode`` - Calibration mode flag
* ``maintenance_mode`` - Maintenance mode flag
* ``leds_on`` - LEDs on flag
This function will return ``true`` if successful, ``false`` otherwise.
setLimits
^^^^^^^^^
Sets the motion limits for the window covering.
.. code-block:: arduino
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);
* ``installed_open_limit_lift`` - Installed open limit for lift
* ``installed_closed_limit_lift`` - Installed closed limit for lift
* ``installed_open_limit_tilt`` - Installed open limit for tilt
* ``installed_closed_limit_tilt`` - Installed closed limit for tilt
This function will return ``true`` if successful, ``false`` otherwise.
Event Handling
**************
onOpen
^^^^^^
Sets a callback function to be called when the window covering opens.
.. code-block:: arduino
void onOpen(void (*callback)());
* ``callback`` - Function to call when window covering opens
onClose
^^^^^^^
Sets a callback function to be called when the window covering closes.
.. code-block:: arduino
void onClose(void (*callback)());
* ``callback`` - Function to call when window covering closes
onGoToLiftPercentage
^^^^^^^^^^^^^^^^^^^^
Sets a callback function to be called when lift percentage changes.
.. code-block:: arduino
void onGoToLiftPercentage(void (*callback)(uint8_t));
* ``callback`` - Function to call when lift percentage changes
onGoToTiltPercentage
^^^^^^^^^^^^^^^^^^^^
Sets a callback function to be called when tilt percentage changes.
.. code-block:: arduino
void onGoToTiltPercentage(void (*callback)(uint8_t));
* ``callback`` - Function to call when tilt percentage changes
onStop
^^^^^^
Sets a callback function to be called when window covering stops.
.. code-block:: arduino
void onStop(void (*callback)());
* ``callback`` - Function to call when window covering stops
Example
-------
Window Covering Implementation
******************************
.. literalinclude:: ../../../libraries/Zigbee/examples/Zigbee_Window_Covering/Zigbee_Window_Covering.ino
:language: arduino

159
docs/en/zigbee/zigbee.rst Normal file
View file

@ -0,0 +1,159 @@
######
Zigbee
######
About
-----
The Zigbee library provides support for creating Zigbee 3.0 compatible devices including:
* Support for different Zigbee roles (Coordinator, Router, End Device)
* Network management (scanning, joining, commissioning)
* Multiple endpoint types for various device categories
* OTA (Over-The-Air) update support
* Power management for battery-powered devices
* Time synchronization
* Advanced binding and group management
The Zigbee library is built on top of `ESP-ZIGBEE-SDK <https://github.com/espressif/esp-zigbee-sdk>`_ and provides a high-level Arduino-style interface for creating Zigbee devices.
Zigbee Network Topology
***********************
.. code-block:: text
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Coordinator │◄─────►│ Router │◄─────►│ Router │
│ (Gateway) │ │ (Repeater) │ │ (Thermostat) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ End Device │ │
│ │ (Sensor) │ │
│ └─────────────────┘ │
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ End Device │ │ End Device │
│ (Sensor) │ │ (Sensor) │
└─────────────────┘ └─────────────────┘
**Device Roles**
* **Coordinator**: Forms and manages the network, stores network information
* **Router**: Extends network range, routes messages, mains powered devices (typically lights, switches, etc.)
* **End Device**: Battery-powered devices that can sleep for extended periods (typically sensors)
Zigbee Library Structure
------------------------
**The library is split into three main components:**
* ``ZigbeeCore``: The main class that manages the Zigbee network
* ``ZigbeeEP``: The base class for all Zigbee endpoints, which provides common functionality for all endpoint types
* ``Specific endpoint classes``: The classes for all Zigbee endpoints, which provides the specific functionality for each endpoint type
ZigbeeCore
**********
The ``ZigbeeCore`` class is the main entry point for all Zigbee operations. It serves as the central coordinator that manages:
* **Network Operations**: Starting, stopping, and managing the Zigbee network
* **Device Role Management**: Configuring the device as Coordinator, Router, or End Device
* **Endpoint Management**: Adding and managing multiple device endpoints
* **Network Discovery**: Scanning for and joining existing networks
* **OTA Updates**: Managing over-the-air firmware updates
* **Power Management**: Configuring sleep modes for battery-powered devices
The ``ZigbeeCore`` class is implemented as a singleton, meaning there's only one instance available globally. You access it directly as ``Zigbee`` without creating an instance.
.. toctree::
:maxdepth: 3
zigbee_core
ZigbeeEP
********
The ``ZigbeeEP`` class is the base class for all Zigbee endpoints. It provides common functionality for all endpoint types.
* **Device Information**: Every endpoint can be configured with manufacturer and model information that helps identify the device on the network
* **Binding Management**: Binding allows endpoints to establish direct communication links with other devices. This enables automatic command transmission without requiring manual addressing
* **Power Management**: Endpoints can report their power source type and battery status, which helps the network optimize communication patterns
* **Time Synchronization**: Endpoints can synchronize with network time, enabling time-based operations and scheduling
* **OTA Support**: Endpoints can receive over-the-air firmware updates to add new features or fix bugs
* **Device Discovery**: Endpoints can read manufacturer and model information from other devices on the network
.. toctree::
:maxdepth: 2
zigbee_ep
Specific endpoint classes
*************************
Library provides the following endpoint classes from lights, switches, sensors, etc. Each endpoint class provides the specific functionality for each endpoint type and inherits from the ``ZigbeeEP`` class.
.. toctree::
:maxdepth: 1
:glob:
ep_*
Common Problems and Issues
--------------------------
Troubleshooting
---------------
Common Issues
*************
**Device won't join network**
* Ensure the coordinator is in pairing mode
* Check that the device is configured with the correct role
* Verify the channel mask includes the coordinator's channel
**OTA updates fail**
* Ensure the OTA server is properly configured
* Check that the device has sufficient memory for the update
* Verify network connectivity
**Battery devices not working**
* Ensure proper power source configuration
* Check sleep/wake timing settings
* Verify parent device (router/coordinator) is always powered
**Binding issues**
* Check that both devices support the required clusters
* Verify that binding is enabled on both devices
* Ensure devices are on the same network
**Network connectivity problems**
* Check that devices are within range
* Verify that routers are properly configured
* Check for interference from other 2.4 GHz devices
Factory Reset
*************
If you have problems with connecting to the network, you can try to factory reset the device. This will erase all the network settings and act as brand new device.
.. code-block:: arduino
Zigbee.factoryReset(true); // true = restart after reset
Debug Mode
**********
For better debugging, you can enable debug mode to get detailed information about network operations. Call debug mode before starting Zigbee.
Also selecting zigbee mode with *debug* suffix is recommended.
.. code-block:: arduino
Zigbee.setDebugMode(true);
// Start Zigbee with debug output
Zigbee.begin();

View file

@ -0,0 +1,375 @@
##########
ZigbeeCore
##########
About
-----
The ``ZigbeeCore`` class is the main entry point for all Zigbee operations. It serves as the central class that manages:
* **Network Operations**: Starting, stopping, and managing the Zigbee network
* **Device Role Management**: Configuring the device as Coordinator, Router, or End Device
* **Endpoint Management**: Adding and managing multiple device endpoints
* **Network Discovery**: Scanning for and joining existing networks
ZigbeeCore APIs
---------------
Network Initialization
**********************
begin
^^^^^
Initializes the Zigbee stack and starts the network.
.. code-block:: arduino
bool begin(zigbee_role_t role = ZIGBEE_END_DEVICE, bool erase_nvs = false);
bool begin(esp_zb_cfg_t *role_cfg, bool erase_nvs = false);
* ``role`` - Device role (default: ``ZIGBEE_END_DEVICE``)
* ``role_cfg`` - Custom role configuration structure
* ``erase_nvs`` - Whether to erase NVS storage (default: ``false``)
This function will return ``true`` if initialization successful, ``false`` otherwise.
**Available Roles:**
* **ZIGBEE_COORDINATOR**: Network coordinator, forms and manages the network
* **ZIGBEE_ROUTER**: Network router, connects to existing network and extends network range and routes messages (if device is mains powered, always use this role)
* **ZIGBEE_END_DEVICE**: End device, connects to existing network (typically battery-powered which can sleep)
.. note::
Depending on the Zigbee role, proper Zigbee mode and partition scheme must be set in the Arduino IDE.
* **ZIGBEE_COORDINATOR** and **ZIGBEE_ROUTER**:
* Zigbee mode to ``Zigbee ZCZR (coordinator/router)``.
* Partition scheme to ``Zigbee ZCZR xMB with spiffs`` (where ``x`` is the number of MB of selected flash size).
* **ZIGBEE_END_DEVICE**:
* Zigbee mode to ``Zigbee ED (end device)``.
* Partition scheme to ``Zigbee xMB with spiffs`` (where ``x`` is the number of MB of selected flash size).
Network Status
**************
started
^^^^^^^
Checks if the Zigbee stack has been started.
.. code-block:: arduino
bool started();
This function will return ``true`` if Zigbee stack is running, ``false`` otherwise.
connected
^^^^^^^^^
Checks if the device is connected to a Zigbee network.
.. code-block:: arduino
bool connected();
This function will return ``true`` if connected to network, ``false`` otherwise.
getRole
^^^^^^^
Gets the current Zigbee device role.
.. code-block:: arduino
zigbee_role_t getRole();
This function will return current device role (``ZIGBEE_COORDINATOR``, ``ZIGBEE_ROUTER``, ``ZIGBEE_END_DEVICE``).
Endpoint Management
*******************
addEndpoint
^^^^^^^^^^^
Adds an endpoint to the Zigbee network.
.. code-block:: arduino
bool addEndpoint(ZigbeeEP *ep);
* ``ep`` - Pointer to the endpoint object to add
This function will return ``true`` if endpoint added successfully, ``false`` otherwise.
Network Configuration
*********************
setPrimaryChannelMask
^^^^^^^^^^^^^^^^^^^^^
Sets the primary channel mask for network scanning and joining.
.. code-block:: arduino
void setPrimaryChannelMask(uint32_t mask);
* ``mask`` - Channel mask (default: all channels 11-26, mask 0x07FFF800)
setScanDuration
^^^^^^^^^^^^^^^
Sets the scan duration for network discovery.
.. code-block:: arduino
void setScanDuration(uint8_t duration);
* ``duration`` - Scan duration (1-4, where 1 is fastest, 4 is slowest)
getScanDuration
^^^^^^^^^^^^^^^
Gets the current scan duration setting.
.. code-block:: arduino
uint8_t getScanDuration();
This function will return current scan duration (1-4).
Power Management
****************
setRxOnWhenIdle
^^^^^^^^^^^^^^^
Sets whether the device keeps its receiver on when idle.
.. code-block:: arduino
void setRxOnWhenIdle(bool rx_on_when_idle);
* ``rx_on_when_idle`` - ``true`` to keep receiver on, ``false`` to allow sleep
getRxOnWhenIdle
^^^^^^^^^^^^^^^
Gets the current receiver idle setting.
.. code-block:: arduino
bool getRxOnWhenIdle();
This function will return current receiver idle setting.
setTimeout
^^^^^^^^^^
Sets the timeout for network operations.
.. code-block:: arduino
void setTimeout(uint32_t timeout);
* ``timeout`` - Timeout in milliseconds (default: 30000 ms)
Network Discovery
*****************
scanNetworks
^^^^^^^^^^^^
Scans for available Zigbee networks.
.. code-block:: arduino
void scanNetworks(uint32_t channel_mask = ESP_ZB_TRANSCEIVER_ALL_CHANNELS_MASK, uint8_t scan_duration = 5);
* ``channel_mask`` - Channels to scan (default: all channels)
* ``scan_duration`` - Scan duration (default: 5)
scanComplete
^^^^^^^^^^^^
Checks if network scanning is complete.
.. code-block:: arduino
int16_t scanComplete();
This function will return:
* ``-2``: Scan failed or not started
* ``-1``: Scan running
* ``0``: No networks found
* ``>0``: Number of networks found
getScanResult
^^^^^^^^^^^^^
Gets the scan results.
.. code-block:: arduino
zigbee_scan_result_t *getScanResult();
This function will return pointer to scan results, or ``NULL`` if no results.
scanDelete
^^^^^^^^^^
Deletes the scan results from memory.
.. code-block:: arduino
void scanDelete();
Network Management (Coordinator only)
*************************************
setRebootOpenNetwork
^^^^^^^^^^^^^^^^^^^^
Opens the network for joining after reboot for a specified time.
.. code-block:: arduino
void setRebootOpenNetwork(uint8_t time);
* ``time`` - Time in seconds to keep network open after reboot
openNetwork
^^^^^^^^^^^
Opens the network for device joining for a specified time.
.. code-block:: arduino
void openNetwork(uint8_t time);
* ``time`` - Time in seconds to keep network open for device joining
closeNetwork
^^^^^^^^^^^^
Closes the network to prevent new devices from joining.
.. code-block:: arduino
void closeNetwork();
Radio Configuration
*******************
setRadioConfig
^^^^^^^^^^^^^^
Sets the radio configuration.
.. code-block:: arduino
void setRadioConfig(esp_zb_radio_config_t config);
* ``config`` - Radio configuration structure
getRadioConfig
^^^^^^^^^^^^^^
Gets the current radio configuration.
.. code-block:: arduino
esp_zb_radio_config_t getRadioConfig();
This function will return current radio configuration.
Host Configuration
******************
setHostConfig
^^^^^^^^^^^^^
Sets the host configuration.
.. code-block:: arduino
void setHostConfig(esp_zb_host_config_t config);
* ``config`` - Host configuration structure
getHostConfig
^^^^^^^^^^^^^
Gets the current host configuration.
.. code-block:: arduino
esp_zb_host_config_t getHostConfig();
This function will return current host configuration.
Debug and Utilities
*******************
setDebugMode
^^^^^^^^^^^^
Enables or disables debug mode.
.. code-block:: arduino
void setDebugMode(bool debug);
* ``debug`` - ``true`` to enable debug output, ``false`` to disable
getDebugMode
^^^^^^^^^^^^
Gets the current debug mode setting.
.. code-block:: arduino
bool getDebugMode();
This function will return current debug mode setting.
factoryReset
^^^^^^^^^^^^
Performs a factory reset, clearing all network settings.
.. code-block:: arduino
void factoryReset(bool restart = true);
* ``restart`` - ``true`` to restart after reset (default: ``true``)
Utility Functions
*****************
formatIEEEAddress
^^^^^^^^^^^^^^^^^
Formats an IEEE address for display.
.. code-block:: arduino
static const char *formatIEEEAddress(const esp_zb_ieee_addr_t addr);
* ``addr`` - IEEE address to format
This function will return formatted address string.
formatShortAddress
^^^^^^^^^^^^^^^^^^
Formats a short address for display.
.. code-block:: arduino
static const char *formatShortAddress(uint16_t addr);
* ``addr`` - Short address to format
This function will return formatted address string.

View file

@ -0,0 +1,357 @@
########
ZigbeeEP
########
About
-----
The ``ZigbeeEP`` class is the base class for all Zigbee endpoints. It provides common functionality for all endpoint types.
* **Device Information**: Every endpoint can be configured with manufacturer and model information that helps identify the device on the network
* **Binding Management**: Binding allows endpoints to establish direct communication links with other devices. This enables automatic command transmission without requiring manual addressing
* **Power Management**: Endpoints can report their power source type and battery status, which helps the network optimize communication patterns
* **Time Synchronization**: Endpoints can synchronize with network time, enabling time-based operations and scheduling
* **OTA Support**: Endpoints can receive over-the-air firmware updates to add new features or fix bugs
* **Device Discovery**: Endpoints can read manufacturer and model information from other devices on the network
ZigbeeEP APIs
-------------
Device Information
******************
setManufacturerAndModel
^^^^^^^^^^^^^^^^^^^^^^^
Sets the manufacturer name and model identifier for the device.
.. code-block:: arduino
bool setManufacturerAndModel(const char *name, const char *model);
* ``name`` - Manufacturer name (max 32 characters)
* ``model`` - Model identifier (max 32 characters)
This function will return ``true`` if set successfully, ``false`` otherwise.
getEndpoint
^^^^^^^^^^^
Gets the endpoint number assigned to this device.
.. code-block:: arduino
uint8_t getEndpoint();
This function will return the endpoint number (1-254).
Binding Management
******************
bound
^^^^^
Checks if the endpoint has any bound devices.
.. code-block:: arduino
bool bound();
This function will return ``true`` if the endpoint has bound devices, ``false`` otherwise.
getBoundDevices
^^^^^^^^^^^^^^^
Gets the list of devices bound to this endpoint.
.. code-block:: arduino
std::vector<esp_zb_binding_info_t> getBoundDevices();
This function will return list of bound device parameters.
printBoundDevices
^^^^^^^^^^^^^^^^^
Prints information about bound devices to Serial or a custom Print object.
.. code-block:: arduino
void printBoundDevices(Print &print = Serial);
* ``print`` - Custom Print object (optional, defaults to Serial)
allowMultipleBinding
^^^^^^^^^^^^^^^^^^^^
Enables or disables multiple device binding for this endpoint.
.. code-block:: arduino
void allowMultipleBinding(bool bind);
* ``bind`` - ``true`` to allow multiple bindings, ``false`` for single binding only
setManualBinding
^^^^^^^^^^^^^^^^
Enables or disables manual binding mode. Manual binding mode is supposed to be used when using ZHA or Z2M where you bind devices manually.
.. code-block:: arduino
void setManualBinding(bool bind);
* ``bind`` - ``true`` for manual binding, ``false`` for automatic binding (default)
clearBoundDevices
^^^^^^^^^^^^^^^^^
Removes all bound devices from this endpoint.
.. code-block:: arduino
void clearBoundDevices();
Binding Status
**************
epAllowMultipleBinding
^^^^^^^^^^^^^^^^^^^^^^
Gets whether multiple device binding is allowed for this endpoint.
.. code-block:: arduino
bool epAllowMultipleBinding();
This function will return ``true`` if multiple bindings are allowed, ``false`` otherwise.
epUseManualBinding
^^^^^^^^^^^^^^^^^^
Gets whether manual binding mode is enabled for this endpoint.
.. code-block:: arduino
bool epUseManualBinding();
This function will return ``true`` if manual binding is enabled, ``false`` otherwise.
Power Management
****************
setPowerSource
^^^^^^^^^^^^^^
Sets the power source type for the endpoint.
.. code-block:: arduino
bool setPowerSource(uint8_t source, uint8_t percentage = 0xff, uint8_t voltage = 0xff);
* ``source`` - Power source type (``ZB_POWER_SOURCE_MAINS``, ``ZB_POWER_SOURCE_BATTERY``, etc.)
* ``percentage`` - Battery percentage (0-100, default: 0xff)
* ``voltage`` - Battery voltage in 100 mV units (default: 0xff)
This function will return ``true`` if set successfully, ``false`` otherwise.
setBatteryPercentage
^^^^^^^^^^^^^^^^^^^^
Sets the current battery percentage.
.. code-block:: arduino
bool setBatteryPercentage(uint8_t percentage);
* ``percentage`` - Battery percentage (0-100)
This function will return ``true`` if set successfully, ``false`` otherwise.
setBatteryVoltage
^^^^^^^^^^^^^^^^^
Sets the battery voltage.
.. code-block:: arduino
bool setBatteryVoltage(uint8_t voltage);
* ``voltage`` - Battery voltage in 100 mV units (e.g., 35 for 3.5 V)
This function will return ``true`` if set successfully, ``false`` otherwise.
reportBatteryPercentage
^^^^^^^^^^^^^^^^^^^^^^^
Reports the current battery percentage to the network.
.. code-block:: arduino
bool reportBatteryPercentage();
This function will return ``true`` if reported successfully, ``false`` otherwise.
Time Synchronization
********************
addTimeCluster
^^^^^^^^^^^^^^
Adds time synchronization cluster to the endpoint. When you want to add a server cluster (have the time and GMT offset) fill the time structure with the current time and GMT offset.
For client cluster (get the time and GMT offset) keep the default parameters.
.. code-block:: arduino
bool addTimeCluster(tm time = {}, int32_t gmt_offset = 0);
* ``time`` - Current time structure (default: empty)
* ``gmt_offset`` - GMT offset in seconds (default: 0)
This function will return ``true`` if added successfully, ``false`` otherwise.
setTime
^^^^^^^
Sets the current time for the endpoint.
.. code-block:: arduino
bool setTime(tm time);
* ``time`` - Time structure to set
This function will return ``true`` if set successfully, ``false`` otherwise.
setTimezone
^^^^^^^^^^^
Sets the timezone offset for the endpoint.
.. code-block:: arduino
bool setTimezone(int32_t gmt_offset);
* ``gmt_offset`` - GMT offset in seconds
This function will return ``true`` if set successfully, ``false`` otherwise.
getTime
^^^^^^^
Gets the current network time.
.. code-block:: arduino
struct tm getTime(uint8_t endpoint = 1, int32_t short_addr = 0x0000, esp_zb_ieee_addr_t ieee_addr = {});
* ``endpoint`` - Target endpoint (default: 1)
* ``short_addr`` - Target device short address (default: 0x0000)
* ``ieee_addr`` - Target device IEEE address (default: empty)
This function will return network time structure.
getTimezone
^^^^^^^^^^^
Gets the timezone offset.
.. code-block:: arduino
int32_t getTimezone(uint8_t endpoint = 1, int32_t short_addr = 0x0000, esp_zb_ieee_addr_t ieee_addr = {});
* ``endpoint`` - Target endpoint (default: 1)
* ``short_addr`` - Target device short address (default: 0x0000)
* ``ieee_addr`` - Target device IEEE address (default: empty)
This function will return GMT offset in seconds.
OTA Support
***********
addOTAClient
^^^^^^^^^^^^
Adds OTA client to the endpoint for firmware updates.
.. code-block:: arduino
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);
* ``file_version`` - Current firmware version
* ``downloaded_file_ver`` - Downloaded file version
* ``hw_version`` - Hardware version
* ``manufacturer`` - Manufacturer code (default: 0x1001)
* ``image_type`` - Image type code (default: 0x1011)
* ``max_data_size`` - Maximum data size for OTA transfer (default: 223)
This function will return ``true`` if added successfully, ``false`` otherwise.
requestOTAUpdate
^^^^^^^^^^^^^^^^
Requests OTA update from the server.
.. code-block:: arduino
void requestOTAUpdate();
Device Discovery
****************
readManufacturer
^^^^^^^^^^^^^^^^
Reads the manufacturer name from a remote device.
.. code-block:: arduino
char *readManufacturer(uint8_t endpoint, uint16_t short_addr, esp_zb_ieee_addr_t ieee_addr);
* ``endpoint`` - Target endpoint number
* ``short_addr`` - Target device short address
* ``ieee_addr`` - Target device IEEE address
This function will return pointer to manufacturer string, or ``NULL`` if read failed.
readModel
^^^^^^^^^
Reads the model identifier from a remote device.
.. code-block:: arduino
char *readModel(uint8_t endpoint, uint16_t short_addr, esp_zb_ieee_addr_t ieee_addr);
* ``endpoint`` - Target endpoint number
* ``short_addr`` - Target device short address
* ``ieee_addr`` - Target device IEEE address
This function will return pointer to model string, or ``NULL`` if read failed.
Event Handling
**************
onIdentify
^^^^^^^^^^
Sets a callback function for identify events.
.. code-block:: arduino
void onIdentify(void (*callback)(uint16_t));
* ``callback`` - Function to call when identify event occurs
* ``time`` - Identify time in seconds
Supported Endpoints
-------------------
The Zigbee library provides specialized endpoint classes for different device types. Each endpoint type includes specific clusters and functionality relevant to that device category.
.. toctree::
:maxdepth: 1
:glob:
ep_*

View file

@ -1,5 +1,7 @@
sphinx==4.5.0
esp-docs>=1.4.0
sphinx-copybutton==0.5.0
sphinx-tabs==3.2.0
numpydoc==1.5.0
standard-imghdr==3.13.0
Sphinx-Substitution-Extensions==2022.2.16

View file

@ -68,6 +68,8 @@ dependencies:
# RainMaker Start (Fixed versions, because Matter supports only Insights 1.0.1)
espressif/network_provisioning:
version: "1.0.2"
rules:
- if: "target != esp32c2"
espressif/esp_rainmaker:
version: "1.5.2"
rules:
@ -103,11 +105,11 @@ dependencies:
rules:
- if: "target in [esp32s3]"
espressif/esp_hosted:
version: "^0.0.25"
version: "^2.0.12"
rules:
- if: "target == esp32p4"
espressif/esp_wifi_remote:
version: "^0.4.1"
version: "^0.13.0"
rules:
- if: "target == esp32p4"
espressif/libsodium:

View file

@ -1,5 +1,5 @@
name=ArduinoOTA
version=3.2.0
version=3.2.1
author=Ivan Grokhotkov and Hristo Gochkov
maintainer=Hristo Gochkov <hristo@espressif.com>
sentence=Enables Over The Air upgrades, via wifi and espota.py UDP request/TCP download.

View file

@ -1,5 +1,5 @@
name=ESP32 Async UDP
version=3.2.0
version=3.2.1
author=Me-No-Dev
maintainer=Me-No-Dev
sentence=Async UDP Library for ESP32

View file

@ -582,8 +582,8 @@ bool AsyncUDP::listen(const ip_addr_t *addr, uint16_t port) {
}
close();
if (addr) {
IP_SET_TYPE_VAL(_pcb->local_ip, addr->type);
IP_SET_TYPE_VAL(_pcb->remote_ip, addr->type);
IP_SET_TYPE_VAL(_pcb->local_ip, IP_GET_TYPE(addr));
IP_SET_TYPE_VAL(_pcb->remote_ip, IP_GET_TYPE(addr));
}
if (_udp_bind(_pcb, addr, port) != ERR_OK) {
return false;
@ -682,6 +682,8 @@ igmp_fail:
}
bool AsyncUDP::listenMulticast(const ip_addr_t *addr, uint16_t port, uint8_t ttl, tcpip_adapter_if_t tcpip_if) {
ip_addr_t bind_addr;
if (!ip_addr_ismulticast(addr)) {
return false;
}
@ -690,7 +692,9 @@ bool AsyncUDP::listenMulticast(const ip_addr_t *addr, uint16_t port, uint8_t ttl
return false;
}
if (!listen(NULL, port)) {
IP_SET_TYPE(&bind_addr, IP_GET_TYPE(addr));
ip_addr_set_any(IP_IS_V6(addr), &bind_addr);
if (!listen(&bind_addr, port)) {
return false;
}

View file

@ -1,5 +1,5 @@
name=BLE
version=3.2.0
version=3.2.1
author=Neil Kolban <kolban1@kolban.com>
maintainer=Dariusz Krempa <esp32@esp32.eu.org>
sentence=BLE functions for ESP32

View file

@ -1,5 +1,5 @@
name=BluetoothSerial
version=3.2.0
version=3.2.1
author=Evandro Copercini
maintainer=Evandro Copercini
sentence=Simple UART to Classical Bluetooth bridge for ESP32

View file

@ -34,8 +34,9 @@ void handleNotFound() {
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_AP);
WiFi.softAP("ESP32-DNSServer");
WiFi.AP.begin();
WiFi.AP.create("ESP32-DNSServer");
WiFi.AP.enableDhcpCaptivePortal();
// by default DNSServer is started serving any "*" domain name. It will reply
// AccessPoint's IP to all DNS request (this is required for Captive Portal detection)

View file

@ -1,5 +1,5 @@
name=DNSServer
version=3.2.0
version=3.2.1
author=Kristijan Novoselić
maintainer=Kristijan Novoselić, <kristijan.novoselic@gmail.com>
sentence=A simple DNS server for ESP32.

View file

@ -111,16 +111,22 @@ void DNSServer::_handleUDP(AsyncUDPPacket &pkt) {
// will reply with IP only to "*" or if domain matches without www. subdomain
if (dnsHeader.OPCode == DNS_OPCODE_QUERY && requestIncludesOnlyOneQuestion(dnsHeader)
&& (_domainName.isEmpty() || getDomainNameWithoutWwwPrefix(static_cast<const unsigned char *>(dnsQuestion.QName), dnsQuestion.QNameLength) == _domainName)) {
// Qtype = A (1) or ANY (255): send an A record otherwise an empty response
if (ntohs(dnsQuestion.QType) == 1 || ntohs(dnsQuestion.QType) == 255) {
replyWithIP(pkt, dnsHeader, dnsQuestion);
} else {
replyWithNoAnsw(pkt, dnsHeader, dnsQuestion);
}
return;
}
// otherwise reply with custom code
replyWithCustomCode(pkt, dnsHeader);
}
bool DNSServer::requestIncludesOnlyOneQuestion(DNSHeader &dnsHeader) {
return ntohs(dnsHeader.QDCount) == 1 && dnsHeader.ANCount == 0 && dnsHeader.NSCount == 0 && dnsHeader.ARCount == 0;
dnsHeader.ARCount = 0; // We assume that if ARCount !=0 there is a EDNS OPT packet, just ignore
return ntohs(dnsHeader.QDCount) == 1 && dnsHeader.ANCount == 0 && dnsHeader.NSCount == 0;
}
String DNSServer::getDomainNameWithoutWwwPrefix(const unsigned char *start, size_t len) {
@ -139,7 +145,6 @@ String DNSServer::getDomainNameWithoutWwwPrefix(const unsigned char *start, size
void DNSServer::replyWithIP(AsyncUDPPacket &req, DNSHeader &dnsHeader, DNSQuestion &dnsQuestion) {
AsyncUDPMessage rpl;
// Change the type of message to a response and set the number of answers equal to
// the number of questions in the header
dnsHeader.QR = DNS_QR_RESPONSE;
@ -187,3 +192,76 @@ void DNSServer::replyWithCustomCode(AsyncUDPPacket &req, DNSHeader &dnsHeader) {
rpl.write(reinterpret_cast<const uint8_t *>(&dnsHeader), sizeof(DNSHeader));
_udp.sendTo(rpl, req.remoteIP(), req.remotePort());
}
void DNSServer::replyWithNoAnsw(AsyncUDPPacket &req, DNSHeader &dnsHeader, DNSQuestion &dnsQuestion) {
dnsHeader.QR = DNS_QR_RESPONSE;
dnsHeader.ANCount = 0;
dnsHeader.NSCount = htons(1);
AsyncUDPMessage rpl;
rpl.write(reinterpret_cast<const uint8_t *>(&dnsHeader), sizeof(DNSHeader));
// Write the question
rpl.write(dnsQuestion.QName, dnsQuestion.QNameLength);
rpl.write((uint8_t *)&dnsQuestion.QType, 2);
rpl.write((uint8_t *)&dnsQuestion.QClass, 2);
// An empty answer contains an authority section with a SOA,
// We take the name of the query as the root of the zone for which the SOA is generated
// and use a value of DNS_MINIMAL_TTL seconds in order to minimize negative caching
// Write the authority section:
// The SOA RR's ownername is set equal to the query name, and we use made up names for
// the MNAME and RNAME - it doesn't really matter from a protocol perspective - as for
// a no such QTYPE answer only the timing fields are used.
// a protocol perspective - it
// Use DNS name compression : instead of repeating the name in this RNAME occurrence,
// set the two MSB of the byte corresponding normally to the length to 1. The following
// 14 bits must be used to specify the offset of the domain name in the message
// (<255 here so the first byte has the 6 LSB at 0)
rpl.write((uint8_t)0xC0);
rpl.write((uint8_t)DNS_OFFSET_DOMAIN_NAME);
// DNS type A : host address, DNS class IN for INternet, returning an IPv4 address
uint16_t answerType = htons(DNS_TYPE_SOA), answerClass = htons(DNS_CLASS_IN);
uint32_t Serial = htonl(DNS_SOA_SERIAL); // Date type serial based on the date this piece of code was written
uint32_t Refresh = htonl(DNS_SOA_REFRESH); // These timers don't matter, we don't serve zone transfers
uint32_t Retry = htonl(DNS_SOA_RETRY);
uint32_t Expire = htonl(DNS_SOA_EXPIRE);
uint32_t MinTTL = htonl(DNS_MINIMAL_TTL); // See RFC2308 section 5
char MLabel[] = DNS_SOA_MNAME_LABEL;
char RLabel[] = DNS_SOA_RNAME_LABEL;
char PostFixLabel[] = DNS_SOA_POSTFIX_LABEL;
// 4 accounts for len fields and for both rname
// and lname and their postfix labels and there are 5 32 bit fields
uint16_t RdataLength = htons((uint16_t)(strlen(MLabel) + strlen(RLabel) + 2 * strlen(PostFixLabel) + 4 + 5 * sizeof(Serial)));
rpl.write((unsigned char *)&answerType, 2);
rpl.write((unsigned char *)&answerClass, 2);
rpl.write((unsigned char *)&MinTTL, 4); // DNS Time To Live
rpl.write((unsigned char *)&RdataLength, 2);
rpl.write((uint8_t)strlen(MLabel));
rpl.write((unsigned char *)&MLabel, strlen(MLabel));
rpl.write((unsigned char *)&PostFixLabel, strlen(PostFixLabel));
rpl.write((uint8_t)0);
// rpl.write((uint8_t)0xC0);
// rpl.write((uint8_t)DNS_OFFSET_DOMAIN_NAME);
rpl.write((uint8_t)strlen(RLabel));
rpl.write((unsigned char *)&RLabel, strlen(RLabel));
rpl.write((unsigned char *)&PostFixLabel, strlen(PostFixLabel));
rpl.write((uint8_t)0);
rpl.write((unsigned char *)&Serial, 4);
rpl.write((unsigned char *)&Refresh, 4);
rpl.write((unsigned char *)&Retry, 4);
rpl.write((unsigned char *)&Expire, 4);
rpl.write((unsigned char *)&MinTTL, 4);
_udp.sendTo(rpl, req.remoteIP(), req.remotePort());
}

View file

@ -9,6 +9,26 @@
#define DNS_OFFSET_DOMAIN_NAME DNS_HEADER_SIZE // Offset in bytes to reach the domain name labels in the DNS message
#define DNS_DEFAULT_PORT 53
#define DNS_SOA_MNAME_LABEL "ns"
#define DNS_SOA_RNAME_LABEL "esp32"
// The POSTFIX_LABEL will be concatenated to the RName and MName Label label
// do not use a multilabel name here. "local" is a good choice as it is reserved for
// local use by IANA
// The postfix label is defined as an array of characters that follows the
// definition of RFC1035 3.1
// for instance, a postfix of example.com would be defined as:
// #define DNS_SOA_POSTFIX_LABEL {'\7', 'e', 'x', 'a', 'm', 'p', 'l', 'e', '\3', 'c', 'o', 'm', '\0'}
#define DNS_SOA_POSTFIX_LABEL \
{ '\5', 'l', 'o', 'c', 'a', 'l', '\0' }
// From the following values only the MINIMAL_TTL has relevance
// in the context of client-server protocol interactions.
// The other values are arbitrary chosen as they are only relevant for
// in a zone-transfer scenario.
#define DNS_SOA_SERIAL 2025052900 // Arbitrary serial (format: YYYYMMDDnn)
#define DNS_SOA_REFRESH 100000 // Arbitrary (seconds)
#define DNS_SOA_RETRY 10000 // Arbitrary (seconds)
#define DNS_SOA_EXPIRE 1000000 // Arbitrary (seconds)
#define DNS_MINIMAL_TTL 5 // Time to live for negative answers RFC2308
enum class DNSReplyCode : uint16_t {
NoError = 0,
FormError = 1,
@ -179,5 +199,7 @@ private:
inline bool requestIncludesOnlyOneQuestion(DNSHeader &dnsHeader);
void replyWithIP(AsyncUDPPacket &req, DNSHeader &dnsHeader, DNSQuestion &dnsQuestion);
inline void replyWithCustomCode(AsyncUDPPacket &req, DNSHeader &dnsHeader);
inline void replyWithNoAnsw(AsyncUDPPacket &req, DNSHeader &dnsHeader, DNSQuestion &dnsQuestion);
void _handleUDP(AsyncUDPPacket &pkt);
};

View file

@ -1,5 +1,5 @@
name=EEPROM
version=3.2.0
version=3.2.1
author=Ivan Grokhotkov
maintainer=Paolo Becchi <pbecchi@aerobusiness.it>
sentence=Enables reading and writing data a sequential, addressable FLASH storage

View file

@ -0,0 +1,111 @@
/* LEDC Gamma Curve Fade Arduino Example
This example demonstrates gamma curve fading on ESP32 variants that support it.
Gamma correction makes LED brightness changes appear more gradual and natural
to human eyes compared to linear fading.
Two methods are supported:
1. Using a pre-computed Gamma Look-Up Table (LUT) for better performance
2. Using mathematical gamma correction with a gamma factor
Supported chips: ESP32-C6, ESP32-C5, ESP32-H2, ESP32-P4 and future chips with Gamma Fade support
Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/)
*/
// use 12 bit precision for LEDC timer
#define LEDC_TIMER_12_BIT 12
// use 5000 Hz as a LEDC base frequency
#define LEDC_BASE_FREQ 5000
// define starting duty, target duty and maximum fade time
#define LEDC_START_DUTY (0)
#define LEDC_TARGET_DUTY (4095)
#define LEDC_FADE_TIME (2000)
// gamma factor for mathematical calculation
#define LEDC_GAMMA_FACTOR (2.6)
// use gamma LUT for better performance instead of mathematical calculation (gamma factor)
#define USE_GAMMA_LUT 1
// fade LED pins
const uint8_t ledPinR = 4;
const uint8_t ledPinG = 5;
const uint8_t ledPinB = 6;
uint8_t fade_ended = 0; // status of LED gamma fade
bool fade_in = true;
#ifdef USE_GAMMA_LUT
// Custom Gamma LUT demonstration with 101 steps (Brightness 0 - 100% gamma correction look up table (gamma = 2.6))
// Y = B ^ 2.6 - Pre-computed LUT to save runtime computation
static const float ledcGammaLUT[101] = {
0.000000, 0.000006, 0.000038, 0.000110, 0.000232, 0.000414, 0.000666, 0.000994, 0.001406, 0.001910, 0.002512, 0.003218, 0.004035, 0.004969, 0.006025,
0.007208, 0.008525, 0.009981, 0.011580, 0.013328, 0.015229, 0.017289, 0.019512, 0.021902, 0.024465, 0.027205, 0.030125, 0.033231, 0.036527, 0.040016,
0.043703, 0.047593, 0.051688, 0.055993, 0.060513, 0.065249, 0.070208, 0.075392, 0.080805, 0.086451, 0.092333, 0.098455, 0.104821, 0.111434, 0.118298,
0.125416, 0.132792, 0.140428, 0.148329, 0.156498, 0.164938, 0.173653, 0.182645, 0.191919, 0.201476, 0.211321, 0.221457, 0.231886, 0.242612, 0.253639,
0.264968, 0.276603, 0.288548, 0.300805, 0.313378, 0.326268, 0.339480, 0.353016, 0.366879, 0.381073, 0.395599, 0.410461, 0.425662, 0.441204, 0.457091,
0.473325, 0.489909, 0.506846, 0.524138, 0.541789, 0.559801, 0.578177, 0.596920, 0.616032, 0.635515, 0.655374, 0.675610, 0.696226, 0.717224, 0.738608,
0.760380, 0.782542, 0.805097, 0.828048, 0.851398, 0.875148, 0.899301, 0.923861, 0.948829, 0.974208, 1.000000,
};
#endif
void ARDUINO_ISR_ATTR LED_FADE_ISR() {
fade_ended += 1;
}
void setup() {
// Initialize serial communication at 115200 bits per second:
Serial.begin(115200);
// Setup timer with given frequency, resolution and attach it to a led pin with auto-selected channel
ledcAttach(ledPinR, LEDC_BASE_FREQ, LEDC_TIMER_12_BIT);
ledcAttach(ledPinG, LEDC_BASE_FREQ, LEDC_TIMER_12_BIT);
ledcAttach(ledPinB, LEDC_BASE_FREQ, LEDC_TIMER_12_BIT);
#if USE_GAMMA_LUT // Use default gamma LUT for better performance
ledcSetGammaTable(ledcGammaLUT, 101);
#else // Use mathematical gamma correction (default, more flexible)
ledcSetGammaFactor(LEDC_GAMMA_FACTOR); // This is optional to set custom gamma factor (default is 2.8)
#endif
// Setup and start gamma curve fade on led (duty from 0 to 4095)
ledcFadeGamma(ledPinR, LEDC_START_DUTY, LEDC_TARGET_DUTY, LEDC_FADE_TIME);
ledcFadeGamma(ledPinG, LEDC_START_DUTY, LEDC_TARGET_DUTY, LEDC_FADE_TIME);
ledcFadeGamma(ledPinB, LEDC_START_DUTY, LEDC_TARGET_DUTY, LEDC_FADE_TIME);
Serial.println("LED Gamma Fade on started.");
// Wait for fade to end
delay(LEDC_FADE_TIME);
// Setup and start gamma curve fade off led and use ISR (duty from 4095 to 0)
ledcFadeGammaWithInterrupt(ledPinR, LEDC_TARGET_DUTY, LEDC_START_DUTY, LEDC_FADE_TIME, LED_FADE_ISR);
ledcFadeGammaWithInterrupt(ledPinG, LEDC_TARGET_DUTY, LEDC_START_DUTY, LEDC_FADE_TIME, LED_FADE_ISR);
ledcFadeGammaWithInterrupt(ledPinB, LEDC_TARGET_DUTY, LEDC_START_DUTY, LEDC_FADE_TIME, LED_FADE_ISR);
Serial.println("LED Gamma Fade off started.");
}
void loop() {
// Check if fade_ended flag was set to true in ISR
if (fade_ended == 3) {
Serial.println("LED gamma fade ended");
fade_ended = 0;
// Check what gamma fade should be started next
if (fade_in) {
ledcFadeGammaWithInterrupt(ledPinR, LEDC_START_DUTY, LEDC_TARGET_DUTY, LEDC_FADE_TIME, LED_FADE_ISR);
ledcFadeGammaWithInterrupt(ledPinG, LEDC_START_DUTY, LEDC_TARGET_DUTY, LEDC_FADE_TIME, LED_FADE_ISR);
ledcFadeGammaWithInterrupt(ledPinB, LEDC_START_DUTY, LEDC_TARGET_DUTY, LEDC_FADE_TIME, LED_FADE_ISR);
Serial.println("LED Gamma Fade in started.");
fade_in = false;
} else {
ledcFadeGammaWithInterrupt(ledPinR, LEDC_TARGET_DUTY, LEDC_START_DUTY, LEDC_FADE_TIME, LED_FADE_ISR);
ledcFadeGammaWithInterrupt(ledPinG, LEDC_TARGET_DUTY, LEDC_START_DUTY, LEDC_FADE_TIME, LED_FADE_ISR);
ledcFadeGammaWithInterrupt(ledPinB, LEDC_TARGET_DUTY, LEDC_START_DUTY, LEDC_FADE_TIME, LED_FADE_ISR);
Serial.println("LED Gamma Fade out started.");
fade_in = true;
}
}
}

View file

@ -0,0 +1,5 @@
{
"requires": [
"CONFIG_SOC_LEDC_GAMMA_CURVE_FADE_SUPPORTED=y"
]
}

View file

@ -1,37 +1,10 @@
#include "esp_camera.h"
#include <WiFi.h>
//
// WARNING!!! PSRAM IC required for UXGA resolution and high JPEG quality
// Ensure ESP32 Wrover Module or other board with PSRAM is selected
// Partial images will be transmitted if image exceeds buffer size
//
// You must select partition scheme from the board menu that has at least 3MB APP space.
// Face Recognition is DISABLED for ESP32 and ESP32-S2, because it takes up from 15
// seconds to process single frame. Face Detection is ENABLED if PSRAM is enabled as well
// ===================
// Select camera model
// ===================
//#define CAMERA_MODEL_WROVER_KIT // Has PSRAM
#define CAMERA_MODEL_ESP_EYE // Has PSRAM
//#define CAMERA_MODEL_ESP32S3_EYE // Has PSRAM
//#define CAMERA_MODEL_M5STACK_PSRAM // Has PSRAM
//#define CAMERA_MODEL_M5STACK_V2_PSRAM // M5Camera version B Has PSRAM
//#define CAMERA_MODEL_M5STACK_WIDE // Has PSRAM
//#define CAMERA_MODEL_M5STACK_ESP32CAM // No PSRAM
//#define CAMERA_MODEL_M5STACK_UNITCAM // No PSRAM
//#define CAMERA_MODEL_M5STACK_CAMS3_UNIT // Has PSRAM
//#define CAMERA_MODEL_AI_THINKER // Has PSRAM
//#define CAMERA_MODEL_TTGO_T_JOURNAL // No PSRAM
//#define CAMERA_MODEL_XIAO_ESP32S3 // Has PSRAM
// ** Espressif Internal Boards **
//#define CAMERA_MODEL_ESP32_CAM_BOARD
//#define CAMERA_MODEL_ESP32S2_CAM_BOARD
//#define CAMERA_MODEL_ESP32S3_CAM_LCD
//#define CAMERA_MODEL_DFRobot_FireBeetle2_ESP32S3 // Has PSRAM
//#define CAMERA_MODEL_DFRobot_Romeo_ESP32S3 // Has PSRAM
#include "camera_pins.h"
// ===========================
// Select camera model in board_config.h
// ===========================
#include "board_config.h"
// ===========================
// Enter your WiFi credentials
@ -40,7 +13,7 @@ const char *ssid = "**********";
const char *password = "**********";
void startCameraServer();
void setupLedFlash(int pin);
void setupLedFlash();
void setup() {
Serial.begin(115200);
@ -130,7 +103,7 @@ void setup() {
// Setup LED FLash if LED pin is defined in camera_pins.h
#if defined(LED_GPIO_NUM)
setupLedFlash(LED_GPIO_NUM);
setupLedFlash();
#endif
WiFi.begin(ssid, password);

View file

@ -19,18 +19,14 @@
#include "esp32-hal-ledc.h"
#include "sdkconfig.h"
#include "camera_index.h"
#include "board_config.h"
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
#include "esp32-hal-log.h"
#endif
// Enable LED FLASH setting
#define CONFIG_LED_ILLUMINATOR_ENABLED 1
// LED FLASH setup
#if CONFIG_LED_ILLUMINATOR_ENABLED
#define LED_LEDC_GPIO 22 //configure LED pin
#if defined(LED_GPIO_NUM)
#define CONFIG_LED_MAX_INTENSITY 255
int led_duty = 0;
@ -91,13 +87,13 @@ static int ra_filter_run(ra_filter_t *filter, int value) {
}
#endif
#if CONFIG_LED_ILLUMINATOR_ENABLED
#if defined(LED_GPIO_NUM)
void enable_led(bool en) { // Turn LED On or Off
int duty = en ? led_duty : 0;
if (en && isStreaming && (led_duty > CONFIG_LED_MAX_INTENSITY)) {
duty = CONFIG_LED_MAX_INTENSITY;
}
ledcWrite(LED_LEDC_GPIO, duty);
ledcWrite(LED_GPIO_NUM, duty);
//ledc_set_duty(CONFIG_LED_LEDC_SPEED_MODE, CONFIG_LED_LEDC_CHANNEL, duty);
//ledc_update_duty(CONFIG_LED_LEDC_SPEED_MODE, CONFIG_LED_LEDC_CHANNEL);
log_i("Set LED intensity to %d", duty);
@ -162,7 +158,7 @@ static esp_err_t capture_handler(httpd_req_t *req) {
int64_t fr_start = esp_timer_get_time();
#endif
#if CONFIG_LED_ILLUMINATOR_ENABLED
#if defined(LED_GPIO_NUM)
enable_led(true);
vTaskDelay(150 / portTICK_PERIOD_MS); // The LED needs to be turned on ~150ms before the call to esp_camera_fb_get()
fb = esp_camera_fb_get(); // or it won't be visible in the frame. A better way to do this is needed.
@ -230,7 +226,7 @@ static esp_err_t stream_handler(httpd_req_t *req) {
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
httpd_resp_set_hdr(req, "X-Framerate", "60");
#if CONFIG_LED_ILLUMINATOR_ENABLED
#if defined(LED_GPIO_NUM)
isStreaming = true;
enable_led(true);
#endif
@ -293,7 +289,7 @@ static esp_err_t stream_handler(httpd_req_t *req) {
);
}
#if CONFIG_LED_ILLUMINATOR_ENABLED
#if defined(LED_GPIO_NUM)
isStreaming = false;
enable_led(false);
#endif
@ -393,7 +389,7 @@ static esp_err_t cmd_handler(httpd_req_t *req) {
} else if (!strcmp(variable, "ae_level")) {
res = s->set_ae_level(s, val);
}
#if CONFIG_LED_ILLUMINATOR_ENABLED
#if defined(LED_GPIO_NUM)
else if (!strcmp(variable, "led_intensity")) {
led_duty = val;
if (isStreaming) {
@ -481,7 +477,7 @@ static esp_err_t status_handler(httpd_req_t *req) {
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
#if defined(LED_GPIO_NUM)
p += sprintf(p, ",\"led_intensity\":%u", led_duty);
#else
p += sprintf(p, ",\"led_intensity\":%d", -1);
@ -843,10 +839,10 @@ void startCameraServer() {
}
}
void setupLedFlash(int pin) {
#if CONFIG_LED_ILLUMINATOR_ENABLED
ledcAttach(pin, 5000, 8);
void setupLedFlash() {
#if defined(LED_GPIO_NUM)
ledcAttach(LED_GPIO_NUM, 5000, 8);
#else
log_i("LED flash is disabled -> CONFIG_LED_ILLUMINATOR_ENABLED = 0");
log_i("LED flash is disabled -> LED_GPIO_NUM undefined");
#endif
}

View file

@ -0,0 +1,34 @@
#ifndef BOARD_CONFIG_H
#define BOARD_CONFIG_H
//
// WARNING!!! PSRAM IC required for UXGA resolution and high JPEG quality
// Ensure ESP32 Wrover Module or other board with PSRAM is selected
// Partial images will be transmitted if image exceeds buffer size
//
// You must select partition scheme from the board menu that has at least 3MB APP space.
// ===================
// Select camera model
// ===================
//#define CAMERA_MODEL_WROVER_KIT // Has PSRAM
#define CAMERA_MODEL_ESP_EYE // Has PSRAM
//#define CAMERA_MODEL_ESP32S3_EYE // Has PSRAM
//#define CAMERA_MODEL_M5STACK_PSRAM // Has PSRAM
//#define CAMERA_MODEL_M5STACK_V2_PSRAM // M5Camera version B Has PSRAM
//#define CAMERA_MODEL_M5STACK_WIDE // Has PSRAM
//#define CAMERA_MODEL_M5STACK_ESP32CAM // No PSRAM
//#define CAMERA_MODEL_M5STACK_UNITCAM // No PSRAM
//#define CAMERA_MODEL_M5STACK_CAMS3_UNIT // Has PSRAM
//#define CAMERA_MODEL_AI_THINKER // Has PSRAM
//#define CAMERA_MODEL_TTGO_T_JOURNAL // No PSRAM
//#define CAMERA_MODEL_XIAO_ESP32S3 // Has PSRAM
// ** Espressif Internal Boards **
//#define CAMERA_MODEL_ESP32_CAM_BOARD
//#define CAMERA_MODEL_ESP32S2_CAM_BOARD
//#define CAMERA_MODEL_ESP32S3_CAM_LCD
//#define CAMERA_MODEL_DFRobot_FireBeetle2_ESP32S3 // Has PSRAM
//#define CAMERA_MODEL_DFRobot_Romeo_ESP32S3 // Has PSRAM
#include "camera_pins.h"
#endif // BOARD_CONFIG_H

View file

@ -0,0 +1,157 @@
/*
SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
SPDX-License-Identifier: Apache-2.0
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.
ESP32 Lambda FunctionalInterrupt Example
========================================
This example demonstrates how to use lambda functions with FunctionalInterrupt
for GPIO pin interrupt callbacks on ESP32. It shows CHANGE mode detection
with LED toggle functionality and proper debouncing.
Hardware Setup:
- Use BOOT Button or connect a button between BUTTON_PIN and GND (with internal pullup)
- Use Builtin Board LED or connect an LED with resistor to GPIO 2 (LED_PIN)
Features Demonstrated:
1. CHANGE mode lambda to detect both RISING and FALLING edges
2. LED toggle on button press (FALLING edge)
3. Edge type detection using digitalRead() within ISR
4. Hardware debouncing with configurable timeout
IMPORTANT NOTE ABOUT ESP32 INTERRUPT BEHAVIOR:
- Only ONE interrupt handler can be attached per GPIO pin at a time
- Calling attachInterrupt() on a pin that already has an interrupt will override the previous one
- This applies regardless of edge type (RISING, FALLING, CHANGE)
- If you need both RISING and FALLING detection on the same pin, use CHANGE mode
and determine the edge type within your handler by reading the pin state
*/
#include <Arduino.h>
#include <FunctionalInterrupt.h>
// Pin definitions
#define BUTTON_PIN BOOT_PIN // BOOT BUTTON - change as needed
#ifdef LED_BUILTIN
#define LED_PIN LED_BUILTIN
#else
#warning Using LED_PIN = GPIO 2 as default - change as needed
#define LED_PIN 2 // change as needed
#endif
// Global variables for interrupt handling (volatile for ISR safety)
volatile uint32_t buttonPressCount = 0;
volatile uint32_t buttonReleaseCount = 0;
volatile bool buttonPressed = false;
volatile bool buttonReleased = false;
volatile bool ledState = false;
volatile bool ledStateChanged = false; // Flag to indicate LED needs updating
// Debouncing variables (volatile for ISR safety)
volatile unsigned long lastButtonInterruptTime = 0;
const unsigned long DEBOUNCE_DELAY_MS = 50; // 50ms debounce delay
// State-based debouncing to prevent hysteresis issues
volatile bool lastButtonState = HIGH; // Track last stable state (HIGH = released)
// Global lambda function (declared at file scope) - ISR in IRAM
IRAM_ATTR std::function<void()> changeModeLambda = []() {
// Simple debouncing: check if enough time has passed since last interrupt
unsigned long currentTime = millis();
if (currentTime - lastButtonInterruptTime < DEBOUNCE_DELAY_MS) {
return; // Ignore this interrupt due to bouncing
}
// Read current pin state to determine edge type
bool currentState = digitalRead(BUTTON_PIN);
// State-based debouncing: only process if state actually changed
if (currentState == lastButtonState) {
return; // No real state change, ignore (hysteresis/noise)
}
// Update timing and state
lastButtonInterruptTime = currentTime;
lastButtonState = currentState;
if (currentState == LOW) {
// FALLING edge detected (button pressed) - set flag for main loop
// volatile variables require use of temporary value transfer
uint32_t temp = buttonPressCount + 1;
buttonPressCount = temp;
buttonPressed = true;
ledStateChanged = true; // Signal main loop to toggle LED
} else {
// RISING edge detected (button released) - set flag for main loop
// volatile variables require use of temporary value transfer
uint32_t temp = buttonReleaseCount + 1;
buttonReleaseCount = temp;
buttonReleased = true;
}
};
void setup() {
Serial.begin(115200);
delay(1000); // Allow serial monitor to connect
Serial.println("ESP32 Lambda FunctionalInterrupt Example");
Serial.println("========================================");
// Configure pins
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
// CHANGE mode lambda to handle both RISING and FALLING edges
// This toggles the LED on button press (FALLING edge)
Serial.println("Setting up CHANGE mode lambda for LED toggle");
// Use the global lambda function
attachInterrupt(BUTTON_PIN, changeModeLambda, CHANGE);
Serial.println();
Serial.printf("Lambda interrupt configured on Pin %d (CHANGE mode)\r\n", BUTTON_PIN);
Serial.printf("Debounce delay: %lu ms\r\n", DEBOUNCE_DELAY_MS);
Serial.println();
Serial.println("Press the button to toggle the LED!");
Serial.println("Button press (FALLING edge) will toggle the LED.");
Serial.println("Button release (RISING edge) will be detected and reported.");
Serial.println("Button includes debouncing to prevent mechanical bounce issues.");
Serial.println();
}
void loop() {
// Handle LED state changes (ISR-safe approach)
if (ledStateChanged) {
ledStateChanged = false;
ledState = !ledState; // Toggle LED state in main loop
digitalWrite(LED_PIN, ledState);
}
// Check for button presses
if (buttonPressed) {
buttonPressed = false;
Serial.printf("==> Button PRESSED! Count: %lu, LED: %s (FALLING edge)\r\n", buttonPressCount, ledState ? "ON" : "OFF");
}
// Check for button releases
if (buttonReleased) {
buttonReleased = false;
Serial.printf("==> Button RELEASED! Count: %lu (RISING edge)\r\n", buttonReleaseCount);
}
delay(10);
}

View file

@ -0,0 +1,147 @@
# ESP32 Lambda FunctionalInterrupt Example
This example demonstrates how to use lambda functions with FunctionalInterrupt for GPIO pin interrupt callbacks on ESP32. It shows CHANGE mode detection with LED toggle functionality and proper debouncing.
## Features Demonstrated
1. **CHANGE mode lambda** to detect both RISING and FALLING edges
2. **LED toggle on button press** (FALLING edge)
3. **Edge type detection** using digitalRead() within ISR
4. **Hardware debouncing** with configurable timeout
5. **IRAM_ATTR lambda declaration** for optimal ISR performance in RAM
## Hardware Setup
- Use BOOT Button or connect a button between BUTTON_PIN and GND (with internal pullup)
- Use Builtin Board LED (no special hardware setup) or connect an LED with resistor to GPIO assigned as LED_PIN.\
Some boards have an RGB LED that needs no special hardware setup to work as a simple white on/off LED.
```
ESP32 Board Button/LED
----------- ---------
BOOT_PIN ------------ [BUTTON] ---- GND
LED_PIN --------------- [LED] ----- GND
¦
[330O] (*) Only needed when using an external LED attached to the GPIO.
¦
3V3
```
## Important ESP32 Interrupt Behavior
**CRITICAL:** Only ONE interrupt handler can be attached per GPIO pin at a time on ESP32.
- Calling `attachInterrupt()` on a pin that already has an interrupt will **override** the previous one
- This applies regardless of edge type (RISING, FALLING, CHANGE)
- If you need both RISING and FALLING detection on the same pin, use **CHANGE mode** and determine the edge type within your handler by reading the pin state
## Code Overview
This example demonstrates a simple CHANGE mode lambda interrupt that:
- **Detects both button press and release** using a single interrupt handler
- **Toggles LED only on button press** (FALLING edge)
- **Reports both press and release events** to Serial output
- **Uses proper debouncing** to prevent switch bounce issues
- **Implements minimal lambda captures** for simplicity
## Lambda Function Pattern
### CHANGE Mode Lambda with IRAM Declaration
```cpp
// Global lambda declared with IRAM_ATTR for optimal ISR performance
IRAM_ATTR std::function<void()> changeModeLambda = []() {
// Debouncing check
unsigned long currentTime = millis();
if (currentTime - lastButtonInterruptTime < DEBOUNCE_DELAY_MS) {
return; // Ignore bouncing
}
// Determine edge type
bool currentState = digitalRead(BUTTON_PIN);
if (currentState == lastButtonState) {
return; // No real state change
}
// Update state and handle edges
lastButtonInterruptTime = currentTime;
lastButtonState = currentState;
if (currentState == LOW) {
// Button pressed (FALLING edge)
buttonPressCount++;
buttonPressed = true;
ledStateChanged = true; // Signal LED toggle
} else {
// Button released (RISING edge)
buttonReleaseCount++;
buttonReleased = true;
}
};
attachInterrupt(BUTTON_PIN, changeModeLambda, CHANGE);
```
## Key Concepts
### Edge Detection in CHANGE Mode
```cpp
if (digitalRead(pin) == LOW) {
// FALLING edge detected (button pressed)
} else {
// RISING edge detected (button released)
}
```
### Debouncing Strategy
This example implements dual-layer debouncing:
1. **Time-based**: Ignores interrupts within 50 ms of previous one
2. **State-based**: Only processes actual state changes
### Main Loop Processing
```cpp
void loop() {
// Handle LED changes safely outside ISR
if (ledStateChanged) {
ledStateChanged = false;
ledState = !ledState;
digitalWrite(LED_PIN, ledState);
}
// Report button events
if (buttonPressed) {
// Handle press event
}
if (buttonReleased) {
// Handle release event
}
}
```
## Expected Output
```
ESP32 Lambda FunctionalInterrupt Example
========================================
Setting up CHANGE mode lambda for LED toggle
Lambda interrupt configured on Pin 0 (CHANGE mode)
Debounce delay: 50 ms
Press the button to toggle the LED!
Button press (FALLING edge) will toggle the LED.
Button release (RISING edge) will be detected and reported.
Button includes debouncing to prevent mechanical bounce issues.
==> Button PRESSED! Count: 1, LED: ON (FALLING edge)
==> Button RELEASED! Count: 1 (RISING edge)
==> Button PRESSED! Count: 2, LED: OFF (FALLING edge)
==> Button RELEASED! Count: 2 (RISING edge)
```
## Pin Configuration
The example uses these default pins:
- `BUTTON_PIN`: BOOT_PIN (automatically assigned by the Arduino Core)
- `LED_PIN`: LED_BUILTIN (may not be available for your board - please verify it)

View file

@ -1,5 +1,5 @@
name=ESP32
version=3.2.0
version=3.2.1
author=Hristo Gochkov, Ivan Grokhtkov
maintainer=Hristo Gochkov <hristo@espressif.com>
sentence=ESP32 sketches examples

View file

@ -24,10 +24,17 @@
2nd September 2021
Lucas Saavedra Vaz (lucasssvaz)
22nd December 2023
anon
10nd February 2025
*/
#include <ESP_I2S.h>
// The GPIO pins are not fixed, most other pins could be used for the I2S function.
#define I2S_LRC 25
#define I2S_BCLK 5
#define I2S_DIN 26
const int frequency = 440; // frequency of square wave in Hz
const int amplitude = 500; // amplitude of square wave
const int sampleRate = 8000; // sample rate in Hz
@ -36,10 +43,10 @@ i2s_data_bit_width_t bps = I2S_DATA_BIT_WIDTH_16BIT;
i2s_mode_t mode = I2S_MODE_STD;
i2s_slot_mode_t slot = I2S_SLOT_MODE_STEREO;
const int halfWavelength = (sampleRate / frequency); // half wavelength of square wave
const unsigned int halfWavelength = sampleRate / frequency / 2; // half wavelength of square wave
int32_t sample = amplitude; // current sample value
int count = 0;
unsigned int count = 0;
I2SClass i2s;
@ -47,6 +54,8 @@ void setup() {
Serial.begin(115200);
Serial.println("I2S simple tone");
i2s.setPins(I2S_BCLK, I2S_LRC, I2S_DIN);
// start I2S at the sample rate with 16-bits per sample
if (!i2s.begin(mode, sampleRate, bps, slot)) {
Serial.println("Failed to initialize I2S!");
@ -60,8 +69,13 @@ void loop() {
sample = -1 * sample;
}
i2s.write(sample); // Right channel
i2s.write(sample); // Left channel
// Left channel, the low 8 bits then high 8 bits
i2s.write(sample);
i2s.write(sample >> 8);
// Right channel, the low 8 bits then high 8 bits
i2s.write(sample);
i2s.write(sample >> 8);
// increment the counter for the next sample
count++;

View file

@ -1,5 +1,5 @@
name=ESP_I2S
version=3.2.0
version=3.2.1
author=me-no-dev
maintainer=me-no-dev
sentence=Library for ESP I2S communication

View file

@ -58,7 +58,7 @@ public:
uint32_t msg_count = 0;
// Create a broadcast peer object
ESP_NOW_Broadcast_Peer broadcast_peer(ESPNOW_WIFI_CHANNEL, WIFI_IF_STA, NULL);
ESP_NOW_Broadcast_Peer broadcast_peer(ESPNOW_WIFI_CHANNEL, WIFI_IF_STA, nullptr);
/* Main */
@ -86,6 +86,8 @@ void setup() {
ESP.restart();
}
Serial.printf("ESP-NOW version: %d, max data length: %d\n", ESP_NOW.getVersion(), ESP_NOW.getMaxDataLen());
Serial.println("Setup complete. Broadcasting messages every 5 seconds.");
}

View file

@ -52,7 +52,8 @@ public:
/* Global Variables */
// List of all the masters. It will be populated when a new master is registered
std::vector<ESP_NOW_Peer_Class> masters;
// Note: Using pointers instead of objects to prevent dangling pointers when the vector reallocates
std::vector<ESP_NOW_Peer_Class *> masters;
/* Callbacks */
@ -62,13 +63,14 @@ void register_new_master(const esp_now_recv_info_t *info, const uint8_t *data, i
Serial.printf("Unknown peer " MACSTR " sent a broadcast message\n", MAC2STR(info->src_addr));
Serial.println("Registering the peer as a master");
ESP_NOW_Peer_Class new_master(info->src_addr, ESPNOW_WIFI_CHANNEL, WIFI_IF_STA, NULL);
masters.push_back(new_master);
if (!masters.back().add_peer()) {
ESP_NOW_Peer_Class *new_master = new ESP_NOW_Peer_Class(info->src_addr, ESPNOW_WIFI_CHANNEL, WIFI_IF_STA, nullptr);
if (!new_master->add_peer()) {
Serial.println("Failed to register the new master");
delete new_master;
return;
}
masters.push_back(new_master);
Serial.printf("Successfully registered master " MACSTR " (total masters: %zu)\n", MAC2STR(new_master->addr()), masters.size());
} else {
// The slave will only receive broadcast messages
log_v("Received a unicast message from " MACSTR, MAC2STR(info->src_addr));
@ -102,12 +104,26 @@ void setup() {
ESP.restart();
}
Serial.printf("ESP-NOW version: %d, max data length: %d\n", ESP_NOW.getVersion(), ESP_NOW.getMaxDataLen());
// Register the new peer callback
ESP_NOW.onNewPeer(register_new_master, NULL);
ESP_NOW.onNewPeer(register_new_master, nullptr);
Serial.println("Setup complete. Waiting for a master to broadcast a message...");
}
void loop() {
delay(1000);
// Print debug information every 10 seconds
static unsigned long last_debug = 0;
if (millis() - last_debug > 10000) {
last_debug = millis();
Serial.printf("Registered masters: %zu\n", masters.size());
for (size_t i = 0; i < masters.size(); i++) {
if (masters[i]) {
Serial.printf(" Master %zu: " MACSTR "\n", i, MAC2STR(masters[i]->addr()));
}
}
}
delay(100);
}

View file

@ -75,7 +75,12 @@
// The following struct is used to send data to the peer device.
// We use the attribute "packed" to ensure that the struct is not padded (all data
// is contiguous in the memory and without gaps).
// The maximum size of the complete message is 250 bytes (ESP_NOW_MAX_DATA_LEN).
// The maximum size of the payload is 250 bytes (ESP_NOW_MAX_DATA_LEN) for ESP-NOW v1.0.
// For ESP-NOW v2.0, the maximum size of the payload is 1470 bytes (ESP_NOW_MAX_DATA_LEN_V2).
// You can use ESP_NOW.getMaxDataLen() after calling ESP_NOW.begin() to get the maximum size
// of the data that can be sent.
// Read about the compatibility between ESP-NOW v1.0 and v2.0 in the ESP-IDF documentation:
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_now.html#frame-format
typedef struct {
uint32_t count;
@ -123,7 +128,7 @@ public:
}
bool send_message(const uint8_t *data, size_t len) {
if (data == NULL || len == 0) {
if (data == nullptr || len == 0) {
log_e("Data to be sent is NULL or has a length of 0");
return false;
}
@ -169,9 +174,12 @@ public:
/* Peers */
std::vector<ESP_NOW_Network_Peer *> peers; // Create a vector to store the peer pointers
ESP_NOW_Network_Peer broadcast_peer(ESP_NOW.BROADCAST_ADDR, 0, NULL); // Register the broadcast peer (no encryption support for the broadcast address)
ESP_NOW_Network_Peer *master_peer = nullptr; // Pointer to peer that is the master
// Create a vector to store the peer pointers
std::vector<ESP_NOW_Network_Peer *> peers;
// Register the broadcast peer (no encryption support for the broadcast address)
ESP_NOW_Network_Peer broadcast_peer(ESP_NOW.BROADCAST_ADDR, 0, nullptr);
// Pointer to the peer that is the master
ESP_NOW_Network_Peer *master_peer = nullptr;
/* Helper functions */
@ -273,13 +281,15 @@ void setup() {
fail_reboot();
}
Serial.printf("ESP-NOW version: %d, max data length: %d\n", ESP_NOW.getVersion(), ESP_NOW.getMaxDataLen());
if (!broadcast_peer.begin()) {
Serial.println("Failed to initialize broadcast peer");
fail_reboot();
}
// Register the callback to be called when a new peer is found
ESP_NOW.onNewPeer(register_new_peer, NULL);
ESP_NOW.onNewPeer(register_new_peer, nullptr);
Serial.println("Setup complete. Broadcasting own priority to find the master...");
memset(&new_msg, 0, sizeof(new_msg));

View file

@ -64,6 +64,7 @@ void setup() {
// Start the ESP-NOW communication
Serial.println("ESP-NOW communication starting...");
NowSerial.begin(115200);
Serial.printf("ESP-NOW version: %d, max data length: %d\n", ESP_NOW.getVersion(), ESP_NOW.getMaxDataLen());
Serial.println("You can now send data to the peer device using the Serial Monitor.\n");
}

View file

@ -1,5 +1,5 @@
name=ESP_NOW
version=3.2.0
version=3.2.1
author=me-no-dev
maintainer=P-R-O-C-H-Y
sentence=Library for ESP_NOW

View file

@ -9,12 +9,12 @@
#include "esp32-hal.h"
#include "esp_wifi.h"
static void (*new_cb)(const esp_now_recv_info_t *info, const uint8_t *data, int len, void *arg) = NULL;
static void *new_arg = NULL; // * tx_arg = NULL, * rx_arg = NULL,
static void (*new_cb)(const esp_now_recv_info_t *info, const uint8_t *data, int len, void *arg) = nullptr;
static void *new_arg = nullptr; // * tx_arg = nullptr, * rx_arg = nullptr,
static bool _esp_now_has_begun = false;
static ESP_NOW_Peer *_esp_now_peers[ESP_NOW_MAX_TOTAL_PEER_NUM];
static esp_err_t _esp_now_add_peer(const uint8_t *mac_addr, uint8_t channel, wifi_interface_t iface, const uint8_t *lmk, ESP_NOW_Peer *_peer = NULL) {
static esp_err_t _esp_now_add_peer(const uint8_t *mac_addr, uint8_t channel, wifi_interface_t iface, const uint8_t *lmk, ESP_NOW_Peer *_peer = nullptr) {
log_v(MACSTR, MAC2STR(mac_addr));
if (esp_now_is_peer_exist(mac_addr)) {
log_e("Peer Already Exists");
@ -26,16 +26,16 @@ static esp_err_t _esp_now_add_peer(const uint8_t *mac_addr, uint8_t channel, wif
memcpy(peer.peer_addr, mac_addr, ESP_NOW_ETH_ALEN);
peer.channel = channel;
peer.ifidx = iface;
peer.encrypt = lmk != NULL;
peer.encrypt = lmk != nullptr;
if (lmk) {
memcpy(peer.lmk, lmk, ESP_NOW_KEY_LEN);
}
esp_err_t result = esp_now_add_peer(&peer);
if (result == ESP_OK) {
if (_peer != NULL) {
if (_peer != nullptr) {
for (uint8_t i = 0; i < ESP_NOW_MAX_TOTAL_PEER_NUM; i++) {
if (_esp_now_peers[i] == NULL) {
if (_esp_now_peers[i] == nullptr) {
_esp_now_peers[i] = _peer;
return ESP_OK;
}
@ -67,8 +67,8 @@ static esp_err_t _esp_now_del_peer(const uint8_t *mac_addr) {
}
for (uint8_t i = 0; i < ESP_NOW_MAX_TOTAL_PEER_NUM; i++) {
if (_esp_now_peers[i] != NULL && memcmp(mac_addr, _esp_now_peers[i]->addr(), ESP_NOW_ETH_ALEN) == 0) {
_esp_now_peers[i] = NULL;
if (_esp_now_peers[i] != nullptr && memcmp(mac_addr, _esp_now_peers[i]->addr(), ESP_NOW_ETH_ALEN) == 0) {
_esp_now_peers[i] = nullptr;
break;
}
}
@ -87,7 +87,7 @@ static esp_err_t _esp_now_modify_peer(const uint8_t *mac_addr, uint8_t channel,
memcpy(peer.peer_addr, mac_addr, ESP_NOW_ETH_ALEN);
peer.channel = channel;
peer.ifidx = iface;
peer.encrypt = lmk != NULL;
peer.encrypt = lmk != nullptr;
if (lmk) {
memcpy(peer.lmk, lmk, ESP_NOW_KEY_LEN);
}
@ -111,17 +111,17 @@ static void _esp_now_rx_cb(const esp_now_recv_info_t *info, const uint8_t *data,
bool broadcast = memcmp(info->des_addr, ESP_NOW.BROADCAST_ADDR, ESP_NOW_ETH_ALEN) == 0;
log_v("%s from " MACSTR ", data length : %u", broadcast ? "Broadcast" : "Unicast", MAC2STR(info->src_addr), len);
log_buf_v(data, len);
if (!esp_now_is_peer_exist(info->src_addr) && new_cb != NULL) {
if (!esp_now_is_peer_exist(info->src_addr) && new_cb != nullptr) {
log_v("Calling new_cb, peer not found.");
new_cb(info, data, len, new_arg);
return;
}
//find the peer and call it's callback
for (uint8_t i = 0; i < ESP_NOW_MAX_TOTAL_PEER_NUM; i++) {
if (_esp_now_peers[i] != NULL) {
if (_esp_now_peers[i] != nullptr) {
log_v("Checking peer " MACSTR, MAC2STR(_esp_now_peers[i]->addr()));
}
if (_esp_now_peers[i] != NULL && memcmp(info->src_addr, _esp_now_peers[i]->addr(), ESP_NOW_ETH_ALEN) == 0) {
if (_esp_now_peers[i] != nullptr && memcmp(info->src_addr, _esp_now_peers[i]->addr(), ESP_NOW_ETH_ALEN) == 0) {
log_v("Calling onReceive");
_esp_now_peers[i]->onReceive(data, len, broadcast);
return;
@ -133,14 +133,17 @@ static void _esp_now_tx_cb(const uint8_t *mac_addr, esp_now_send_status_t status
log_v(MACSTR " : %s", MAC2STR(mac_addr), (status == ESP_NOW_SEND_SUCCESS) ? "SUCCESS" : "FAILED");
//find the peer and call it's callback
for (uint8_t i = 0; i < ESP_NOW_MAX_TOTAL_PEER_NUM; i++) {
if (_esp_now_peers[i] != NULL && memcmp(mac_addr, _esp_now_peers[i]->addr(), ESP_NOW_ETH_ALEN) == 0) {
if (_esp_now_peers[i] != nullptr && memcmp(mac_addr, _esp_now_peers[i]->addr(), ESP_NOW_ETH_ALEN) == 0) {
_esp_now_peers[i]->onSent(status == ESP_NOW_SEND_SUCCESS);
return;
}
}
}
ESP_NOW_Class::ESP_NOW_Class() {}
ESP_NOW_Class::ESP_NOW_Class() {
max_data_len = 0;
version = 0;
}
ESP_NOW_Class::~ESP_NOW_Class() {}
@ -155,6 +158,23 @@ bool ESP_NOW_Class::begin(const uint8_t *pmk) {
return false;
}
// Unfortunately we can't get the ESP-NOW version before initializing the Wi-Fi
uint32_t esp_now_version;
err = esp_now_get_version(&esp_now_version);
if (err != ESP_OK) {
log_w("esp_now_get_version failed! Assuming ESP-NOW v1.0");
esp_now_version = 1;
}
if (esp_now_version == 1) {
max_data_len = ESP_NOW_MAX_DATA_LEN;
} else {
max_data_len = ESP_NOW_MAX_DATA_LEN_V2;
}
version = esp_now_version;
log_i("ESP-NOW version: %lu, max_data_len: %lu", version, max_data_len);
_esp_now_has_begun = true;
memset(_esp_now_peers, 0, sizeof(ESP_NOW_Peer *) * ESP_NOW_MAX_TOTAL_PEER_NUM);
@ -197,7 +217,7 @@ bool ESP_NOW_Class::end() {
}
//remove all peers
for (uint8_t i = 0; i < ESP_NOW_MAX_TOTAL_PEER_NUM; i++) {
if (_esp_now_peers[i] != NULL) {
if (_esp_now_peers[i] != nullptr) {
removePeer(*_esp_now_peers[i]);
}
}
@ -212,7 +232,7 @@ bool ESP_NOW_Class::end() {
return true;
}
int ESP_NOW_Class::getTotalPeerCount() {
int ESP_NOW_Class::getTotalPeerCount() const {
if (!_esp_now_has_begun) {
return -1;
}
@ -225,7 +245,7 @@ int ESP_NOW_Class::getTotalPeerCount() {
return num.total_num;
}
int ESP_NOW_Class::getEncryptedPeerCount() {
int ESP_NOW_Class::getEncryptedPeerCount() const {
if (!_esp_now_has_begun) {
return -1;
}
@ -238,18 +258,40 @@ int ESP_NOW_Class::getEncryptedPeerCount() {
return num.encrypt_num;
}
int ESP_NOW_Class::getMaxDataLen() const {
if (max_data_len == 0) {
log_e("ESP-NOW not initialized. Please call begin() first to get the max data length.");
return -1;
}
return max_data_len;
}
int ESP_NOW_Class::getVersion() const {
if (version == 0) {
log_e("ESP-NOW not initialized. Please call begin() first to get the version.");
return -1;
}
return version;
}
int ESP_NOW_Class::availableForWrite() {
return ESP_NOW_MAX_DATA_LEN;
int available = getMaxDataLen();
if (available < 0) {
return 0;
}
return available;
}
size_t ESP_NOW_Class::write(const uint8_t *data, size_t len) {
if (!_esp_now_has_begun) {
return 0;
}
if (len > ESP_NOW_MAX_DATA_LEN) {
len = ESP_NOW_MAX_DATA_LEN;
if (len > max_data_len) {
len = max_data_len;
}
esp_err_t result = esp_now_send(NULL, data, len);
esp_err_t result = esp_now_send(nullptr, data, len);
if (result == ESP_OK) {
return len;
} else if (result == ESP_ERR_ESPNOW_NOT_INIT) {
@ -292,7 +334,7 @@ ESP_NOW_Peer::ESP_NOW_Peer(const uint8_t *mac_addr, uint8_t channel, wifi_interf
}
chan = channel;
ifc = iface;
encrypt = lmk != NULL;
encrypt = lmk != nullptr;
if (encrypt) {
memcpy(key, lmk, 16);
}
@ -305,7 +347,7 @@ bool ESP_NOW_Peer::add() {
if (added) {
return true;
}
if (_esp_now_add_peer(mac, chan, ifc, encrypt ? key : NULL, this) != ESP_OK) {
if (_esp_now_add_peer(mac, chan, ifc, encrypt ? key : nullptr, this) != ESP_OK) {
return false;
}
log_v("Peer added - " MACSTR, MAC2STR(mac));
@ -350,7 +392,7 @@ bool ESP_NOW_Peer::setChannel(uint8_t channel) {
if (!_esp_now_has_begun || !added) {
return true;
}
return _esp_now_modify_peer(mac, chan, ifc, encrypt ? key : NULL) == ESP_OK;
return _esp_now_modify_peer(mac, chan, ifc, encrypt ? key : nullptr) == ESP_OK;
}
wifi_interface_t ESP_NOW_Peer::getInterface() const {
@ -362,7 +404,7 @@ bool ESP_NOW_Peer::setInterface(wifi_interface_t iface) {
if (!_esp_now_has_begun || !added) {
return true;
}
return _esp_now_modify_peer(mac, chan, ifc, encrypt ? key : NULL) == ESP_OK;
return _esp_now_modify_peer(mac, chan, ifc, encrypt ? key : nullptr) == ESP_OK;
}
bool ESP_NOW_Peer::isEncrypted() const {
@ -370,14 +412,14 @@ bool ESP_NOW_Peer::isEncrypted() const {
}
bool ESP_NOW_Peer::setKey(const uint8_t *lmk) {
encrypt = lmk != NULL;
encrypt = lmk != nullptr;
if (encrypt) {
memcpy(key, lmk, 16);
}
if (!_esp_now_has_begun || !added) {
return true;
}
return _esp_now_modify_peer(mac, chan, ifc, encrypt ? key : NULL) == ESP_OK;
return _esp_now_modify_peer(mac, chan, ifc, encrypt ? key : nullptr) == ESP_OK;
}
size_t ESP_NOW_Peer::send(const uint8_t *data, int len) {
@ -386,8 +428,15 @@ size_t ESP_NOW_Peer::send(const uint8_t *data, int len) {
log_e("Peer not added.");
return 0;
}
if (len > ESP_NOW_MAX_DATA_LEN) {
len = ESP_NOW_MAX_DATA_LEN;
int max_data_len = ESP_NOW.getMaxDataLen();
if (max_data_len < 0) {
log_e("Error getting max data length.");
return 0;
}
if (len > max_data_len) {
len = max_data_len;
}
esp_err_t result = esp_now_send(mac, data, len);
if (result == ESP_OK) {

View file

@ -20,11 +20,13 @@ public:
ESP_NOW_Class();
~ESP_NOW_Class();
bool begin(const uint8_t *pmk = NULL /* 16 bytes */);
bool begin(const uint8_t *pmk = nullptr /* 16 bytes */);
bool end();
int getTotalPeerCount();
int getEncryptedPeerCount();
int getTotalPeerCount() const;
int getEncryptedPeerCount() const;
int getMaxDataLen() const;
int getVersion() const;
int availableForWrite();
size_t write(const uint8_t *data, size_t len);
@ -34,6 +36,10 @@ public:
void onNewPeer(void (*cb)(const esp_now_recv_info_t *info, const uint8_t *data, int len, void *arg), void *arg);
bool removePeer(ESP_NOW_Peer &peer);
protected:
size_t max_data_len;
uint32_t version;
};
class ESP_NOW_Peer {
@ -50,7 +56,7 @@ protected:
bool remove();
size_t send(const uint8_t *data, int len);
ESP_NOW_Peer(const uint8_t *mac_addr, uint8_t channel = 0, wifi_interface_t iface = WIFI_IF_AP, const uint8_t *lmk = NULL);
ESP_NOW_Peer(const uint8_t *mac_addr, uint8_t channel = 0, wifi_interface_t iface = WIFI_IF_AP, const uint8_t *lmk = nullptr);
public:
virtual ~ESP_NOW_Peer() {}

View file

@ -18,11 +18,11 @@
ESP_NOW_Serial_Class::ESP_NOW_Serial_Class(const uint8_t *mac_addr, uint8_t channel, wifi_interface_t iface, const uint8_t *lmk, bool remove_on_fail)
: ESP_NOW_Peer(mac_addr, channel, iface, lmk) {
tx_ring_buf = NULL;
rx_queue = NULL;
tx_sem = NULL;
tx_ring_buf = nullptr;
rx_queue = nullptr;
tx_sem = nullptr;
queued_size = 0;
queued_buff = NULL;
queued_buff = nullptr;
resend_count = 0;
_remove_on_fail = remove_on_fail;
}
@ -34,7 +34,7 @@ ESP_NOW_Serial_Class::~ESP_NOW_Serial_Class() {
size_t ESP_NOW_Serial_Class::setTxBufferSize(size_t tx_queue_len) {
if (tx_ring_buf) {
vRingbufferDelete(tx_ring_buf);
tx_ring_buf = NULL;
tx_ring_buf = nullptr;
}
if (!tx_queue_len) {
return 0;
@ -49,7 +49,7 @@ size_t ESP_NOW_Serial_Class::setTxBufferSize(size_t tx_queue_len) {
size_t ESP_NOW_Serial_Class::setRxBufferSize(size_t rx_queue_len) {
if (rx_queue) {
vQueueDelete(rx_queue);
rx_queue = NULL;
rx_queue = nullptr;
}
if (!rx_queue_len) {
return 0;
@ -65,13 +65,30 @@ bool ESP_NOW_Serial_Class::begin(unsigned long baud) {
if (!ESP_NOW.begin() || !add()) {
return false;
}
if (tx_sem == NULL) {
if (tx_sem == nullptr) {
tx_sem = xSemaphoreCreateBinary();
//xSemaphoreTake(tx_sem, 0);
xSemaphoreGive(tx_sem);
}
setRxBufferSize(1024); //default if not preset
setTxBufferSize(1024); //default if not preset
size_t buf_size = 0;
if (ESP_NOW.getVersion() == 2) {
// ESP-NOW v2.0 has a larger maximum data length, so we need to increase the buffer sizes
// to hold around 3-4 packets
buf_size = setRxBufferSize(4096);
buf_size &= setTxBufferSize(4096);
} else {
// ESP-NOW v1.0 has a smaller maximum data length, so we can use the default buffer sizes
// to hold around 3-4 packets
buf_size = setRxBufferSize(1024);
buf_size &= setTxBufferSize(1024);
}
if (buf_size == 0) {
log_e("Failed to set buffer size");
return false;
}
return true;
}
@ -79,22 +96,22 @@ void ESP_NOW_Serial_Class::end() {
remove();
setRxBufferSize(0);
setTxBufferSize(0);
if (tx_sem != NULL) {
if (tx_sem != nullptr) {
vSemaphoreDelete(tx_sem);
tx_sem = NULL;
tx_sem = nullptr;
}
}
//Stream
int ESP_NOW_Serial_Class::available(void) {
if (rx_queue == NULL) {
if (rx_queue == nullptr) {
return 0;
}
return uxQueueMessagesWaiting(rx_queue);
}
int ESP_NOW_Serial_Class::peek(void) {
if (rx_queue == NULL) {
if (rx_queue == nullptr) {
return -1;
}
uint8_t c;
@ -105,7 +122,7 @@ int ESP_NOW_Serial_Class::peek(void) {
}
int ESP_NOW_Serial_Class::read(void) {
if (rx_queue == NULL) {
if (rx_queue == nullptr) {
return -1;
}
uint8_t c = 0;
@ -116,7 +133,7 @@ int ESP_NOW_Serial_Class::read(void) {
}
size_t ESP_NOW_Serial_Class::read(uint8_t *buffer, size_t size) {
if (rx_queue == NULL) {
if (rx_queue == nullptr) {
return -1;
}
uint8_t c = 0;
@ -128,11 +145,11 @@ size_t ESP_NOW_Serial_Class::read(uint8_t *buffer, size_t size) {
}
void ESP_NOW_Serial_Class::flush() {
if (tx_ring_buf == NULL) {
if (tx_ring_buf == nullptr) {
return;
}
UBaseType_t uxItemsWaiting = 0;
vRingbufferGetInfo(tx_ring_buf, NULL, NULL, NULL, NULL, &uxItemsWaiting);
vRingbufferGetInfo(tx_ring_buf, nullptr, nullptr, nullptr, nullptr, &uxItemsWaiting);
if (uxItemsWaiting) {
// Now trigger the ISR to read data from the ring buffer.
if (xSemaphoreTake(tx_sem, 0) == pdTRUE) {
@ -141,13 +158,13 @@ void ESP_NOW_Serial_Class::flush() {
}
while (uxItemsWaiting) {
delay(5);
vRingbufferGetInfo(tx_ring_buf, NULL, NULL, NULL, NULL, &uxItemsWaiting);
vRingbufferGetInfo(tx_ring_buf, nullptr, nullptr, nullptr, nullptr, &uxItemsWaiting);
}
}
//RX callback
void ESP_NOW_Serial_Class::onReceive(const uint8_t *data, size_t len, bool broadcast) {
if (rx_queue == NULL) {
if (rx_queue == nullptr) {
return;
}
for (uint32_t i = 0; i < len; i++) {
@ -164,8 +181,7 @@ void ESP_NOW_Serial_Class::onReceive(const uint8_t *data, size_t len, bool broad
//Print
int ESP_NOW_Serial_Class::availableForWrite() {
//return ESP_NOW_MAX_DATA_LEN;
if (tx_ring_buf == NULL) {
if (tx_ring_buf == nullptr) {
return 0;
}
return xRingbufferGetCurFreeSize(tx_ring_buf);
@ -178,7 +194,7 @@ size_t ESP_NOW_Serial_Class::tryToSend() {
//_onSent will not be called anymore
//the data is lost in this case
vRingbufferReturnItem(tx_ring_buf, queued_buff);
queued_buff = NULL;
queued_buff = nullptr;
xSemaphoreGive(tx_sem);
end();
}
@ -188,12 +204,12 @@ size_t ESP_NOW_Serial_Class::tryToSend() {
bool ESP_NOW_Serial_Class::checkForTxData() {
//do we have something that failed the last time?
resend_count = 0;
if (queued_buff == NULL) {
queued_buff = (uint8_t *)xRingbufferReceiveUpTo(tx_ring_buf, &queued_size, 0, ESP_NOW_MAX_DATA_LEN);
if (queued_buff == nullptr) {
queued_buff = (uint8_t *)xRingbufferReceiveUpTo(tx_ring_buf, &queued_size, 0, ESP_NOW.getMaxDataLen());
} else {
log_d(MACSTR " : PREVIOUS", MAC2STR(addr()));
}
if (queued_buff != NULL) {
if (queued_buff != nullptr) {
return tryToSend() > 0;
}
//log_d(MACSTR ": EMPTY", MAC2STR(addr()));
@ -203,7 +219,7 @@ bool ESP_NOW_Serial_Class::checkForTxData() {
size_t ESP_NOW_Serial_Class::write(const uint8_t *buffer, size_t size, uint32_t timeout) {
log_v(MACSTR ", size %u", MAC2STR(addr()), size);
if (tx_sem == NULL || tx_ring_buf == NULL || !added) {
if (tx_sem == nullptr || tx_ring_buf == nullptr || !added) {
return 0;
}
size_t space = availableForWrite();
@ -249,12 +265,12 @@ size_t ESP_NOW_Serial_Class::write(const uint8_t *buffer, size_t size, uint32_t
//TX Done Callback
void ESP_NOW_Serial_Class::onSent(bool success) {
log_v(MACSTR " : %s", MAC2STR(addr()), success ? "OK" : "FAIL");
if (tx_sem == NULL || tx_ring_buf == NULL || !added) {
if (tx_sem == nullptr || tx_ring_buf == nullptr || !added) {
return;
}
if (success) {
vRingbufferReturnItem(tx_ring_buf, queued_buff);
queued_buff = NULL;
queued_buff = nullptr;
//send next packet?
//log_d(MACSTR ": NEXT", MAC2STR(addr()));
checkForTxData();
@ -269,7 +285,7 @@ void ESP_NOW_Serial_Class::onSent(bool success) {
//resend limit reached
//the data is lost in this case
vRingbufferReturnItem(tx_ring_buf, queued_buff);
queued_buff = NULL;
queued_buff = nullptr;
log_e(MACSTR " : RE-SEND_MAX[%u]", MAC2STR(addr()), resend_count);
//if we are not able to send the data and remove_on_fail is set, remove the peer
if (_remove_on_fail) {

View file

@ -28,7 +28,9 @@ private:
size_t tryToSend();
public:
ESP_NOW_Serial_Class(const uint8_t *mac_addr, uint8_t channel, wifi_interface_t iface = WIFI_IF_AP, const uint8_t *lmk = NULL, bool remove_on_fail = false);
ESP_NOW_Serial_Class(
const uint8_t *mac_addr, uint8_t channel, wifi_interface_t iface = WIFI_IF_AP, const uint8_t *lmk = nullptr, bool remove_on_fail = false
);
~ESP_NOW_Serial_Class();
size_t setRxBufferSize(size_t);
size_t setTxBufferSize(size_t);

View file

@ -1,5 +1,5 @@
name=ESP_SR
version=3.2.0
version=3.2.1
author=me-no-dev
maintainer=me-no-dev
sentence=Library for ESP Sound Recognition

View file

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

Some files were not shown because too many files have changed in this diff Show more