22 changed files with 102 additions and 91 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
#! /bin/sh #!/bin/sh
exec > /dev/null 2>&1 exec > /dev/null 2>&1
+1 -1
View File
@@ -1,4 +1,4 @@
#! /bin/sh #!/bin/sh
cat << 'EOF' cat << 'EOF'
+1 -1
View File
@@ -1,4 +1,4 @@
#! /bin/sh #!/bin/sh
cat << 'EOF' cat << 'EOF'
+4
View File
@@ -160,6 +160,10 @@ PS:如果还是不行,建议更换其他更易识别的唤醒词。
由于 ASR 相关模型文件体积较大,并未直接提交在 git 仓库中,你可以在 release 中下载 [VAD + KWS 相关模型](https://github.com/idootop/open-xiaoai/releases/tag/vad-kws-models),然后解压到 `xiaozhi/models` 路径下即可。 由于 ASR 相关模型文件体积较大,并未直接提交在 git 仓库中,你可以在 release 中下载 [VAD + KWS 相关模型](https://github.com/idootop/open-xiaoai/releases/tag/vad-kws-models),然后解压到 `xiaozhi/models` 路径下即可。
## 相关项目
- [oxa-server](https://github.com/pu-007/oxa-server): 提供了更强大易用的 config.py 的配置方式
## 鸣谢 ## 鸣谢
该演示使用的 Python 版小智 AI 客户端基于 [py-xiaozhi](https://github.com/Huang-junsen/py-xiaozhi) 项目,特此鸣谢。 该演示使用的 Python 版小智 AI 客户端基于 [py-xiaozhi](https://github.com/Huang-junsen/py-xiaozhi) 项目,特此鸣谢。
+3 -3
View File
@@ -65,8 +65,8 @@ APP_CONFIG = {
"xiaozhi": { "xiaozhi": {
"OTA_URL": "https://api.tenclass.net/xiaozhi/ota/", "OTA_URL": "https://api.tenclass.net/xiaozhi/ota/",
"WEBSOCKET_URL": "wss://api.tenclass.net/xiaozhi/v1/", "WEBSOCKET_URL": "wss://api.tenclass.net/xiaozhi/v1/",
"WEBSOCKET_ACCESS_TOKEN": "(可选)一般用不到这个值", "WEBSOCKET_ACCESS_TOKEN": "", #(可选)一般用不到这个值
"DEVICE_ID": "(可选)默认自动生成", "DEVICE_ID": "", #(可选)默认自动生成
"VERIFICATION_CODE": "首次登陆时,验证码会在这里更新", "VERIFICATION_CODE": "", # 首次登陆时,验证码会在这里更新
}, },
} }
@@ -201,7 +201,7 @@ class WebsocketProtocol(Protocol):
if self.websocket and get_xiaozhi().device_state == DeviceState.IDLE: if self.websocket and get_xiaozhi().device_state == DeviceState.IDLE:
try: try:
await self.send_text( await self.send_text(
json.dumps({"session_id": "", "type": "abort"}) json.dumps({"session_id": "", "type": "ping"})
) )
except Exception: except Exception:
# 发送心跳失败,重新连接 # 发送心跳失败,重新连接
+9 -4
View File
@@ -1,9 +1,14 @@
# 你的小米账号/密码 #你的小米账号/密码
MI_USER=23333333 MI_USER=23333333
MI_PASS=xxxxxxxxx MI_PASS=xxxxxxxxx
#你的小爱音箱名称/DID
# 你的小爱音箱名称/DID
MI_DID=小爱音箱Pro MI_DID=小爱音箱Pro
# 你的 SSH 登录密码默认为 open-xiaoai #你的 SSH 登录密码默认为 open-xiaoai
SSH_PASSWORD=open-xiaoai SSH_PASSWORD=open-xiaoai
#账号登录异常时,请取消下面的注释,使用 MI_TOKEN 登录
#MI_TOKEN=你的 passToken 获取教程 👉 https://github.com/idootop/migpt-next/issues/4
# 获取设备异常时,请取消下面的注释,查看设备列表详情
#MI_DEBUG=true
+1
View File
@@ -6,6 +6,7 @@ ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime \ RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime \
&& echo $TZ > /etc/timezone \ && echo $TZ > /etc/timezone \
&& apk add --no-cache \ && apk add --no-cache \
bash \
file \ file \
patch \ patch \
python3 \ python3 \
+26 -13
View File
@@ -4,6 +4,7 @@
> 刷机有风险,操作需谨慎。请勿下载使用不明来历的固件! > 刷机有风险,操作需谨慎。请勿下载使用不明来历的固件!
小爱音箱 Pro 补丁固件制作流程: 小爱音箱 Pro 补丁固件制作流程:
- 固件提取(登录小米账号获取 OTA 链接) - 固件提取(登录小米账号获取 OTA 链接)
- 开启固化 SSH(支持自定义登录密码) - 开启固化 SSH(支持自定义登录密码)
- 禁用系统自动更新(系统更新后需要重新刷机打补丁) - 禁用系统自动更新(系统更新后需要重新刷机打补丁)
@@ -12,31 +13,31 @@
## 下载固件 ## 下载固件
你可以直接在 [Github Releases](https://github.com/idootop/open-xiaoai/releases) 页面下载打包好的固件: 你可以直接在 [Github Releases](https://github.com/idootop/open-xiaoai/releases) 页面下载打包好的固件:
- [Xiaomi 智能音箱 Pro v1.56.19](https://github.com/idootop/open-xiaoai/releases/tag/OH2P_1.56.19)
- [小爱音箱 Pro v1.88.206](https://github.com/idootop/open-xiaoai/releases/tag/LX06_1.88.206) - [Xiaomi 智能音箱 Pro v1.56.31](https://github.com/idootop/open-xiaoai/releases/tag/OH2P_1.56.31)
- [小爱音箱 Pro v1.88.221](https://github.com/idootop/open-xiaoai/releases/tag/LX06_1.88.221)
> [!TIP] > [!TIP]
> 里面有两个文件,下载 `patched` 那个: > 里面有两个文件,下载 `patched` 那个:
>
> - `xxx_patched.squashfs` 打补丁后的固件 > - `xxx_patched.squashfs` 打补丁后的固件
> - `xxx.squashfs` 原版固件(可用来刷回原系统) > - `xxx.squashfs` 原版固件(可用来刷回原系统)
> [!NOTE] > [!NOTE]
> 默认 SSH 登录密码为 `open-xiaoai`,如需修改请自行制作固件。 > 默认 SSH 登录密码为 `open-xiaoai`,如需修改请自行制作固件。
> [!IMPORTANT] > [!IMPORTANT]
> 请下载和你当前小爱音箱版本一致的固件,跨版本刷机可能会出现未知错误,导致设备变砖。 > 请下载和你当前小爱音箱版本一致的固件,跨版本刷机可能会出现未知错误,导致设备变砖。
> 如果上面没有你的版本,请升级设备固件到最新版本,或者按照下面的教程自行制作固件。 > 如果上面没有你的版本,请升级设备固件到最新版本,或者按照下面的教程自行制作固件。
> [!CAUTION] > [!CAUTION]
> 当前支持的最新固件版本为: > 当前支持的最新固件版本为:
> - Xiaomi 智能音箱 Pro 👉 [v1.56.19](https://github.com/idootop/open-xiaoai/releases/tag/OH2P_1.56.19) >
> - 小爱音箱 Pro 👉 [v1.88.206](https://github.com/idootop/open-xiaoai/releases/tag/LX06_1.88.206) > - Xiaomi 智能音箱 Pro 👉 [v1.56.31](https://github.com/idootop/open-xiaoai/releases/tag/OH2P_1.56.31)
> - 小爱音箱 Pro 👉 [v1.88.221](https://github.com/idootop/open-xiaoai/releases/tag/LX06_1.88.221)
> >
> 更新版本的固件可能存在变化,导致刷机失败,设备变砖,请自行评估风险。 > 更新版本的固件可能存在变化,导致刷机失败,设备变砖,请自行评估风险。
## 制作固件 ## 制作固件
你可以按照下面的 2 种方法,制作自定义固件。 你可以按照下面的 2 种方法,制作自定义固件。
@@ -66,13 +67,25 @@ SSH_PASSWORD=open-xiaoai
- Dockerhttps://www.docker.com/get-started/ - Dockerhttps://www.docker.com/get-started/
> [!NOTE] > [!NOTE]
> Windows 系统推荐使用 [Git Bash](https://git-scm.com/downloads) 终端运行。 > Windows 系统请在 [Git Bash](https://git-scm.com/downloads) 终端运行以下命令
>
> CMD 和 PowerShell 终端需要调整下面命令中文件(夹)的实际路径。 > [!TIP]
> 如果你是 Apple Silicon 芯片,请先在 Docker Desktop - Settings - General - Virtual Machine Options 中打开 Apple Virtual framework 选项,然后开启 `Use Rosetta for x86_64/amd64 emulation on Apple Silicon`
```shell ```shell
# 克隆代码
git clone https://github.com/idootop/open-xiaoai.git
# 进入当前项目根目录
cd packages/client-patch
# 使用 Docker 进行构建 # 使用 Docker 进行构建
docker run -it --rm --env-file $(pwd)/.env -v $(pwd)/assets:/app/assets -v $(pwd)/patches:/app/patches idootop/open-xiaoai:latest docker run -it --rm \
--platform linux/amd64 \
--env-file $(pwd)/.env \
-v $(pwd)/assets:/app/assets \
-v $(pwd)/patches:/app/patches \
idootop/open-xiaoai:latest
# ✅ 打包完成,固件文件已复制到 assets 目录... # ✅ 打包完成,固件文件已复制到 assets 目录...
# /app/assets/mico_all_92db90ed6_1.88.197/root-patched.squashfs # /app/assets/mico_all_92db90ed6_1.88.197/root-patched.squashfs
@@ -113,7 +126,7 @@ npm run build
示例: 示例:
```bash ```bash
#! /bin/sh #!/bin/sh
/usr/sbin/tts_play.sh '初始化成功' /usr/sbin/tts_play.sh '初始化成功'
``` ```
+20 -20
View File
@@ -8,11 +8,11 @@
"name": "open-xiaoai-patch", "name": "open-xiaoai-patch",
"version": "1.0.0", "version": "1.0.0",
"dependencies": { "dependencies": {
"@mi-gpt/miot": "^1.0.0" "@mi-gpt/miot": "^1.2.1"
}, },
"devDependencies": { "devDependencies": {
"@mi-gpt/config": "1.0.0", "@mi-gpt/config": "1.1.0",
"@types/node": "^22.13.11", "@types/node": "^24.2.1",
"tsx": "^4.19.3", "tsx": "^4.19.3",
"typescript": "^5.8.2" "typescript": "^5.8.2"
} }
@@ -443,9 +443,9 @@
} }
}, },
"node_modules/@mi-gpt/config": { "node_modules/@mi-gpt/config": {
"version": "1.0.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/@mi-gpt/config/-/config-1.0.0.tgz", "resolved": "https://registry.npmjs.org/@mi-gpt/config/-/config-1.1.0.tgz",
"integrity": "sha512-oo/roYiRcGiHsZESjukwPTsRFqddShTJ8gkccR5ZMYn8SySj07A0nCsEsLEfB9mLkvNY8D6PCO1NxbRDDRBBlA==", "integrity": "sha512-o24iFINsoDuvInnMpfBQ4zCuTObbdodjXyizXmxl3yyYOMjmIAXizO/1UZ9/dv3UVTov3sjL09aCGuBeIVhvtA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@@ -453,12 +453,12 @@
} }
}, },
"node_modules/@mi-gpt/miot": { "node_modules/@mi-gpt/miot": {
"version": "1.0.0", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/@mi-gpt/miot/-/miot-1.0.0.tgz", "resolved": "https://registry.npmjs.org/@mi-gpt/miot/-/miot-1.2.1.tgz",
"integrity": "sha512-smWhddHzK1du3/LW2FifBrIIyeZNx/RvTSe0Zi4v3lYZwK8NeEwomg1jBjktQCCV4Fh8OuqNbCdNbmiVXmr5kw==", "integrity": "sha512-DAFNUsLPepXSqJk/b+zfct8NCQHZzcl7f1t4X2WPKzxmDNagkawYlb96uPbk4syvn+DSg6vqle0Wm+gjmJ4kUA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@mi-gpt/utils": "1.0.0", "@mi-gpt/utils": "1.1.1",
"axios": "^1.8.4", "axios": "^1.8.4",
"pako": "^2.1.0" "pako": "^2.1.0"
}, },
@@ -467,22 +467,22 @@
} }
}, },
"node_modules/@mi-gpt/utils": { "node_modules/@mi-gpt/utils": {
"version": "1.0.0", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/@mi-gpt/utils/-/utils-1.0.0.tgz", "resolved": "https://registry.npmjs.org/@mi-gpt/utils/-/utils-1.1.1.tgz",
"integrity": "sha512-hAU/uYPNiNJgXWkQrVqRLe/9Uz8AgtoiNwcbbwQs8iXJcyq3NjcSHkkwUseJAnaQFE9iv/kvHZZsx3r2HhlKjw==", "integrity": "sha512-FiGHV2RDBRGE/Xb9Q5H757t3ZqOpo6gL+44VXiRxQb3fQiapOpn038RAWErHJYZajYzkxP2jl8Wggsb+wp77Zg==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=16" "node": ">=16"
} }
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "22.14.1", "version": "24.2.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.14.1.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-24.2.1.tgz",
"integrity": "sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw==", "integrity": "sha512-DRh5K+ka5eJic8CjH7td8QpYEV6Zo10gfRkjHCO3weqZHWDtAaSTFtl4+VMqOJ4N5jcuhZ9/l+yy8rVgw7BQeQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"undici-types": "~6.21.0" "undici-types": "~7.10.0"
} }
}, },
"node_modules/asynckit": { "node_modules/asynckit": {
@@ -883,9 +883,9 @@
} }
}, },
"node_modules/undici-types": { "node_modules/undici-types": {
"version": "6.21.0", "version": "7.10.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz",
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==",
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
} }
+7 -7
View File
@@ -5,17 +5,17 @@
"type": "module", "type": "module",
"scripts": { "scripts": {
"ota": "tsx --env-file=.env src/ota.ts", "ota": "tsx --env-file=.env src/ota.ts",
"extract": "sh src/extract.sh", "extract": "bash src/extract.sh",
"patch": "sh src/patch.sh", "patch": "bash src/patch.sh",
"squashfs": "sh src/squashfs.sh", "squashfs": "bash src/squashfs.sh",
"build": "sh src/build.sh" "build": "bash src/build.sh"
}, },
"dependencies": { "dependencies": {
"@mi-gpt/miot": "^1.0.0" "@mi-gpt/miot": "^1.2.1"
}, },
"devDependencies": { "devDependencies": {
"@mi-gpt/config": "1.0.0", "@mi-gpt/config": "1.1.0",
"@types/node": "^22.13.11", "@types/node": "^24.2.1",
"tsx": "^4.19.3", "tsx": "^4.19.3",
"typescript": "^5.8.2" "typescript": "^5.8.2"
} }
@@ -1,4 +1,4 @@
#!/bin/bash #!/usr/bin/env bash
set -e set -e
+1 -1
View File
@@ -1,4 +1,4 @@
#!/bin/bash #!/usr/bin/env bash
set -e set -e
+1 -1
View File
@@ -1,4 +1,4 @@
#!/bin/bash #!/usr/bin/env bash
set -e set -e
+6 -24
View File
@@ -13,36 +13,18 @@ const kSupportedDevices = [
// 获取 OTA 信息 // 获取 OTA 信息
async function getOTA(channel: "release" | "current" | "stable" = "release") { async function getOTA(channel: "release" | "current" | "stable" = "release") {
const MiNA = await getMiNA({ const MiNA = await getMiNA({
did: process.env.MI_DID!,
userId: process.env.MI_USER!, userId: process.env.MI_USER!,
password: process.env.MI_PASS!, password: process.env.MI_PASS!,
passToken: process.env.MI_TOKEN,
debug: !!process.env.MI_DEBUG,
}); });
if (!MiNA) { if (!MiNA) {
console.log(`❌ 登录失败,请检查小米账号密码是否正确:`);
console.log(`当前账号:${process.env.MI_USER}`);
console.log(`当前密码:${process.env.MI_PASS}`);
return; return;
} }
const devices = await MiNA.getDevices(); const devices = await MiNA.getDevices();
const speaker = devices?.find( const speaker = MiNA.account.device as any;
(e: any) =>
e.name === process.env.MI_DID || e.miotDID === process.env.MI_DID
);
if (!speaker) {
console.log(`❌ 找不到设备: ${process.env.MI_DID}`);
console.log(`可用设备列表:`);
console.log(
JSON.stringify(
devices.map((e: any) => ({
name: e.name,
did: e.miotDID,
})),
null,
4
)
);
return;
}
if (!kSupportedDevices.includes(speaker.hardware)) { if (!kSupportedDevices.includes(speaker.hardware)) {
console.log( console.log(
@@ -65,7 +47,7 @@ async function getOTA(channel: "release" | "current" | "stable" = "release") {
} }
const model = speaker.hardware; const model = speaker.hardware;
const time = new Date().getTime(); const time = Date.now();
const sn = process.env.DEBUG_VERSION ? "" : speaker.serialNumber; const sn = process.env.DEBUG_VERSION ? "" : speaker.serialNumber;
const version = process.env.DEBUG_VERSION ?? speaker.romVersion; const version = process.env.DEBUG_VERSION ?? speaker.romVersion;
const otaInfo = `channel=${channel}&filterID=${sn}&locale=zh_CN&model=${model}&time=${time}&version=${version}&8007236f-a2d6-4847-ac83-c49395ad6d65`; const otaInfo = `channel=${channel}&filterID=${sn}&locale=zh_CN&model=${model}&time=${time}&version=${version}&8007236f-a2d6-4847-ac83-c49395ad6d65`;
@@ -88,7 +70,7 @@ async function main() {
} else { } else {
ota = await getOTA(); ota = await getOTA();
} }
if (!ota.url) { if (!ota?.url) {
console.log(`❌ 获取设备信息失败`); console.log(`❌ 获取设备信息失败`);
process.exit(1); process.exit(1);
} }
+2 -2
View File
@@ -1,4 +1,4 @@
#!/bin/bash #!/usr/bin/env bash
set -e set -e
@@ -28,7 +28,7 @@ apply_patches() {
# 清理临时文件 # 清理临时文件
rm "$temp_patch" rm "$temp_patch"
elif [[ "$file" == *.sh ]]; then elif [[ "$file" == *.sh ]]; then
sh "$file" bash "$file"
fi fi
fi fi
done done
+11 -5
View File
@@ -1,4 +1,4 @@
#!/bin/bash #!/usr/bin/env bash
set -e set -e
@@ -40,14 +40,20 @@ elif [ "$MODEL" = "LX06" ]; then
IMAGE_MAX_SIZE=$((0x02800000)) IMAGE_MAX_SIZE=$((0x02800000))
fi fi
SIZE=`stat -L -c %s $FIRMWARE/root-patched.squashfs` SIZE=$(stat -L -c %s "$FIRMWARE/root-patched.squashfs")
echo "📊 当前固件大小: $SIZE 字节" SIZE_MB=$((SIZE / 1024 / 1024))
IMAGE_MAX_SIZE_MB=$((IMAGE_MAX_SIZE / 1024 / 1024))
echo "📊 当前固件大小: $SIZE 字节 ($SIZE_MB MB)"
if [ "$SIZE" -ge "$IMAGE_MAX_SIZE" ]; then if [ "$SIZE" -ge "$IMAGE_MAX_SIZE" ]; then
echo "❌ 固件大小超过允许的最大值:$IMAGE_MAX_SIZE 字节" echo "❌ 固件大小超过允许的最大值:$IMAGE_MAX_SIZE 字节 ($IMAGE_MAX_SIZE_MB MB)"
exit 1 exit 1
fi fi
echo "✅ 固件大小检查通过,剩余空间: $((IMAGE_MAX_SIZE - SIZE)) 字节" REMAINING_BYTES=$((IMAGE_MAX_SIZE - SIZE))
REMAINING_MB=$((REMAINING_BYTES / 1024 / 1024))
echo "✅ 固件大小检查通过,剩余可用空间: $REMAINING_BYTES 字节 ($REMAINING_MB MB)"
cp -rf $FIRMWARE $BASE_DIR/assets/$FIRMWARE cp -rf $FIRMWARE $BASE_DIR/assets/$FIRMWARE
+1 -1
View File
@@ -59,7 +59,7 @@ cross build --release --target armv7-unknown-linux-gnueabihf
``` ```
> [!TIP] > [!TIP]
> 如果你是 Apple silicon 芯片,为了能够正常使用 cross 交叉编译镜像,请先在 Docker Desktop - Settings - General - Virtual Machine Options 中打开 Apple Virtual framework 选项,然后开启 `Use Rosetta for x86_64/amd64 emulation on Apple Silicon` > 如果你是 Apple Silicon 芯片,为了能够正常使用 cross 交叉编译镜像,请先在 Docker Desktop - Settings - General - Virtual Machine Options 中打开 Apple Virtual framework 选项,然后开启 `Use Rosetta for x86_64/amd64 emulation on Apple Silicon`
编译成功后,将构建好的补丁程序 `client` 复制到小爱音箱上 编译成功后,将构建好的补丁程序 `client` 复制到小爱音箱上
+1 -1
View File
@@ -1,4 +1,4 @@
#! /bin/sh #!/bin/sh
exec > /dev/null 2>&1 exec > /dev/null 2>&1
+1 -1
View File
@@ -1,4 +1,4 @@
#! /bin/sh #!/bin/sh
cat << 'EOF' cat << 'EOF'
+2 -2
View File
@@ -44,8 +44,8 @@ chmod +x ./flash
# 执行命令后拔掉小爱音箱的电源线,重新插上电源,等待设备连接 # 执行命令后拔掉小爱音箱的电源线,重新插上电源,等待设备连接
./flash connect ./flash connect
# 第 2 步:设置启动延时(5 秒) # 第 2 步:设置启动延时(15 秒)
./flash delay 5 ./flash delay 15
# 第 3 步:切换启动分区 # 第 3 步:切换启动分区
./flash switch boot0 ./flash switch boot0
+1 -1
View File
@@ -1,4 +1,4 @@
#!/bin/bash #!/usr/bin/env bash
RED='\033[0;31m' RED='\033[0;31m'