Shelly 设备的脚本功能(Shelly Script)让用户可以在设备本地运行基于 mJS 的小型脚本,实现设备之间的联动控制。不过一旦在设备上开启了 HTTP 身份验证,直接调用接口就会收到 401 未授权错误,很多用户在这一步卡住。本文将系统地讲解如何在 Shelly 脚本中携带身份验证信息去控制其他 Shelly 设备,包括基础认证的配置、脚本写法以及常见问题的排查。

一、为什么需要在脚本中处理身份验证
Shelly 设备固件(Gen2 及以上版本)默认在局域网内开放 HTTP API,任何能访问该网段的设备都可以直接调用 /rpc 接口控制继电器、读取传感器数据。这对家庭网络来说风险不小:一旦路由器或某个智能设备被攻破,攻击者就能横向控制所有 Shelly 设备。
因此在安全性要求较高的场景中,建议在设备的 Web 界面中进入 Settings(设置)页面,找到 Authentication(身份验证)选项并启用,同时设置用户名和密码。启用后,无论是浏览器访问还是脚本调用,都必须提供正确的凭据,否则接口会返回 401 Unauthorized。
问题随之而来:脚本通常运行在其中一台 Shelly 设备上,目标是控制另一台开启了认证的设备,此时请求必须带上凭据才能通过校验。Shelly 脚本引擎提供了 Fetch 模块和 Shelly.call 两种途径,都可以携带认证信息。
二、在 Shelly 脚本中使用 HTTP Basic Authentication
HTTP 基础认证是最直接的方式。客户端在请求头中添加 Authorization 字段,值为 Basic 加上「用户名:密码」经过 Base64 编码后的字符串。Shelly 的 mJS 环境提供了 btoa 函数来完成 Base64 编码,无需手动计算。
下面是一段完整的示例脚本,运行在设备 A 上,目标是控制设备 B(IP 为 192.168.1.50,已开启认证):
// 目标设备信息
let host = "192.168.1.50";
let username = "admin";
let password = "your_password_here";
// 生成 Basic 认证头
let auth = "Basic " + btoa(username + ":" + password);
// 发起带认证的 RPC 请求,切换 0 号继电器
Fetch.post(
"http://" + host + "/rpc/Switch.Toggle",
{
headers: { "Authorization": auth },
body: JSON.stringify({ id: 0 })
},
function (resp, error_code, error_msg) {
if (error_code !== 0) {
print("请求失败:", error_msg);
return;
}
let body = JSON.parse(resp.body());
print("执行成功,当前状态:", JSON.stringify(body));
}
);
这段脚本的关键点有三个:一是用 btoa 拼装认证头,二是通过 Fetch.post 的 headers 参数传递该头,三是在回调中解析响应体判断执行结果。需要注意的是,密码中如果包含非 ASCII 字符,编码可能出现问题,建议密码只使用字母和数字的组合。
此外,基础认证的凭据是可逆编码而不是加密,配合 HTTPS 使用才更安全。局域网内 Shelly 设备默认走 HTTP,若安全要求较高,可以将设备接入 Shelly Cloud 或通过反向代理套一层 TLS。
三、使用 Token(API Key)方式的替代方案
较新的 Shelly 固件还支持基于 Token 的鉴权方式。用户可以在目标设备的 Web 界面中生成 API Token,之后脚本只需在请求头中携带 Authorization: Bearer <token> 即可,无需再暴露用户名和密码。
Token 方式的优势在于权限可控、可随时吊销。比如某个 Token 只用于客厅设备的联动,泄露后直接在设备上删除该 Token 就能切断风险,不必修改主密码。示例写法如下:
let host = "192.168.1.50";
let token = "your_api_token_here";
Fetch.post(
"http://" + host + "/rpc/Switch.Set",
{
headers: {
"Authorization": "Bearer " + token,
"Content-Type": "application/json"
},
body: JSON.stringify({ id: 0, on: true })
},
function (resp, error_code, error_msg) {
if (error_code !== 0) {
print("错误:", error_msg);
} else {
print("继电器已开启");
}
}
);
如果希望每次定时轮询目标设备状态,可以把 Fetch.post 放进 Timer.set 的回调中,形成周期性的状态同步逻辑。Token 建议定期轮换,并且不要把包含 Token 的脚本随意导出分享。
四、常见报错与排查思路
实际使用中最常见的报错是 401。遇到时先确认三件事:目标设备的认证开关是否确实开启、用户名密码是否拼写正确、认证头的格式是否为 Basic 或 Bearer 加一个空格再接凭据。少了这个空格是新手最容易犯的错误。
其次是超时或连接拒绝,这通常是 IP 地址写错、设备掉线或者固件版本过旧不支持 Fetch 模块导致的。建议先把脚本简化为只请求 /rpc/Shelly.GetDeviceInfo 验证连通性,再逐步加入控制逻辑。另外,mJS 与标准 JavaScript 有差异,JSON.parse 返回的对象方法有限,调试时多用 print 输出中间结果比猜测有效得多。
最后提醒一点:脚本中的凭据是明文存储在设备上的,任何能登录该设备脚本页面的人都能看到。因此控制端设备本身也应开启认证并使用强密码,形成完整的防护链条。只要按以上方式正确携带凭据,Shelly 设备之间的联动控制既灵活又安全。