mirror of
https://github.com/m5stack/ESP-Claw.git
synced 2026-05-20 11:51:49 -07:00
Merge branch 'doc/add-auto-publish' into 'master'
feat: add CI for automatic doc deployment See merge request ae_group/esp-claw!64
This commit is contained in:
+3
-9
@@ -1,15 +1,8 @@
|
||||
spec:
|
||||
inputs:
|
||||
force_push_to_github:
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
---
|
||||
|
||||
stages:
|
||||
- pre-check
|
||||
- build
|
||||
- deploy
|
||||
- deploy-github
|
||||
|
||||
workflow:
|
||||
rules:
|
||||
@@ -28,10 +21,11 @@ workflow:
|
||||
|
||||
variables:
|
||||
IOT_SOLUTION_PATH: "$CI_PROJECT_DIR"
|
||||
CI_FORCE_PUSH_TO_GITHUB: "$[[ inputs.force_push_to_github ]]"
|
||||
|
||||
include:
|
||||
- '.gitlab/ci/rules.yml'
|
||||
- '.gitlab/ci/pre-check.yml'
|
||||
- '.gitlab/ci/build.yml'
|
||||
- '.gitlab/ci/build-doc.yml'
|
||||
- '.gitlab/ci/deploy.yml'
|
||||
- '.gitlab/ci/deploy-github.yml'
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
build_doc:
|
||||
stage: build
|
||||
tags:
|
||||
- build
|
||||
image: node:24
|
||||
extends:
|
||||
- .rules:build:doc
|
||||
needs:
|
||||
- job: build_application_basic_demo
|
||||
artifacts: true
|
||||
optional: true
|
||||
script:
|
||||
- apt update && apt install -y curl
|
||||
- curl -fsSL https://d2lang.com/install.sh | sh -s --
|
||||
- npm install -g pnpm
|
||||
- cd docs
|
||||
- pnpm install
|
||||
- pnpm run generate-firmware-json ../merged_binary
|
||||
- pnpm run build
|
||||
artifacts:
|
||||
when: always
|
||||
paths:
|
||||
- docs/public/**/*
|
||||
- docs/dist/**/*
|
||||
- docs/src/flash-tool/firmware.json
|
||||
expire_in: 1 week
|
||||
@@ -0,0 +1,24 @@
|
||||
push_to_github:
|
||||
stage: deploy-github
|
||||
tags:
|
||||
- build
|
||||
image: alpine:latest
|
||||
variables:
|
||||
GIT_STRATEGY: clone
|
||||
GIT_DEPTH: "0"
|
||||
extends:
|
||||
- .rules:push:github
|
||||
script:
|
||||
- apk add --no-cache git openssh-client curl
|
||||
- mkdir -p ~/.ssh
|
||||
- chmod 700 ~/.ssh
|
||||
- printf '%s' "$GH_PUSH_KEY" | base64 -d > ~/.ssh/id_rsa
|
||||
- chmod 600 ~/.ssh/id_rsa
|
||||
- ssh-keyscan -H github.com >> ~/.ssh/known_hosts 2>/dev/null || true
|
||||
- git remote remove github 2>/dev/null || true
|
||||
- git remote add github "$GH_REMOTE_URL"
|
||||
- git push github "refs/heads/master:refs/heads/master"
|
||||
- |
|
||||
for tag in $(git tag --merged refs/heads/master); do
|
||||
git push github "refs/tags/$tag:refs/tags/$tag"
|
||||
done
|
||||
+21
-21
@@ -1,35 +1,35 @@
|
||||
collect_firmware_manifest:
|
||||
extends:
|
||||
- .rules:build:application_basic_demo
|
||||
deploy_website:
|
||||
stage: deploy
|
||||
tags:
|
||||
- build
|
||||
image: python:3.13-slim
|
||||
allow_failure: true
|
||||
image: node:24-alpine
|
||||
variables:
|
||||
GIT_STRATEGY: fetch
|
||||
environment:
|
||||
name: $DEPLOY_ENV_NAME
|
||||
url: $DEPLOY_ENV_URL
|
||||
deployment_tier: $DEPLOY_ENV_TIER
|
||||
rules:
|
||||
- if: '$CI_COMMIT_REF_NAME == "master" && $CI_PIPELINE_SOURCE == "push"'
|
||||
- if: '$CI_COMMIT_REF_NAME == "master" && $CI_COMMIT_TAG == null && $CI_PIPELINE_SOURCE == "push"'
|
||||
when: on_success
|
||||
variables:
|
||||
DEPLOY_FIRMWARE: "1"
|
||||
- if: '$CI_COMMIT_REF_NAME != "master" && $CI_PIPELINE_SOURCE == "merge_request_event"'
|
||||
DEPLOY_ENV_NAME: docs-production
|
||||
DEPLOY_ENV_URL: https://esp-claw.com
|
||||
DEPLOY_ENV_TIER: production
|
||||
DEPLOY_BRANCH: master
|
||||
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
|
||||
changes:
|
||||
- "docs/**/*"
|
||||
when: on_success
|
||||
variables:
|
||||
DEPLOY_FIRMWARE: "0"
|
||||
DEPLOY_ENV_NAME: docs-preview/$CI_COMMIT_REF_SLUG
|
||||
DEPLOY_ENV_URL: https://$CI_COMMIT_REF_SLUG.$PREVIEW_DOMAIN
|
||||
DEPLOY_ENV_TIER: development
|
||||
DEPLOY_BRANCH: $CI_COMMIT_REF_NAME
|
||||
- when: never
|
||||
needs:
|
||||
- job: build_application_basic_demo
|
||||
- job: build_doc
|
||||
artifacts: true
|
||||
optional: true
|
||||
script:
|
||||
- apt-get update
|
||||
- apt-get install -y curl
|
||||
- python .gitlab/ci/generate_firmware_json.py
|
||||
- python .gitlab/ci/deploy_firmware.py
|
||||
artifacts:
|
||||
when: always
|
||||
paths:
|
||||
- firmware.json
|
||||
- merged_binary/**/*
|
||||
expire_in: 1 week
|
||||
- cd docs
|
||||
- npx wrangler pages deploy "dist/" --project-name "$SITE_DEPLOY_PROJECT_NAME" --branch="$DEPLOY_BRANCH"
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
"""
|
||||
Deploy firmware artifacts to the download server.
|
||||
|
||||
Behavior is controlled by the DEPLOY_FIRMWARE environment variable:
|
||||
"1" - package firmware.json + merged_binary/ into esp-claw-firmware.zip and upload
|
||||
"0" - print a skip message and exit
|
||||
"""
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
|
||||
ARCHIVE_NAME = 'esp-claw-firmware.zip'
|
||||
|
||||
|
||||
def build_archive() -> Path:
|
||||
archive_path = Path(ARCHIVE_NAME)
|
||||
with zipfile.ZipFile(archive_path, 'w', zipfile.ZIP_DEFLATED) as zf:
|
||||
firmware_json = Path('firmware.json')
|
||||
if firmware_json.exists():
|
||||
zf.write(firmware_json, firmware_json.name)
|
||||
print(f" added: {firmware_json}")
|
||||
else:
|
||||
print('WARNING: firmware.json not found, skipping.', file=sys.stderr)
|
||||
|
||||
merged_binary = Path('merged_binary')
|
||||
if merged_binary.exists():
|
||||
for file in sorted(merged_binary.rglob('*')):
|
||||
if file.is_file():
|
||||
zf.write(file, file.as_posix())
|
||||
print(f" added: {file}")
|
||||
else:
|
||||
print('WARNING: merged_binary/ directory not found, skipping.', file=sys.stderr)
|
||||
|
||||
print(f"Archive created: {archive_path} ({archive_path.stat().st_size} bytes)")
|
||||
return archive_path
|
||||
|
||||
|
||||
def upload_archive(archive_path: Path) -> None:
|
||||
upload_key = os.environ.get('DL_UPLOAD_KEY')
|
||||
upload_api_url = os.environ.get('DL_UPLOAD_API_URL')
|
||||
upload_path = os.environ.get('DL_UPLOAD_PATH')
|
||||
|
||||
missing = [var for var, val in [
|
||||
('DL_UPLOAD_KEY', upload_key),
|
||||
('DL_UPLOAD_API_URL', upload_api_url),
|
||||
('DL_UPLOAD_PATH', upload_path),
|
||||
] if not val]
|
||||
|
||||
if missing:
|
||||
print(f"ERROR: Missing required environment variables: {', '.join(missing)}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
cmd = [
|
||||
'curl',
|
||||
'--fail',
|
||||
'-u', upload_key,
|
||||
'-F', f"file=@{archive_path}",
|
||||
'-F', f"path={upload_path}",
|
||||
upload_api_url,
|
||||
]
|
||||
|
||||
print(f"Uploading {archive_path} to {upload_api_url} (path={upload_path}) ...")
|
||||
result = subprocess.run(cmd, check=False)
|
||||
if result.returncode != 0:
|
||||
print(f"ERROR: Upload failed with exit code {result.returncode}", file=sys.stderr)
|
||||
sys.exit(result.returncode)
|
||||
|
||||
print('Upload succeeded.')
|
||||
|
||||
|
||||
def main() -> None:
|
||||
deploy_firmware = os.environ.get('DEPLOY_FIRMWARE', '0')
|
||||
|
||||
if deploy_firmware != '1':
|
||||
print(f"DEPLOY_FIRMWARE={deploy_firmware!r}: skipping firmware deployment.")
|
||||
sys.exit(0)
|
||||
|
||||
print('DEPLOY_FIRMWARE=1: packaging and uploading firmware artifacts ...')
|
||||
archive_path = build_archive()
|
||||
upload_archive(archive_path)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,140 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List
|
||||
|
||||
|
||||
def _log(msg: str) -> None:
|
||||
print(msg, file=sys.stderr)
|
||||
|
||||
|
||||
def _parse_flash_mb(value: Any) -> int:
|
||||
if isinstance(value, int):
|
||||
return value
|
||||
|
||||
if not isinstance(value, str):
|
||||
raise ValueError(f'unsupported min_flash_size type: {type(value)}')
|
||||
|
||||
text = value.strip()
|
||||
if not text:
|
||||
raise ValueError('empty min_flash_size')
|
||||
|
||||
upper = text.upper()
|
||||
if upper.endswith('MB'):
|
||||
return int(upper[:-2].strip(), 0)
|
||||
if upper.endswith('M'):
|
||||
return int(upper[:-1].strip(), 0)
|
||||
|
||||
num = int(text, 0)
|
||||
if num % (1024 * 1024) == 0:
|
||||
return num // (1024 * 1024)
|
||||
|
||||
return num
|
||||
|
||||
|
||||
def _join_base_url(base_url: str, filename: str) -> str:
|
||||
if not base_url:
|
||||
base_url = '/'
|
||||
|
||||
if base_url.endswith('/'):
|
||||
return f'{base_url}{filename}'
|
||||
|
||||
return f'{base_url}/{filename}'
|
||||
|
||||
|
||||
def _load_metadata_files(merged_dir: Path) -> List[Dict[str, Any]]:
|
||||
metadata_files = sorted(merged_dir.glob('*.json'))
|
||||
if not metadata_files:
|
||||
raise RuntimeError(f'No metadata json found in {merged_dir}')
|
||||
|
||||
records: List[Dict[str, Any]] = []
|
||||
for path in metadata_files:
|
||||
with path.open('r', encoding='utf-8') as fr:
|
||||
data = json.load(fr)
|
||||
if not isinstance(data, dict):
|
||||
raise RuntimeError(f'Invalid metadata format: {path}')
|
||||
records.append(data)
|
||||
|
||||
return records
|
||||
|
||||
|
||||
def main() -> int:
|
||||
cwd = Path.cwd()
|
||||
merged_dir = cwd / 'merged_binary'
|
||||
|
||||
if not merged_dir.is_dir():
|
||||
_log(f'merged_binary directory not found: {merged_dir}')
|
||||
return 1
|
||||
|
||||
base_url = os.getenv('MERGED_BINARY_BASE_URL', '/').strip() or '/'
|
||||
|
||||
try:
|
||||
records = _load_metadata_files(merged_dir)
|
||||
except Exception as e:
|
||||
_log(str(e))
|
||||
return 1
|
||||
|
||||
firmware: Dict[str, List[Dict[str, Any]]] = {}
|
||||
|
||||
for record in records:
|
||||
chip = record.get('chip')
|
||||
board = record.get('board')
|
||||
merged_binary = record.get('merged_binary')
|
||||
min_flash_size = record.get('min_flash_size')
|
||||
nvs_info = record.get('nvs_info')
|
||||
|
||||
if not isinstance(chip, str) or not chip.strip():
|
||||
_log(f'skip one metadata: invalid chip ({record})')
|
||||
continue
|
||||
if not isinstance(board, str) or not board.strip():
|
||||
_log(f'skip one metadata: invalid board ({record})')
|
||||
continue
|
||||
if not isinstance(merged_binary, str) or not merged_binary.strip():
|
||||
_log(f'skip one metadata: invalid merged_binary ({record})')
|
||||
continue
|
||||
if not isinstance(nvs_info, dict):
|
||||
_log(f'skip one metadata: invalid nvs_info ({record})')
|
||||
continue
|
||||
|
||||
try:
|
||||
min_flash_mb = _parse_flash_mb(min_flash_size)
|
||||
except Exception as e:
|
||||
_log(f'skip one metadata: invalid min_flash_size ({record}) ({e})')
|
||||
continue
|
||||
|
||||
item = {
|
||||
'board': board,
|
||||
'features': [],
|
||||
'description': '',
|
||||
'merged_binary': _join_base_url(base_url, merged_binary),
|
||||
'min_flash_size': min_flash_mb,
|
||||
'min_psram_size': 8,
|
||||
'nvs_info': {
|
||||
'start_addr': str(nvs_info.get('start_addr', '')),
|
||||
'size': str(nvs_info.get('size', '')),
|
||||
},
|
||||
}
|
||||
|
||||
firmware.setdefault(chip, []).append(item)
|
||||
|
||||
if not firmware:
|
||||
_log('No valid metadata collected from merged_binary/*.json')
|
||||
return 1
|
||||
|
||||
for chip in firmware:
|
||||
firmware[chip].sort(key=lambda x: x['board'])
|
||||
|
||||
out_file = cwd / 'firmware.json'
|
||||
out_file.write_text(json.dumps(firmware, ensure_ascii=False, indent=2) + '\n', encoding='utf-8')
|
||||
print(f'Generated: {out_file}')
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
+50
-108
@@ -10,78 +10,38 @@
|
||||
- "pytest.ini"
|
||||
|
||||
# components folder, in the alphabetic order
|
||||
.patterns-components_cap_cli: &patterns-components_cap_cli
|
||||
- "components/cap_cli/**/*"
|
||||
.patterns-components_capabilities: &patterns-components_capabilities
|
||||
- "components/claw_capabilities/**/*"
|
||||
|
||||
.patterns-components_cap_files: &patterns-components_cap_files
|
||||
- "components/cap_files/**/*"
|
||||
.patterns-components_modules: &patterns-components_modules
|
||||
- "components/claw_modules/**/*"
|
||||
|
||||
.patterns-components_cap_im_attachment: &patterns-components_cap_im_attachment
|
||||
- "components/cap_im_attachment/**/*"
|
||||
|
||||
.patterns-components_cap_im_qq: &patterns-components_cap_im_qq
|
||||
- "components/cap_im_qq/**/*"
|
||||
|
||||
.patterns-components_cap_im_tg: &patterns-components_cap_im_tg
|
||||
- "components/cap_im_tg/**/*"
|
||||
|
||||
.patterns-components_cap_im_wechat: &patterns-components_cap_im_wechat
|
||||
- "components/cap_im_wechat/**/*"
|
||||
|
||||
.patterns-components_cap_llm_inspect: &patterns-components_cap_llm_inspect
|
||||
- "components/cap_llm_inspect/**/*"
|
||||
|
||||
.patterns-components_cap_lua: &patterns-components_cap_lua
|
||||
- "components/cap_lua/**/*"
|
||||
|
||||
.patterns-components_cap_mcp_client: &patterns-components_cap_mcp_client
|
||||
- "components/cap_mcp_client/**/*"
|
||||
|
||||
.patterns-components_cap_mcp_server: &patterns-components_cap_mcp_server
|
||||
- "components/cap_mcp_server/**/*"
|
||||
|
||||
.patterns-components_cap_skill: &patterns-components_cap_skill
|
||||
- "components/cap_skill/**/*"
|
||||
|
||||
.patterns-components_cap_time: &patterns-components_cap_time
|
||||
- "components/cap_time/**/*"
|
||||
|
||||
.patterns-components_cap_web_search: &patterns-components_cap_web_search
|
||||
- "components/cap_web_search/**/*"
|
||||
|
||||
.patterns-components_claw_cap: &patterns-components_claw_cap
|
||||
- "components/claw_cap/**/*"
|
||||
|
||||
.patterns-components_claw_core: &patterns-components_claw_core
|
||||
- "components/claw_core/**/*"
|
||||
|
||||
.patterns-components_claw_event_router: &patterns-components_claw_event_router
|
||||
- "components/claw_event_router/**/*"
|
||||
|
||||
.patterns-components_claw_memory: &patterns-components_claw_memory
|
||||
- "components/claw_memory/**/*"
|
||||
|
||||
.patterns-components_claw_skill: &patterns-components_claw_skill
|
||||
- "components/claw_skill/**/*"
|
||||
.patterns-components_lua_modules: &patterns-components_lua_modules
|
||||
- "components/lua_modules/**/*"
|
||||
|
||||
# application folder, in the alphabetic order
|
||||
.patterns-application_basic_demo: &patterns-application_basic_demo
|
||||
- "application/basic_demo/**/*"
|
||||
|
||||
.patterns-yml: &patterns-yml
|
||||
- "**/*.yml"
|
||||
|
||||
.patterns-docs: &patterns-docs
|
||||
- "docs/**/*"
|
||||
|
||||
##############
|
||||
# if anchors #
|
||||
##############
|
||||
.if-protected: &if-protected
|
||||
if: '($CI_COMMIT_REF_NAME == "master" || $CI_COMMIT_BRANCH =~ /^release\/v/ || $CI_COMMIT_TAG =~ /^v\d+\.\d+(\.\d+)?($|-)/)'
|
||||
|
||||
.if-dev-push: &if-dev-push
|
||||
if: '$CI_COMMIT_REF_NAME != "master" && $CI_COMMIT_BRANCH !~ /^release\/v/ && $CI_COMMIT_TAG !~ /^v\d+\.\d+(\.\d+)?($|-)/ && ($CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "merge_request_event")'
|
||||
# Push to any protected ref
|
||||
.if-protected-push: &if-protected-push
|
||||
if: '$CI_COMMIT_REF_PROTECTED == "true" && $CI_PIPELINE_SOURCE == "push"'
|
||||
|
||||
# master push only
|
||||
.if-master-push: &if-master-push
|
||||
if: '$CI_COMMIT_REF_NAME == "master" && $CI_PIPELINE_SOURCE == "push"'
|
||||
|
||||
# Merge request pipeline (dev branches). Non-protected branch push pipelines are
|
||||
# disabled at workflow level (see .gitlab-ci.yml), so we only care about MR here.
|
||||
.if-mr: &if-mr
|
||||
if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
|
||||
|
||||
##################
|
||||
# Auto Generated #
|
||||
@@ -92,69 +52,51 @@
|
||||
.if-label-build: &if-label-build
|
||||
if: '$BOT_LABEL_BUILD || $CI_MERGE_REQUEST_LABELS =~ /^(?:[^,\n\r]+,)*build(?:,[^,\n\r]+)*$/i'
|
||||
|
||||
.if-label-target_test: &if-label-target_test
|
||||
if: '$BOT_LABEL_TARGET_TEST || $CI_MERGE_REQUEST_LABELS =~ /^(?:[^,\n\r]+,)*target_test(?:,[^,\n\r]+)*$/i'
|
||||
|
||||
.if-label-build_docs: &if-label-build_docs
|
||||
if: '$BOT_LABEL_BUILD_DOCS || $CI_MERGE_REQUEST_LABELS =~ /^(?:[^,\n\r]+,)*build_docs(?:,[^,\n\r]+)*$/i'
|
||||
|
||||
.if-label-pre_check: &if-label-pre_check
|
||||
if: '$BOT_LABEL_PRE_CHECK || $CI_MERGE_REQUEST_LABELS =~ /^(?:[^,\n\r]+,)*pre_check(?:,[^,\n\r]+)*$/i'
|
||||
|
||||
.if_label-deploy: &if-label-deploy
|
||||
if: '$BOT_LABEL_DEPLOY || $CI_MERGE_REQUEST_LABELS =~ /^(?:[^,\n\r]+,)*deploy(?:,[^,\n\r]+)*$/i'
|
||||
#########
|
||||
# Rules #
|
||||
#########
|
||||
|
||||
# rules for applications
|
||||
.rules:build:application_basic_demo:
|
||||
rules:
|
||||
- <<: *if-protected
|
||||
- <<: *if-protected-push
|
||||
- <<: *if-label-build
|
||||
- <<: *if-trigger-job
|
||||
- <<: *if-dev-push
|
||||
- <<: *if-mr
|
||||
changes: *patterns-build_system
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-components_cap_cli
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-components_cap_files
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-components_cap_im_attachment
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-components_cap_im_qq
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-components_cap_im_tg
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-components_cap_im_wechat
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-components_cap_llm_inspect
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-components_cap_lua
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-components_cap_mcp_client
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-components_cap_mcp_server
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-components_cap_skill
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-components_cap_time
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-components_cap_web_search
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-components_claw_cap
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-components_claw_core
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-components_claw_event_router
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-components_claw_memory
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-components_claw_skill
|
||||
- <<: *if-dev-push
|
||||
- <<: *if-mr
|
||||
changes: *patterns-components_capabilities
|
||||
- <<: *if-mr
|
||||
changes: *patterns-components_modules
|
||||
- <<: *if-mr
|
||||
changes: *patterns-components_lua_modules
|
||||
- <<: *if-mr
|
||||
changes: *patterns-application_basic_demo
|
||||
- <<: *if-mr
|
||||
changes: *patterns-docs
|
||||
- when: never
|
||||
|
||||
.rules:pre_check:docs:
|
||||
rules:
|
||||
- <<: *if-protected
|
||||
- <<: *if-protected-push
|
||||
- <<: *if-label-pre_check
|
||||
- <<: *if-trigger-job
|
||||
- <<: *if-dev-push
|
||||
- <<: *if-mr
|
||||
changes: *patterns-docs
|
||||
- when: never
|
||||
|
||||
.rules:build:doc:
|
||||
rules:
|
||||
- <<: *if-protected-push
|
||||
- <<: *if-label-build
|
||||
- <<: *if-trigger-job
|
||||
- <<: *if-mr
|
||||
changes: *patterns-docs
|
||||
- when: never
|
||||
|
||||
.rules:push:github:
|
||||
rules:
|
||||
- <<: *if-master-push
|
||||
- when: never
|
||||
|
||||
@@ -168,6 +168,16 @@ esp-claw/
|
||||
|
||||
If this project inspires or helps you, please consider giving it a star. ⭐⭐⭐⭐⭐
|
||||
|
||||
### Star History
|
||||
|
||||
<a href="https://www.star-history.com/?repos=espressif%2Fesp-claw&type=date&legend=top-left">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/chart?repos=espressif/esp-claw&type=date&theme=dark&legend=top-left" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/chart?repos=espressif/esp-claw&type=date&legend=top-left" />
|
||||
<img alt="Star History Chart" src="https://api.star-history.com/chart?repos=espressif/esp-claw&type=date&legend=top-left" />
|
||||
</picture>
|
||||
</a>
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
ESP-Claw is inspired by [OpenClaw](https://github.com/openclaw/openclaw).
|
||||
|
||||
@@ -168,6 +168,16 @@ esp-claw/
|
||||
|
||||
如果这个项目对您有所启发和帮助,欢迎点亮一颗星!⭐⭐⭐⭐⭐
|
||||
|
||||
### Star History
|
||||
|
||||
<a href="https://www.star-history.com/?repos=espressif%2Fesp-claw&type=date&legend=top-left">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/chart?repos=espressif/esp-claw&type=date&theme=dark&legend=top-left" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/chart?repos=espressif/esp-claw&type=date&legend=top-left" />
|
||||
<img alt="Star History Chart" src="https://api.star-history.com/chart?repos=espressif/esp-claw&type=date&legend=top-left" />
|
||||
</picture>
|
||||
</a>
|
||||
|
||||
## 致谢
|
||||
|
||||
灵感来自 [OpenClaw](https://github.com/openclaw/openclaw)。
|
||||
|
||||
+2
-1
@@ -8,7 +8,8 @@
|
||||
"build": "astro build",
|
||||
"preview": "astro preview",
|
||||
"astro": "astro",
|
||||
"check:doc-lines": "node ./tools/check-doc-line-alignment.ts"
|
||||
"check:doc-lines": "node ./tools/check-doc-line-alignment.ts",
|
||||
"generate-firmware-json": "node ./tools/generate-firmware-json.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/check": "^0.9.8",
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
/ /zh-cn/ 302
|
||||
/esp-claw/* /:splat 302
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -25,10 +25,13 @@ import { Steps, Aside, Badge } from '@astrojs/starlight/components';
|
||||
pip install esp-bmgr-assist
|
||||
```
|
||||
|
||||
<Aside type="tip">
|
||||
ESP-Claw uses ESP Board Manager to support multiple development boards.
|
||||
<Aside title="Need to adapt a new development board?" type="tip">
|
||||
ESP-Claw uses ESP Board Manager to support multiple development boards.
|
||||
|
||||
To add other boards, see the [ESP Board Manager component](https://components.espressif.com/components/espressif/esp_board_manager/).
|
||||
To add other boards, see the [ESP Board Manager component](https://github.com/espressif/esp-gmf/blob/main/packages/esp_board_manager/docs/how_to_customize_board.md),
|
||||
and put the board adaptation files in [`application/basic_demo/boards`](https://github.com/espressif/esp-claw/tree/master/application/basic_demo/boards).
|
||||
|
||||
Welcome to submit the board adaptation code to the ESP-Claw repository via Pull Request.
|
||||
</Aside>
|
||||
|
||||
2. **Get the ESP-Claw source**
|
||||
|
||||
@@ -101,10 +101,12 @@ If you use the USB camera sample from Espressif, you only need to buy a micropho
|
||||
In addition to the built-in WS2812 LED on ESP32-S3-DevKitC-1, you can connect a WS2812 strip/ring to extend lighting effects.
|
||||
|
||||
Due to power limits, do not connect an overly long WS2812 strip/ring.
|
||||
You can choose the WS2812 ring with the same model as the [demo image](https://detail.tmall.com/item.htm?id=994762490273&skuId=6139364670619).
|
||||
|
||||
### Servo
|
||||
|
||||
ESP-Claw supports servos for mechanical motion.
|
||||
You can choose a common servo, such as [this one](https://item.taobao.com/item.htm?id=1016474722460).
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -18,3 +18,12 @@ Coming soon:
|
||||
## Supported development boards
|
||||
|
||||
See [GitHub repository](https://github.com/espressif/esp-claw/tree/master/application/basic_demo/boards).
|
||||
|
||||
<Aside title="Need to adapt a new development board?" type="tip">
|
||||
ESP-Claw uses ESP Board Manager to support multiple development boards.
|
||||
|
||||
To add other boards, see the [ESP Board Manager component](https://github.com/espressif/esp-gmf/blob/main/packages/esp_board_manager/docs/how_to_customize_board.md),
|
||||
and put the board adaptation files in [`application/basic_demo/boards`](https://github.com/espressif/esp-claw/tree/master/application/basic_demo/boards).
|
||||
|
||||
Welcome to submit the board adaptation code to the ESP-Claw repository via Pull Request.
|
||||
</Aside>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user