Skip to content

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

Hand of Agents

一个面向 Agent 的树莓派 GPIO 控制框架。Host Server 提供网页、REST/OpenAPI 和审计记录;树莓派 Client 主动连接 Server,执行经过配置白名单约束的 GPIO 命令,并持续上报节点、系统和 IO 状态。

界面预览

Hand of Agents GPIO 控制面板

架构

Agent / Browser
      │  REST (optional X-API-Key)
      ▼
FastAPI Host Server ─── SQLite audit log
      ▲
      │  authenticated WebSocket
      │  commands / acknowledgements / telemetry
      ▼
Raspberry Pi Client ─── gpiozero ─── relay / sensor
  • Client 主动连接 Host,局域网里无需向树莓派开放控制 API。
  • Server 支持免密钥局域网模式,也可要求 X-API-Key;每个节点的 WebSocket 始终使用后台配置的独立 X-Node-Token,用户操作时无需输入节点 token。
  • raspberry-pi-40pin 配置会列出 26 个通用 GPIO,物理 27/28 脚作为 HAT ID 保留,不开放控制。
  • GPIO 初始保持 unconfigured,网页或 API 明确配置后才会被程序申请,避免启动时抢占 I²C、SPI 和 UART 复用引脚。
  • Client 启动、断线、退出、释放、重配置或命令脉冲结束时,输出回到各自的 safe_state;单路清理失败不会跳过其他已申请引脚的清理。
  • Server 把连接与命令审计写入 SQLite,前端每 2 秒刷新节点状态。
  • 节点显示名默认为 Pi,可在网页中点击名称重命名;名称由 Host SQLite 持久保存,不改变内部 node_id、连接地址或 token。
  • Client 优先从设备树读取树莓派板级序列号,回退到 /proc/cpuinfo 的 Serial,并在设备摘要中作为只读 id 显示。

硬件支持

项目支持从 Raspberry Pi 3B 到 Raspberry Pi 5 的标准 40-pin GPIO 排针,并对各代 SoC / GPIO 控制器显示对应的 Pinmux 复用功能:

硬件系列 已支持型号 GPIO / Pinmux 控制器 复用功能范围
Raspberry Pi 3 3B、3B+、3A+、Zero 2 W、CM3/CM3+ BCM2837 / RP3A0(BCM283x GPIO) ALT0–ALT5
Raspberry Pi 4 4B、400、CM4/CM4S BCM2711 ALT0–ALT5
Raspberry Pi 5 Pi 5、CM5 RP1 ALT0–ALT8
  • 所有型号统一使用 BCM GPIO 编号。raspberry-pi-40pin profile 提供 GPIO2–GPIO27 共 26 个通用 GPIO;物理 27/28 脚是 HAT ID 保留脚,不开放为通用 GPIO。
  • 通用 GPIO 默认保持 unconfigured,只有收到明确的配置命令后才会申请,避免启动时占用 I²C、SPI 或 UART 引脚。
  • Client 组合 /proc/device-tree/model 与 compatible 自动识别硬件,并优先通过只读的 pinctrl -c ... funcs 获取当前系统的功能表;命令不可用时回退到项目内置数据。无法识别的硬件不会误套其他型号的 Pinmux 表。
  • Compute Module 仅在载板确实提供兼容的 40-pin 排针时适用,且需要显式配置 board_profile = "raspberry-pi-40pin"。
  • Pi 5 需要使用当前 Raspberry Pi OS;系统应将 RP1 用户排针暴露为 gpiochip0,由 gpiozero / lgpio 使用 BCM 编号访问。

内置 Pinmux 数据参考 Raspberry Pi 官方的 BCM2711 外设手册 与 RP1 外设手册。

本机启动 Server

需要 Python 3.11+:

python3 -m venv .venv
.venv/bin/pip install -e '.[server,dev]'
cp .env.example .env

编辑 .env。仅在可信局域网使用时可设 HOA_AUTH_MODE=none,网页和 API 无需密钥;设为 api_key 时务必更换示例密钥:

