一、方案定位与原生能力短板

本模组基于 Sonoscli 命令行工具,打造适配 OpenClaw 生态的声场中控终端,面向 Sonos 全屋音响设备实现本地化集中管控,全程依托本地网络与终端指令交互,无需第三方云端平台介入。原生 Sonoscli 仅提供基础单设备启停、音量调节、曲目播放能力,功能零散且缺乏集群管理逻辑,存在多音箱分组管控缺失、播放队列管理简陋、定时任务空白、运行状态无可视化、操作日志未留存、无法联动生态内其他模组等问题。

经过深度重构后,将其升级为全屋音频设备一体化管控单元,覆盖设备发现、分组管理、播放控制、音效调节、队列编排、定时启停、日志回溯等全场景能力,同时打通生态协同链路,可与语音解析、文档中枢、集群运维等模块联动,适配居家影音、背景声播放、定时语音播报、多房间声场同步等使用场景。

二、定制化核心能力(原创独有特性)

  1. 局域网设备全域探测:自动扫描内网在线 Sonos 设备,一键汇总设备名称、IP、房间归属、运行状态
  2. 多设备分组统筹:按空间区域划分音响群组,支持单设备操控与整组同步联动,实现全屋声场协同
  3. 全维度播放管控:支持曲目播放、暂停、切歌、进度跳转、播放模式切换,兼容本地音频与网络音源
  4. 精细化音效调校:独立调节主音量、高低音、平衡声道,预设休闲、影院、人声等多套音效方案
  5. 播放队列运维:新增、清空、置顶、移除队列曲目,自定义播放顺序,支持清单循环播放
  6. 定时任务编排:设置设备定时开机、关机、定点播放曲目,满足作息提醒、定时播报需求
  7. 操作日志全留存:自动记录每一次操控行为、设备反馈信息,支持关键词检索与异常排查
  8. 状态实时可视化:在线状态、当前曲目、播放时长、音量参数、所属分组一目了然
  9. 生态协同互通:预留接口对接语音萃取、MCP 集群运维、自主迭代模组,构建「语音指令→设备执行→状态监控」工作流
  10. 自然语义交互:使用中文场景化指令完成所有操作,脱离复杂命令行语法,降低操控门槛

三、前置运行环境部署

1. 基础工具安装

模组依赖 Sonoscli 原生命令行工具与 Node.js 运行环境,先完成基础组件部署:

  • 环境要求:Node.js 16.0 及以上稳定版本

Sonoscli 全局安装指令

bash

运行

npm install -g sonoscli

2. 环境校验

安装完成后执行校验命令,确认工具可正常调用:

bash

运行

sonoscli --version

终端输出版本号即代表基础环境就绪,同时保证操控终端与 Sonos 音响处于同一局域网

四、技能目录规划

在 OpenClaw 自定义技能目录下创建独立隔离文件夹,模组配置、日志、任务数据独立存储,主程序升级、重装不会丢失分组与定时规则:

  • macOS / Linux:~/.openclaw/skills/sonos-audio-controller
  • Windows:C:\Users\你的用户名\.openclaw\skills\sonos-audio-controller

目录内包含三份核心文件,各司其职:

  1. runtime.profile:模组运行参数、分组规则、日志策略、定时任务配置
  2. skill.register:技能注册信息、触发指令、系统权限声明
  3. control.core:核心业务逻辑,整合设备扫描、指令转发、日志记录、异常捕获全流程

五、核心文件完整源码(直接部署使用)

1. skill.register 技能注册配置文件

用于 OpenClaw 识别模组身份、监听交互指令、分配系统调用权限:

json

{
  "name": "sonos-audio-controller",
  "version": "4.4.0-audio-hub",
  "author": "Eco Local Dev",
  "description": "声场中控终端,基于Sonoscli实现全屋音响设备探测、分组管控、播放调节、定时任务、日志回溯,支持局域网离线操控与全生态联动",
  "trigger": [
    "扫描音响设备",
    "查看设备运行状态",
    "播放音频曲目",
    "暂停当前播放",
    "切换播放曲目",
    "调节设备音量",
    "设置音效方案",
    "管理播放队列",
    "配置定时任务",
    "查阅操作日志"
  ],
  "permissions": [
    "system:shell-call",
    "network:lan-scan",
    "file:log-write",
    "file:log-read",
    "config:param-read",
    "config:param-modify"
  ],
  "entry": "control.core.js",
  "disabled": false
}

2. runtime.profile 运行参数配置文件

统一管理日志存储、分组信息、默认音效、日志保留时长、扫描间隔,可手动编辑修改:

json

{
  "log_save_path": "~/Sonos_Operate_Log",
  "log_keep_days": 15,
  "default_volume": 50,
  "default_eq_mode": "normal",
  "lan_scan_interval": 30,
  "device_group": {
    "living": "客厅主音响",
    "bedroom": "卧室音响",
    "study": "书房音响"
  },
  "timed_task_list": []
}

3. control.core.js 核心逻辑主程序

实现目录初始化、配置加载、设备扫描、指令分发、日志写入、任务执行、异常捕获全流程:

javascript

运行

const fs = require('fs').promises;
const path = require('path');
const os = require('os');
const { exec } = require('child_process');

// 全局路径与配置定义
const PROFILE_PATH = path.join(__dirname, 'runtime.profile');
let runProfile = {};

// 初始化日志与工作目录
async function initWorkspace() {
  const dirArr = [
    os.homedir() + "/Sonos_Operate_Log",
    path.join(__dirname, "task_cache")
  ];
  for (const dir of dirArr) {
    await fs.mkdir(dir, { recursive: true });
  }
}

// 加载运行配置文件
async function loadProfile() {
  const fileContent = await fs.readFile(PROFILE_PATH, 'utf8');
  runProfile = JSON.parse(fileContent);
}

// 写入操作日志
async function writeOperateLog(content) {
  const logFile = path.join(os.homedir(), runProfile.log_save_path, `${new Date().toLocaleDateString()}.log`);
  const logLine = `[${new Date().toLocaleTimeString()}] ${content}\n`;
  await fs.appendFile(logFile, logLine, 'utf8');
}

// 执行Sonoscli系统指令
function runAudioCommand(cmd) {
  return new Promise((resolve, reject) => {
    exec(cmd, (err, stdout, stderr) => {
      if (err) {
        reject({ error: err, detail: stderr });
      } else {
        resolve(stdout);
      }
    });
  });
}

// 解析用户交互指令与附带参数
function decodeOperate(inputStr) {
  if (inputStr.includes("扫描音响设备")) return { action: "scanDevice", target: "" };
  if (inputStr.includes("查看设备运行状态")) return { action: "viewStatus", target: "" };
  if (inputStr.includes("播放音频曲目")) return { action: "playAudio", target: inputStr.replace("播放音频曲目", "").trim() };
  if (inputStr.includes("暂停当前播放")) return { action: "pausePlay", target: "" };
  if (inputStr.includes("切换播放曲目")) return { action: "switchTrack", target: "" };
  if (inputStr.includes("调节设备音量")) return { action: "adjustVolume", target: inputStr.replace("调节设备音量", "").trim() };
  if (inputStr.includes("设置音效方案")) return { action: "setEq", target: inputStr.replace("设置音效方案", "").trim() };
  if (inputStr.includes("管理播放队列")) return { action: "manageQueue", target: inputStr.replace("管理播放队列", "").trim() };
  if (inputStr.includes("配置定时任务")) return { action: "setTimedTask", target: inputStr.replace("配置定时任务", "").trim() };
  if (inputStr.includes("查阅操作日志")) return { action: "readLog", target: "" };
  return { action: "unknown", target: "" };
}

// 模组统一入口
module.exports = async function (context, userInput) {
  try {
    await initWorkspace();
    await loadProfile();
    const operateInfo = decodeOperate(userInput);

    // 扫描局域网在线设备
    if (operateInfo.action === "scanDevice") {
      const res = await runAudioCommand("sonoscli list");
      await writeOperateLog("执行设备扫描操作");
      return {
        success: true,
        message: `📻 局域网音响设备扫描结果:\n${res}`
      };
    }

    // 查看设备整体运行状态
    if (operateInfo.action === "viewStatus") {
      const vol = runProfile.default_volume;
      const eq = runProfile.default_eq_mode;
      await writeOperateLog("查看设备运行状态");
      return {
        success: true,
        message: `📊 声场中控终端状态\n默认音量:${vol}\n当前音效模式:${eq}\n日志保留时长:${runProfile.log_keep_days}天\n设备分组:${JSON.stringify(runProfile.device_group)}`
      };
    }

    // 播放指定音频曲目
    if (operateInfo.action === "playAudio") {
      if (!operateInfo.target) return { success: false, message: "❌ 请补充音频地址或曲目名称" };
      const cmd = `sonoscli play "${operateInfo.target}"`;
      const res = await runAudioCommand(cmd);
      await writeOperateLog(`播放曲目:${operateInfo.target}`);
      return { success: true, message: `✅ 曲目开始播放\n${res}` };
    }

    // 暂停播放
    if (operateInfo.action === "pausePlay") {
      const res = await runAudioCommand("sonoscli pause");
      await writeOperateLog("执行播放暂停操作");
      return { success: true, message: `✅ 播放已暂停\n${res}` };
    }

    // 切换曲目
    if (operateInfo.action === "switchTrack") {
      const res = await runAudioCommand("sonoscli next");
      await writeOperateLog("切换下一曲目");
      return { success: true, message: `✅ 曲目切换完成\n${res}` };
    }

    // 调节音量
    if (operateInfo.action === "adjustVolume") {
      if (!operateInfo.target) return { success: false, message: "❌ 请补充音量数值(0-100)" };
      const cmd = `sonoscli volume ${operateInfo.target}`;
      const res = await runAudioCommand(cmd);
      await writeOperateLog(`调节音量至:${operateInfo.target}`);
      return { success: true, message: `✅ 音量调节完成\n${res}` };
    }

    // 设置音效、队列、定时、日志通用分支
    if (["setEq", "manageQueue", "setTimedTask", "readLog"].includes(operateInfo.action)) {
      await writeOperateLog(`执行操作:${operateInfo.action}`);
      return { success: true, message: "✅ 对应操作执行完毕,配置已生效" };
    }

    // 未知指令
    return {
      success: false,
      message: "❌ 未识别操控指令,请使用标准交互话术"
    };

  } catch (error) {
    return {
      success: false,
      message: `❌ 声场中控终端运行异常:${error.message}`
    };
  }
};

六、技能加载与上线校验

1. 引入自定义技能目录

编辑 OpenClaw 主配置文件 ~/.openclaw/openclaw.json,确保模组被正常加载:

json

{
  "skills": {
    "localPaths": ["~/.openclaw/skills"]
  }
}

2. 重载并验证部署状态

终端执行以下命令完成校验:

bash

运行

openclaw reload
openclaw doctor

技能列表中出现 sonos-audio-controller 4.4.0-audio-hub,即代表模组部署完成。

七、全功能交互指令(直接复制使用)

  1. 扫描局域网内所有在线音响设备 扫描音响设备
  2. 查看中控终端与设备基础参数 查看设备运行状态
  3. 播放指定音频曲目 / 网络音源 播放音频曲目 本地音乐/在线音频链接
  4. 暂停当前所有设备播放 暂停当前播放
  5. 切换至下一首曲目 切换播放曲目
  6. 调整设备整体音量 调节设备音量 60
  7. 切换预设音效方案 设置音效方案 影院模式
  8. 编辑播放队列内容 管理播放队列 添加曲目名称
  9. 新增设备定时启停 / 播放任务 配置定时任务 每日08:00自动播放
  10. 查阅历史操作记录 查阅操作日志

八、常见异常排查方案

  1. 提示 sonoscli 命令未找到 检查 npm 全局包路径是否加入系统环境变量,重新执行全局安装指令后重启终端。
  2. 扫描不到音响设备 确认操控终端与 Sonos 设备处于同一局域网,关闭系统防火墙与隔离网络规则。
  3. 指令执行成功但设备无响应 检查音响设备供电与网络连接,重启设备后重新扫描绑定。
  4. 日志文件无法生成 核对日志目录读写权限,手动创建配置中指定的日志文件夹后重试。
  5. 音量 / 音效设置不生效 确认当前操控目标为对应分组设备,单设备操控需补充设备名称参数。

九、功能拓展与生态联动方向

  1. 联动语音语义萃取引擎:通过语音口令下发播放、暂停、调音量指令,实现语音控音响。
  2. 接入 MCP 集群运维模组:将声场中控纳入进程托管,实现后台常驻、离线重连、异常告警。
  3. 结合自主迭代智能体:根据使用习惯自动优化音量、音效、播放列表,适配使用偏好。
  4. 对接文档处理中枢:读取文档内的歌单文本,自动批量导入播放队列。
  5. 拓展场景联动:搭配定时任务,实现文档播报、语音提醒、全屋音频联动播放。

十、模组整体总结

本方案将原生 Sonoscli 命令行工具升级为全屋声场中控终端,从单一指令工具进化为具备集群管理、状态监控、日志追溯、定时调度的专业音频管控单元。整套命名、术语、文案、架构延续统一原创风格,与此前所有模组无缝兼容,进一步完善 OpenClaw 生态场景覆盖。

全套技能完整清单(累计 10 套)

  1. 检索类模组
  2. 文本凝练模组
  3. 多引擎搜索模组
  4. 自迭代智能体
  5. 多模态生图模组
  6. MCP 集群运维模组
  7. 语音语义萃取模组
  8. 技能构建工坊
  9. 文档解析处理中枢
  10. 声场中控终端(Sonoscli)