chmod +x scripts/*.zsh
./scripts/run-server.zsh

打开 http://HOST_IP:8000/ 查看面板,OpenAPI 位于 http://HOST_IP:8000/docs。

节点头部以两行设备摘要显示可重命名名称、由 Host 连接端确认的 IP、板级序列号、型号及遥测信息;内部节点 ID 不在页面显示。面板默认使用英文,右上角的 ZH/EN 按钮可切换中英文,选择会保存在当前浏览器中。右上角的 PINMUX 按钮默认关闭;点击后会在全部 GPIO 旁显示与当前硬件匹配的复用功能,再次点击即隐藏。该视图仅供接线和 Device Tree 配置参考,不会改变引脚模式。排针图中的每个 GPIO 都带有独立的 Direction、Level 下拉和一键“释放”按钮;输入上下拉等完整参数通过引脚框内的“高级”按钮设置。

如需随桌面用户会话自动启动,可链接仓库内的 user service:

systemctl --user link "$PWD/deployment/hand-of-agents-server-user.service"
systemctl --user enable --now hand-of-agents-server-user.service

如果希望注销后仍保持服务运行,需要管理员执行 loginctl enable-linger USERNAME;也可以改用 deployment/hand-of-agents-server.service 安装为系统服务。

树莓派 Client

复制 configs/pi-lab.toml.example 并按实际接线填写。board_profile = "raspberry-pi-40pin" 会自动生成排针图和 26 个可操作 GPIO;单独的 [[pins]] 条目只能覆盖 profile 中已有 BCM 的名称、默认模式及安全状态,不能改变物理针脚映射或加入 BCM0/1。引脚编号统一采用 BCM。继电器板常见低电平触发,此时应设置 active_high = false,但必须以实际模块规格为准。

server_url 应填写 Host Server 的实际可达地址。若 Server 与 Client 同在一台树莓派上,并希望面板显示该树莓派的局域网 IP,也应填写其局域网地址(例如 192.168.10.190),不要填写 127.0.0.1;Host 会使用 WebSocket 对端地址作为节点 IP。

sudo apt install python3-gpiozero python3-lgpio
python3 -m venv --system-site-packages .venv
.venv/bin/pip install -e '.[pi]'
cp configs/pi-lab.toml.example client.toml
.venv/bin/hoa-client --config client.toml

没有 GPIO 的开发机将 gpio_backend 改为 mock。Pi 5 应使用当前 Raspberry Pi OS;当前系统把 RP1 用户排针统一暴露为 gpiochip0,gpiozero 通过 lgpio 使用与 Pi 3/4 相同的 BCM 编号。生产部署可使用 deployment/hand-of-agents-client.service。该 unit 使用无登录权限的专用账号 hand-of-agents,不依赖安装人员或开发机的用户名。首次安装时创建账号并保护 Client 配置:

sudo useradd --system --user-group --home-dir /var/lib/hand-of-agents \
  --create-home --shell /usr/sbin/nologin hand-of-agents
sudo install -d -o root -g hand-of-agents -m 0750 /etc/hand-of-agents
sudo install -o root -g hand-of-agents -m 0640 client.toml \
  /etc/hand-of-agents/client.toml
sudo install -o root -g root -m 0644 deployment/hand-of-agents-client.service \
  /etc/systemd/system/hand-of-agents-client.service
sudo systemctl daemon-reload
sudo systemctl enable --now hand-of-agents-client.service

若 hand-of-agents 账号已由 Server 部署创建,则跳过 useradd。unit 通过 SupplementaryGroups=gpio 取得 GPIO 设备权限;不要把 Client token 放进 unit 或命令行。

Agent API

当前部署使用 HOA_AUTH_MODE=none,以下请求无需 token。若切换为 api_key,给写操作及审计请求增加 X-API-Key 请求头。

# 节点状态
curl http://192.168.1.40:8000/api/v1/nodes

# 修改节点显示名;pi-lab 是内部 node_id,不会随显示名改变
curl -X POST \
  -H 'Content-Type: application/json' \
  -d '{"name":"Bench Pi"}' \
  http://192.168.1.40:8000/api/v1/nodes/pi-lab/name

# 将 GPIO17(物理 11 脚)配置为输出;初始化为 safe_state
curl -X POST \
  -H 'Content-Type: application/json' \
  -d '{"action":"configure","direction":"output"}' \
  http://192.168.1.40:8000/api/v1/nodes/pi-lab/pins/GPIO17

# 输出 HIGH
curl -X POST \
  -H 'Content-Type: application/json' \
  -d '{"action":"set","value":true}' \
  http://192.168.1.40:8000/api/v1/nodes/pi-lab/pins/GPIO17

# 持续输出 500ms HIGH / 500ms LOW;HIGH、LOW、释放或断线会停止循环
curl -X POST \
  -H 'Content-Type: application/json' \
  -d '{"action":"pulse","duration_ms":500,"continuous":true}' \
  http://192.168.1.40:8000/api/v1/nodes/pi-lab/pins/GPIO17

# 配置为带上拉的输入
curl -X POST \
  -H 'Content-Type: application/json' \
  -d '{"action":"configure","direction":"input","pull":"up"}' \
  http://192.168.1.40:8000/api/v1/nodes/pi-lab/pins/GPIO17

# 释放引脚,恢复 FREE 状态
curl -X POST \
  -H 'Content-Type: application/json' \
  -d '{"action":"configure","direction":"unconfigured"}' \
  http://192.168.1.40:8000/api/v1/nodes/pi-lab/pins/GPIO17

# 最近的审计事件
curl 'http://192.168.1.40:8000/api/v1/events?limit=50&node_id=pi-lab'

节点名称接口接受 1–64 个字符,网页点击绿色名称即可重命名;api_key 模式下与其他写操作一样需要 X-API-Key。configure 支持 input、output、unconfigured,输入模式的 pull 支持 up、down、floating,并可通过 pulse_hz 保存该引脚的 PULSE 频率(0.1–10 Hz,默认 1 Hz)。重复确认相同的 Direction/Pull 不会重新初始化 GPIO;修改运行中 PULSE 的频率会保留当前模式和电平相位。高级弹窗会同步实际配置,Direction、Pull、频率及 HIGH/LOW/PULSE 均只在本地暂存,点击“确认”后才提交。set 接受布尔值,toggle 不需要额外字段。pulse 接受半周期 duration_ms;continuous=true 时持续循环,默认 false 时仅输出一次。网页仅在“高级”设置中编辑频率,Level 控件保持显示 PULSE,而引脚状态文字和颜色显示最近采样到的实际 HIGH/LOW。节点空闲时每 2 秒更新一次,存在连续 PULSE 时自适应为 500 ms。HTTP 2xx 代表树莓派已确认执行;节点离线返回 409,超时返回 504,非法引脚或模式错误返回 422。

配置参考

Server 环境变量:

变量 说明
HOA_BIND_HOST / HOA_BIND_PORT 监听地址与端口
HOA_AUTH_MODE none 免密钥操作;api_key 要求操作密钥
HOA_API_KEY Agent 和网页写操作密钥
HOA_NODE_TOKENS 逗号分隔的 node-id:token 列表
HOA_DB_PATH SQLite 审计库路径
HOA_CORS_ORIGINS 前端独立部署时允许的来源列表
HOA_COMMAND_TIMEOUT Server 等待 Client 确认的秒数

Client 的完整示例见 configs/pi-lab.toml.example。gpio_backend = "auto" 和 gpiozero 当前行为相同:GPIO 操作失败会明确返回错误,不会静默降级到 Mock。通用引脚默认 safe_state = false,为长期连接的继电器等设备添加覆盖配置,以明确触发极性和断线安全状态。时间间隔必须是有限正数,max_pulse_ms 必须为 50–60000,布尔配置必须使用 TOML 的 true/false,不能写成字符串。

开发验证

PYTHONPATH=src python3 -m pytest -q
python3 -m compileall -q src tests

实机测试日志放在 logs/,不要将 .env、Client token、SSH 密码或其他凭据提交到版本库。

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages