NINA 控制 API 文档
1.4 中文深色界面与分级菜单
已按用户提供的参考图改为黑色背景和深灰分层界面。新增观测概览;主控台、设备和序列采用分级菜单,不再集中在一个长页面。中文正文 16px,375 / 390 / 430px 布局与底部导航经过截图复查。设计与信息主次见 docs/UI-DESIGN.md。
分体部署更新到 nina-server-1.4.zip 和 nina-host-1.4.zip,两端同时升级并保留 config.json 与运行数据。域名仍为 https://nina.finderskys.online,现有密钥不变。
1.3 主控台与图形化序列
新增“主控台 / Imaging”页面和多目标图形化序列生成器,继续分为服务器与工控机两个部署包,域名及现有密钥保留。详见 docs/IMAGING.md,其中按 NINA 源码列出已接入功能及 Advanced API 未开放的项目。
支持图像预览、历史与统计、解析、导星曲线、设备附加控制,及常用顺序序列的可视化编排、生成、保存、加载。生成与加载不会自动开始拍摄。
此版不是完整 NINA 桌面克隆,也不冒充支持插件全部节点;未接入项在功能对照中明确列出。
1.2 分体部署与实际拍摄入口
本次正式部署交付为两个包:nina-server-1.2.zip 和 nina-host-1.2.zip,服务器域名已配置为 https://nina.finderskys.online。两个包内 README 分别说明部署操作;详见随包交付的《部署与拍摄说明.md》。
服务器端仅运行转发和网页,工控机端运行 Agent,主动通过 HTTPS 连接服务器;NINA 与 PHD2 保持本机访问。两端保留当前项目的同一对密钥。
新增序列页拍摄监控,每 5 秒读取真实设备和序列状态;可按名称读取、加载 NINA 保存的序列,再单独开始。连续拍摄由 NINA 本地执行,原图保存工控机。
新增只读检查命令 python -m nina_control.preflight --config config.json 和 Windows 当前用户登录任务脚本 install-agent-task.ps1。不自动安装登录任务。
停止命令有独立执行名额,避免四个远程查询或操作等待时阻塞停止。停止序列、曝光、导星和赤道仪是独立命令。
HTTP 命令成功表示 NINA 接受或完成了相应 API 请求,不能用单帧曝光 API 的成功或 IsExposing=false 证明图像已落盘;首次拍摄需要核对 NINA 保存目录中的文件。
该版本未在你的远程服务器或真实设备上验收;Docker、HTTPS 证书签发和真实出片仍需部署后检查。序列 JSON 编辑沿用原生格式,未提供完整拖拽编辑器或原图云端上传下载。
Windows 启动脚本与服务器分离部署步骤见 docs/DEPLOY.md,运行服务后也可打开 /deploy。网页不再按缓存连接状态禁用控制按钮,实际请求交由后端返回结果。
1 连接结构与职责
网页或业务调用方 → HTTPS REST 平台服务器 → 主机主动轮询 → 本机 NINA Advanced API → 已配置的赤道仪驱动。
主机 Agent 每 0.2 秒空闲轮询一次,每 2 秒上报心跳和状态。只使用出站 HTTP 请求,不要求现场开放公网端口。相对长连接,这个首版更容易在代理和断网重连环境下调试;后续可将下行替换为 WebSocket/MQTT,保留 REST 和命令协议不变。方向点动仅在主机与本地 NINA 间使用 WebSocket。
服务器默认为 http://127.0.0.1:18700;联网 Agent 的主机本地 REST 默认为 http://127.0.0.1:18701;单独 host 模式默认 18700。两个 REST 服务提供相同业务接口。远程主机连接强制要求 HTTPS,环回调试允许 HTTP。所有功能只针对一套主机和赤道仪。
2 认证和请求规则
业务请求:Authorization: Bearer <api_token>。网页会记住已填写的密钥,保存在当前浏览器 localStorage;刷新及重新打开页面后自动使用。服务端密钥来自 config.json 或环境变量,不会在重启时自动轮换。
Agent 请求:Authorization: Bearer <agent_token>;注册后还要携带 X-Agent-Session: <session_id>。两种密钥必须不同且至少 32 字符。真实模式不提供无认证控制入口,静态网页和 API 文档可公开读取。
所有改变状态的命令必须携带 Idempotency-Key,长度 8–128。同键同内容返回原命令,同键不同内容返回 409。使用新键表示新的操作;网络超时后应查询旧命令状态,不要换新键重复移动。
POST 使用 JSON;单请求最大 8 MB。跨域请求被拒绝,不启用通配 CORS。默认只接受 localhost/127.0.0.1 Host;部署域名通过 allowed_hosts 配置。反向代理须保留 Host,浏览器与 API 保持同源。HTTP 监听器供本机代理使用,不是 TLS 终止器。
3 业务 REST 接口
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /health | 无密钥存活检查,不代表设备在线 |
| POST | /api/v1/session | 校验已有 Bearer Token,不提供匿名会话或自动登录 |
| GET | /api/v1/mount | 缓存的现场状态;含 agent_online、stale、updated_at、mode、mount |
| GET | /api/v1/mount/capabilities | 向主机查询驱动能力及点动速率区间 |
| GET | /api/v1/targets?q=M31&limit=20 | 向主机读取 NINA 星表,默认最多 20 条,上限 100 |
| POST | /api/v1/commands | 提交命令,202 返回命令记录及 Location |
| GET | /api/v1/commands/{id} | 查询命令状态、结果或错误 |
| GET | /docs | 中文离线文档 |
| GET | /openapi.json | OpenAPI 3.1 规范 |
查询结果示例:
{
"source": "nina_catalog",
"epoch": "J2000",
"targets": [{"id":"NGC224","aliases":["M31"],"name":"NGC224","ra_deg":10.6847,"dec_deg":41.2690,"epoch":"J2000","type":"GALXY","source":"nina_catalog"}]
}
示例坐标仅示意返回结构;实际使用主机星表数值。不会请求 NINA 不存在的 /target/search 接口。查询不会移动设备。
4 命令统一格式
POST /api/v1/commands
Authorization: Bearer <api_token>
Idempotency-Key: goto-m31-20261029-001
Content-Type: application/json
{"action":"mount.goto","params":{"ra_deg":10.6847,"dec_deg":41.2690,"epoch":"J2000","tracking":"sidereal"}}
{"id":"<UUID>","action":"mount.goto","params":{},"state":"queued","created":0,"expires":15,"updated":0,"result":null,"error":null}
上例时间字段结构为 Unix 秒,实际响应含完整原始 params。服务器创建的 expires 是 created+15 秒,表示开始执行期限,不表示运动必须 15 秒内完成。Agent 与服务器需进行系统时钟同步。
所有位置输入均为 J2000 赤经角度 ra_deg [0,360)、赤纬 dec_deg [-90,90]。赤经小时须先乘 15。当前不接受 JNOW 输入;NINA 在内部根据驱动完成坐标转换。返回 mount 的坐标可能属于驱动历元,必须同时查看 epoch/raw,不要直接与 J2000 目标做减法。
4.1 赤道仪命令
| action | params | NINA 对应接口 |
|---|---|---|
| mount.info | {} | GET /equipment/mount/info |
| mount.capabilities | {} | 根据 mount/info 提取能力和速率 |
| mount.devices | {} | GET /equipment/mount/list-devices |
| mount.rescan | {} | GET /equipment/mount/rescan |
| mount.connect | 可选 device_id | GET /equipment/mount/connect?to=...;省略用 NINA 已选设备 |
| mount.disconnect | {} | GET /equipment/mount/disconnect;转向或跟踪中拒绝 |
| mount.goto | ra_deg,dec_deg;可选 epoch、tracking | GET /equipment/mount/slew;见下一节 |
| mount.stop | {} | GET /equipment/mount/slew/stop,再停止跟踪 |
| mount.tracking | mode | GET /equipment/mount/tracking?mode=... |
| mount.park | {} | GET /equipment/mount/park |
| mount.unpark | {} | GET /equipment/mount/unpark |
| mount.set_park | {} | GET /equipment/mount/set-park-position |
| mount.home | {} | GET /equipment/mount/home |
| mount.sync | ra_deg,dec_deg;可选 epoch | GET /equipment/mount/sync;同步坐标模型,不做转向 |
| mount.flip | {} | GET /equipment/mount/flip;只在 NINA 判定需要时翻转,不强制 |
| mount.jog | direction,rate_deg_s;可选 duration_ms | 本机 WS /v2/mount,发送 direction/rate |
tracking/mode 枚举:sidereal 恒星、lunar 月球、solar 太阳、king King、stopped 停止。对应上游数值 0/1/2/3/4;Goto 不接受 stopped,默认 sidereal。可用模式仍由驱动决定。设置跟踪模式不包含自动寻找相应天体。
Goto 流程:检查已连接、未停放、未转向和必要能力 → 开启指定跟踪 → NINA slew(ra/dec 为角度,center=false、rotate=false、waitForResult=true)→ 再次设置跟踪并读取状态确认。成功表示 NINA 转向返回成功,且读回非 Slewing、TrackingEnabled=true;不是拍照解析居中证明。上游转向请求超时为 180 秒,失败时尝试本地停止,不自动重试。停放设备必须显式 unpark,不会隐式解除停放。
停止不等待 Goto 操作锁。停止命令会取消仍在服务器队列的旧赤道仪控制;主机亦拒绝早于最近停止的旧命令。它是软件停止接口,不能代替硬件急停与现场限位。
park/home/flip 上游会启动异步动作,其命令成功结果标注 completion: accepted_by_nina,只表示 NINA 接受;使用 mount.info 的 AtPark/AtHome/Slewing 等确认物理完成。connect/unpark 等也应读回状态。不要把所有 succeeded 一律解释为设备已停止运动。
点动示例:
{"action":"mount.jog","params":{"direction":"east","rate_deg_s":0.5,"duration_ms":500}}
direction 为 north/south/east/west;速度单位度/秒,非“恒星速倍数”。duration_ms 默认 500,范围 100–1500。请求速率必须在驱动上报区间内;服务上限为 10 度/秒。Agent 每约 0.5 秒续传,结束后发送 0 速,NINA 自身无续传约 2 秒停止。这里是有限时长点动,不能依赖浏览器 mouseup 或远程长按维持运动。
4.2 构图与目标命令
| action | params | 说明 |
|---|---|---|
| target.search | query;可选 limit | 同目标查询 REST,读取 NINA.sqlite |
| framing.info | {} | 原样读取 NINA 构图助手信息 |
| framing.set | ra_deg,dec_deg;可选 epoch、rotation_deg、survey_image | 设置构图中心与旋转角、回传视场、可选真实底图 |
| framing.source | source | 切换 NINA 构图来源 |
source 可取 NASA、SKYSERVER、STSCI、ESO、HIPS2FITS、SKYATLAS、FILE、CACHE。NINA 必须至少打开过一次构图助手;set 不执行 slew,不触发相机曝光,不保证 NINA 自己已下载新底图。网页返回的底图由独立 CDS 查询取得,不冒充 NINA 界面截图。
{"action":"framing.set","params":{"ra_deg":10.6847,"dec_deg":41.2690,"epoch":"J2000","rotation_deg":0,"survey_image":true}}
成功 result 包含:
- source:nina_framing。
- center:输入的 J2000 中心。
- rotation_deg:构图角度,0–360;仅更改构图助手,不转动旋转器。
- fov:width_deg、height_deg、width_px、height_px、pixel_um、focal_mm。
- nina:NINA 构图助手完整原始信息。
- image:真实底图 data_url、field_deg、TAN 投影、来源、归属信息和查询地址,或 null。
- image_error:底图不可用的原因,或 null;几何视场成功但底图失败不算整项失败。
视场公式:width_deg = 2 * atan(width_px * pixel_um / 1000 / (2 * focal_mm)) * 180/pi,高度同理。取 NINA 已有相机和焦距配置,不从浏览器参数臆造设备。参数缺失/非正数返回 FRAMING_NOT_READY。
底图采用固定 CDS HiPS2FITS DSS2 color 服务,800×800,J2000/ICRS 实用近似、TAN 投影,字段范围为相机较大视场的 1.45 倍。网页蓝框显示中心相机视场和构图旋转,是中心视场预览;未实现拼接面板、畸变模型和精密 WCS 拖拽。示意方向为北上东左。运行程序没有模拟模式或模拟回退;无法连接真实 NINA 时返回明确错误,不返回假视场。
5 命令状态与恢复
queued → dispatched → running → succeeded / failed。
queued 超过开始期限由队列认领时标记 expired。进程重启时 dispatched/running 标记 unknown,不自动重放硬件动作。若最终结果超过 240 秒仍未收到,查询时转 unknown,需检查现场。终态不被迟到回报覆盖。
主机日志使用 commandId 去重:网络重试只重传结果,不重新运动。服务器无心跳超过 10 秒判离线,拒绝新命令;状态超过 5 秒标记 stale。服务器重启不重新下发已 dispatch 的命令;Agent 断线不等于设备已经停止。普通 Goto 可能继续在 NINA 内执行,点动有主机时限和 NINA 续传超时。断网期间应在现场 NINA 或主机本地 REST 停止。当前不能保证操作系统崩溃与设备动作之间的严格 exactly-once。
数据库本身已完成 WAL 提交后才派发命令。命令记录没有自动清理策略,应按运营需要离线归档。此版无多租户权限、任务排程、外部天气限位或多机资源调度。
6 Agent 协议
| 方法 | 路径 | 请求/响应 |
|---|---|---|
| POST | /api/agent/heartbeat | {session_id,mode,mount};注册并更新在线状态 |
| POST | /api/agent/next | {};返回 {command:记录或null},单次领取、不会因 ACK 丢失重发运动 |
| POST | /api/agent/commands/{id} | {state,result?,error?};上报 running/succeeded/failed/unknown |
session_id 每次 Agent 启动重新生成。已有在线会话时拒绝另一实例注册,避免同套设备同时运行两个 Agent。最后一次心跳超过 10 秒后允许新会话接管;旧会话不再可拉取命令。接管前仍需确认旧现场操作是否运行。
7 错误结构
{"error":{"code":"MOUNT_PARKED","message":"Unpark explicitly before moving"}}
HTTP 常见状态:400 参数错误、401 密钥错误、403 来源/Host 错误、404 未知命令、409 状态冲突或上游拒绝、413 请求过大、501 驱动未声明能力、502 上游失败、503 主机/星表不可用、504 查询超时。
异步命令执行错误位于命令记录 error 中,含 code/message/status;查询命令本身仍返回 HTTP 200。NINA 可能 HTTP 200 但 JSON Success=false,本适配器会判为失败,不将其当成功。
8 快速调用
$headers = @{ Authorization = "Bearer $env:NINA_API_TOKEN" }
Invoke-RestMethod 'http://127.0.0.1:18700/api/v1/targets?q=M31' -Headers $headers
$headers['Idempotency-Key'] = [guid]::NewGuid().ToString()
$body = @{ action='mount.goto'; params=@{ra_deg=10.6847; dec_deg=41.2690; epoch='J2000'; tracking='sidereal'} } | ConvertTo-Json
$cmd = Invoke-RestMethod 'http://127.0.0.1:18700/api/v1/commands' -Method Post -Headers $headers -ContentType 'application/json' -Body $body
Invoke-RestMethod "http://127.0.0.1:18700/api/v1/commands/$($cmd.id)" -Headers $headers
9 范围和上游依据
截图所示赤道仪常用功能已覆盖。驱动的物理能力以 capability 为准;未支持的能力不会伪装成功。Advanced API 本身未暴露的厂商私有控制、任意 RA/Dec 自定义跟踪率、脉冲导星、站点写入、驱动设置对话框尚未实现,详见 mount.capabilities 的 unsupported_via_advanced_api。主机不同时直连 ASCOM COM 创建第二个设备控制实例。
上游依据(核对日期 2026-10-29):
- https://github.com/christian-photo/ninaAPI
- https://raw.githubusercontent.com/christian-photo/ninaAPI/dev/ninaAPI/api_spec.yaml
- https://raw.githubusercontent.com/christian-photo/ninaAPI/dev/ninaAPI/websocket_spec.yaml
- https://github.com/christian-photo/ninaAPI/blob/dev/ninaAPI/WebService/V2/Equipment/Mount.cs
- https://github.com/christian-photo/ninaAPI/blob/dev/ninaAPI/WebService/V2/Application/Framing.cs
- https://alasky.cds.unistra.fr/hips-image-services/hips2fits
本项目使用上游公开协议,未分发 NINA、驱动、其星表或其插件源码。上游 dev 分支会变化,真实联调应记录 /version 返回并核对 API 映射。交付包中的 tests/ 使用隔离的设备替身、伪 NINA 和本地反向连接;生产模块不含模拟设备;不构成 AVX 实机运动验收。
10 设备与序列扩展 1.1
新增功能不改变既有密钥、部署模式或赤道仪接口。仍使用 POST /api/v1/commands 下发 action,202 表示命令已入队;通过返回的 id 查询最终结果。
10.1 设备状态 REST
GET /api/v1/equipment:NINA 全部设备状态原文。
GET /api/v1/camera、/api/v1/filterwheel、/api/v1/focuser、/api/v1/guider:分别读取设备状态。GET /api/v1/guidecamera:通过 PHD2 读取导星相机状态、曝光时间及支持的曝光选项。所有接口均需要 api_token。
设备控制映射如下。参数的必填项以 OpenAPI 为准,带 * 的字段为必填。
| action | params | 上游接口 |
|---|---|---|
| camera.info | {} | /equipment/camera/info |
| camera.devices | {} | /equipment/camera/list-devices |
| camera.rescan | {} | /equipment/camera/rescan |
| camera.connect | device_id | /equipment/camera/connect |
| camera.disconnect | {} | /equipment/camera/disconnect |
| filterwheel.info | {} | /equipment/filterwheel/info |
| filterwheel.devices | {} | /equipment/filterwheel/list-devices |
| filterwheel.rescan | {} | /equipment/filterwheel/rescan |
| filterwheel.connect | device_id | /equipment/filterwheel/connect |
| filterwheel.disconnect | {} | /equipment/filterwheel/disconnect |
| focuser.info | {} | /equipment/focuser/info |
| focuser.devices | {} | /equipment/focuser/list-devices |
| focuser.rescan | {} | /equipment/focuser/rescan |
| focuser.connect | device_id | /equipment/focuser/connect |
| focuser.disconnect | {} | /equipment/focuser/disconnect |
| guider.info | {} | /equipment/guider/info |
| guider.devices | {} | /equipment/guider/list-devices |
| guider.rescan | {} | /equipment/guider/rescan |
| guider.connect | device_id | /equipment/guider/connect |
| guider.disconnect | {} | /equipment/guider/disconnect |
| equipment.info | {} | /equipment/info |
| camera.capture | duration_s*, gain, image_type, save, target_name | /equipment/camera/capture |
| camera.abort | {} | /equipment/camera/abort-exposure |
| camera.cool | temperature_c*, minutes, cancel | /equipment/camera/cool |
| camera.warm | minutes, cancel | /equipment/camera/warm |
| camera.binning | binning* | /equipment/camera/set-binning |
| camera.readout | mode* | /equipment/camera/set-readout |
| camera.dew_heater | enabled* | /equipment/camera/dew-heater |
| camera.usb_limit | limit* | /equipment/camera/usb-limit |
| camera.statistics | {} | /equipment/camera/capture/statistics |
| filterwheel.change | filter_id* | /equipment/filterwheel/change-filter |
| filterwheel.filter_info | filter_id* | /equipment/filterwheel/filter-info |
| focuser.move | position* | /equipment/focuser/move |
| focuser.stop | {} | /equipment/focuser/stop-move |
| focuser.autofocus | cancel | /equipment/focuser/auto-focus |
| focuser.last_autofocus | {} | /equipment/focuser/last-af |
| guider.start | calibrate | /equipment/guider/start |
| guider.stop | {} | /equipment/guider/stop |
| guider.clear_calibration | {} | /equipment/guider/clear-calibration |
| guider.graph | {} | /equipment/guider/graph |
| guidecamera.info | {} | 本机 PHD2 JSON-RPC |
| guidecamera.connect | {} | 本机 PHD2 JSON-RPC |
| guidecamera.disconnect | {} | 本机 PHD2 JSON-RPC |
| guidecamera.loop | {} | 本机 PHD2 JSON-RPC |
| guidecamera.stop | {} | 本机 PHD2 JSON-RPC |
| guidecamera.exposure | exposure_ms* | 本机 PHD2 JSON-RPC |
| guidecamera.capture | exposure_ms | 本机 PHD2 JSON-RPC |
| guidecamera.star_image | size | 本机 PHD2 JSON-RPC |
| sequence.list | {} | 主机持久序列库 / NINA 原生 JSON 加载 |
| sequence.get | id* | 主机持久序列库 / NINA 原生 JSON 加载 |
| sequence.create | name*, document | 主机持久序列库 / NINA 原生 JSON 加载 |
| sequence.update | id*, revision*, name, document | 主机持久序列库 / NINA 原生 JSON 加载 |
| sequence.delete | id*, revision* | 主机持久序列库 / NINA 原生 JSON 加载 |
| sequence.load | id*, revision* | 主机持久序列库 / NINA 原生 JSON 加载 |
| sequence.current | {} | /sequence/json |
| sequence.state | {} | /sequence/state |
| sequence.available | {} | /sequence/list-available |
| sequence.start | {} | /sequence/start |
| sequence.stop | {} | /sequence/stop |
| sequence.reset | {} | /sequence/reset |
| sequence.skip | type* | /sequence/skip |
| sequence.load_file | name* | /sequence/load |
| sequence.edit_live | path*, value* | /sequence/edit |
| sequence.set_target | name*, ra_deg*, dec_deg*, rotation_deg*, index* | /sequence/set-target |
10.2 主相机
camera.capture 请求例子:
{"action":"camera.capture","params":{"duration_s":60,"gain":100,"image_type":"LIGHT","save":true,"target_name":"M31"}}
曝光秒数、帧类型、增益由单次 capture 指定;binning 和 readout 通过独立命令设置。不把主相机与导星相机占用同一个硬件实例。原图保存目录由 NINA 配置,接口不返回原图二进制。曝光返回 accepted_by_nina 后用 camera.info 与 camera.statistics 判断真实完成情况;中止使用 camera.abort,停止请求不等待其他操作的控制锁。
制冷 temperature_c 单位摄氏度,minutes 单位分钟,-1 表示 NINA 默认时长;warm 不需要目标温度。驱动不支持某项能力时以真实 NINA 错误为准,不模拟成功。滤镜 ID 以 filterwheel.info 为准;focuser.move 是绝对步数,实际行程以驱动限制为准。自动对焦依赖 NINA 已配置好的相机、滤镜和对焦参数。停止调焦和取消自动对焦是两个独立操作。
10.3 导星相机与 PHD2
NINA guider.* 控制 NINA 已选的导星器:连接、启停、重新校准、读导星误差。guidecamera.* 则直接调用工控机 PHD2 的 JSON-RPC,用于导星相机曝光、循环取像、单帧取像和导星局部图像。
在工控机启动 PHD2,配置真实相机和赤道仪,然后启用“工具 → 启用服务器”。默认 TCP 4400;如第二实例使用其他端口,在 config.json 添加 phd2_port 整数,不需要改变任何已有密钥。所有 PHD2 连接限定 127.0.0.1,不向网页开放原始 TCP。
exposure_ms 单位毫秒,只接受 get_exposure_durations 返回的支持值。单帧取像会让 PHD2 检查当前导星/循环状态;需要时先停止取像。connect/disconnect 对应 PHD2 set_connected,影响其当前配置内全部设备,不是仅对相机做开关。star_image 返回导星星点的局部 16 位图像数据及宽高,不是全幅相机预览。gain、offset 等厂商私有导星相机参数未被 PHD2 JSON-RPC 公开,因此没有虚构接口。
10.4 原生序列库 CRUD
序列文件由工控机持久保存,默认在启动 --data 目录下的 sequences/library.sqlite;可用 config.json 的 sequence_directory 指定其他序列库目录。服务器和 Agent 分开部署时,库仍放在 Agent 工控机上,而不是只存到浏览器或服务器缓存。
| 方法 | 路径 | 请求体及行为 |
|---|---|---|
| GET | /api/v1/sequences | 返回库内 id、name、revision、created、updated |
| POST | /api/v1/sequences | name 必填;document 可选;返回异步命令 |
| GET | /api/v1/sequences/{id} | 返回完整原生 document 和当前 revision |
| PUT 或 PATCH | /api/v1/sequences/{id} | revision 必填,name/document 至少一个;返回异步命令 |
| DELETE | /api/v1/sequences/{id} | JSON 请求体含 revision;返回异步命令 |
| POST | /api/v1/sequences/{id}/load | JSON 请求体含 revision;加载到 NINA,绝不自动开始 |
所有写请求需要 Idempotency-Key。也可通过统一命令接口调用同名 sequence.create/get/update/delete/list/load。id 为服务器生成的 32 位小写十六进制标识,不接受文件路径。revision 为乐观锁,更新后加一;版本不匹配返回 REVISION_CONFLICT,防止旧页面覆盖新编辑。
新建示例:
{"action":"sequence.create","params":{"name":"M31 LRGB"}}
省略 document 时生成符合 NINA 容器结构的 Start / Imaging / End 空序列,不包含曝光或运动指令。实际拍摄可在 NINA 保存高级序列 JSON,然后在网页导入、修改原生 JSON 并保存为新序列。网页支持序列列表、读取、JSON 编辑、导入和导出,不提供完整的 NINA 拖拽编辑器。
NINA 原生保存 JSON 包含 $type,并以 SequenceRootContainer 为根。sequence.current 与 sequence.state 是状态快照,不是原生保存文件;服务会拒绝把这类状态结果当成原生序列导入。单序列上限 4 MB。新增自定义插件节点时,工控机 NINA 也必须安装相应插件。服务校验根结构与大小,不替代 NINA 对每个具体节点的验证。
加载指定序列:
{"action":"sequence.load","params":{"id":"返回的32位id","revision":1}}
先在 NINA 打开高级序列器以完成初始化。load 使用 POST /sequence/load,发送未经额外包装的原生 JSON,结果标记 started=false。随后显式调用 sequence.start,保留 skipValidation=false,由 NINA 校验实际设备与序列条件。若 NINA 已在执行序列,加载冲突由 NINA 返回。
sequence.stop 停止 NINA 当前高级序列;sequence.reset 重置当前进度;sequence.skip 可选 CurrentItems/ToEnd/ToImaging。sequence.available 列出 NINA 自己序列目录内的文件;sequence.load_file 只接受这个列表里已有的相对名称,不允许任意路径读取。序列库与 NINA 默认文件目录分开管理:删除库条目不会删除用户原有 NINA 文件,也不会清空已加载的 NINA 副本。更改已保存条目不会直接修改正在执行的副本。
sequence.edit_live 使用 NINA sequence/state 中的路径,支持简单标量字段,是上游实验功能;格式为 Imaging-Items-0-ExposureTime 等。它只修改当前 NINA 内存对象,不自动写回序列库。建议先停止序列再操作,复杂对象/枚举应编辑库中的原生 document 后重新加载。
10.5 来源与验证
接口依据:NINA Advanced API v2 的 api_spec.yaml、Application/Sequence.cs,以及 PHD2 官方事件服务文档:
- https://github.com/christian-photo/ninaAPI/blob/dev/ninaAPI/api_spec.yaml
- https://github.com/christian-photo/ninaAPI/blob/dev/ninaAPI/WebService/V2/Application/Sequence.cs
- https://github.com/OpenPHDGuiding/phd2/wiki/EventMonitoring
- https://github.com/isbeorn/nina/blob/develop/NINA.Sequencer/Serialization/SequenceContainerCreationConverter.cs
扩展在隔离的 HTTP/TCP 假上游验证参数、状态和序列读写;没有自动曝光、调焦、切换滤镜或移动真实设备。目标设备与 NINA/PHD2 的实机兼容性仍需现场联调。
11 设备选择与操作反馈修正 1.1.1
网页进入设备页后自动读取设备列表和实时连接状态。相机、滤镜轮、电调焦、导星器和赤道仪均以设备名称显示在下拉框,界面不再要求手工输入 device_id;实际连接时把所选条目的 Id 传给原有 API。可点击刷新设备列表重新获取;没有列表或读取失败时明确显示原因,不会猜测设备 ID。
滤镜轮从 info 的 AvailableFilters 生成滤镜名称下拉框,用 SelectedFilter 显示当前滤镜。选择后自动读取 filter-info,切换前再次核对最新列表,发送实际 Id(支持不连续的编号),切换后读取 SelectedFilter 和 IsMoving 确认到位,不要求用户输入数字。
连接、断开、滤镜切换均显示卡片内反馈、处理中的按钮文案及成功/失败浮动通知。连接/断开由读回的 Connected 状态确认,连接时也核对驱动 DeviceId。12 秒内未确认时显示“请求已接受、状态未确认”,不会把命令接受直接当作连接成功。NINA/PHD2 错误在当前卡片和浮动通知显示。
PHD2 设备连接仍按 PHD2 当前配置执行,不通过 NINA 的 device_id 选择导星相机。该卡片明确显示 PHD2 中配置的相机名称与连接状态。既有 HTTP API、密钥和序列库兼容。
NINA Control 1.3 · 主控台与图形化序列
源码依据与功能边界
已克隆官方仓库到 outputs/nina-upstream,开发版提交 717ea13;同时核对官方 Version-3.2 标签(2393eae581145ed5b8114bf07c48ca2580540fd5)的曝光、等待、制冷和滤镜序列化格式。
本次扩展的是网页和工控机 Agent,没有修改或替换已安装的 NINA 桌面程序。
主控台按 NINA Imaging 的信息面板和工具面板对照实现,连接 NINA Advanced API 2.2.15 系列。
| NINA 成像功能 | 网页对应实现 | 说明 |
|---|---|---|
| 当前图像、历史图像 | 真实图像预览、历史点击查看 | 工控机从 NINA 二进制接口取图,经鉴权命令链路回传 |
| 缩放、适应、1:1、旋转、十字线 | 浏览器图像工具栏 | 1:1 为预览像素,最大 1280×960,不是传感器全分辨率 |
| 九宫格像差检查 | 预览图中心及边角九宫格 | 基于预览采样,不替代原图像差测量 |
| 图像拉伸、Debayer | 跟随 NINA 或手动 factor / blackClipping / unlinked / debayer | 只影响预览处理,不改原图 |
| 图像历史与 HFR 历史 | 历史列表和 HFR / Stars / Mean / Median / StDev / Temperature 曲线 | 图表使用 NINA 返回值;不编造缺失值 |
| 图像统计 | 原始 NINA 统计字段 | HFR、星点数等要求 NINA 自身完成分析 |
| 直方图 | 本地 8 位预览亮度直方图 | 明确标注为预览,不冒充原始 ADU 直方图 |
| 拍摄、保存开关、中止曝光 | 主控台相机面板 | 图像保存在 NINA 配置目录;接受请求不等于文件已保存 |
| 相机制冷、回温、Binning、读出模式、防露、USB 限速 | 相机控制与附加设置 | 实际支持范围由真实相机驱动决定 |
| 滤镜轮 | 自动读取名称和位置、切换并确认 | 不手输驱动 ID 或猜测滤镜槽位 |
| 电调焦 | 绝对位置、停止、自动对焦、取消、读取 AF 结果 | 对焦曲线原始结果可展开查看 |
| 旋转器 | 位置、机械位置、反转、机械范围、停止 | 设备按名称连接 |
| 赤道仪 | 连接、停放、解除、零位、跟踪、翻转、停止;目标页 Goto 与同步 API | 支持范围来自驱动与 Advanced API |
| 导星 | NINA / PHD2 控制、RA/Dec 曲线、RMS、像素/角秒 | 角秒换算需要 NINA 返回有效 PixelScale |
| 序列 | 状态、开始、停止、重置、原生文件与库管理 | 开始保留 skipValidation=false |
| 开关、天气、安全、平场板、圆顶 | 补充设备面板 | 名称选择连接;开关通道来自真实可写开关列表 |
| 图像解析 | 当前图、历史图、拍摄并解析 | 拍摄解析最长 120 秒曝光;不会自动同步或转向 |
| NINA 画面与日志 | 读取 NINA 截图、最近日志、切到成像页 | 截图不是相机图像 |
以下项目在 NINA 本体源码中存在,但 Advanced API 没有对应控制接口,本次没有宣称完成:原生相机 Live View、ROI 子框、自动 HFR 开关、逐星 HFR 标注、巴氏对焦分析器、自动选取对焦亮星、调焦温度补偿、取消解析、桌面窗口布局控制。也没有把定时刷新预览伪装成相机 Live View。
连续曝光通过 NINA 本地拍摄序列执行;没有引入断线后自动重发的浏览器循环曝光。
若要覆盖上述桌面专属功能,需要另行实现并安装 NINA 扩展插件,不能靠现有 REST 路由假装支持。
图形化生成序列
序列页顶部是图形编辑器。填写计划名称,添加目标,可直接按名称查询工控机 NINA 星表,也可使用目标页已选天体。
坐标输入为 J2000 赤经度数(0..360)与赤纬度数(-90..90),不是赤经小时。多个目标顺序执行。
开始、目标和结束区域均可添加步骤;步骤支持拖动、上移、下移、复制、删除,目标也可调整顺序。
支持的步骤:曝光组、目标转向、解析居中、跟踪设置、自动对焦、开始/停止导星、抖动、等待、制冷、回温、解除停放与停放。
曝光组可选真实滤镜、曝光时间、张数、Gain、Offset、Binning 和帧类型。滤镜 ID 只做接口定位,原生文件使用从 NINA 读回的真实滤镜 Position 和序列化字段。
曝光张数编译为 LoopCondition.Iterations;TakeExposure.ExposureCount 从 0 开始,不把它误用为总张数。
等待时长为秒;温控表单输入秒,生成原生 CoolCamera/WarmCamera.Duration 时转换成分钟。
负赤纬使用 NegativeDec 加有符号 DecDegrees,包含 -0.x° 情况。过中天翻转使用 NINA 自身触发器,需在本机配置翻转参数。
1. “生成 NINA 序列”只编译与校验,显示目标数、曝光张数、纯曝光时间与原生 JSON。
2. “保存到工控机序列库”只保存;“保存并加载”会保存并加载到 NINA,不自动开始。
3. 到主控台或序列监控单独点击“开始”,由 NINA 真实校验后执行。
4. 可导出原生 NINA JSON 或可编辑 .plan.json。草稿也保存在当前浏览器 localStorage。
5. 从序列库读取本工具生成的序列,点击“在图形生成器中编辑”可恢复图形计划,并沿用库条目 revision 更新。
普通 NINA 序列可能包含插件、自定义条件和触发器,不会强行反向转换成有限图形步骤而丢失内容。继续使用原生 JSON 编辑入口。
图形计划嵌入根对象 NinaControlPlan 字段供本工具恢复;NINA 执行的是 Items / Conditions / Triggers 原生结构。
图形器是常用顺序拍摄计划编辑器,不是 NINA 完整节点库:没有并行、嵌套循环编辑、任意插件节点、表达式或完整安全策略的可视化编排。
API
仍使用 POST /api/v1/commands:action=sequence.generate,params={plan:{...}},返回原生 document 和 summary。
它只读取选中滤镜信息,不发送曝光、转向、加载或开始命令。保存继续使用 sequence.create / sequence.update。
新增 image.history / image.preview / image.solve / image.solve_prepared / imaging.capture_solve / application.screenshot / application.logs / application.plugins / application.imaging。
新增 rotator / switch / weather / safetymonitor / flatdevice / dome 的控制路由;通过 GET /api/v1/console/schema 读取表单字段定义。
预览和截图的已完成命令结果仅保留最近 20 个;设备写命令去重记录继续持久保存。
图像以受限尺寸的 data_url 进入原有异步命令结果,不提供任意上游 URL,不开放磁盘路径下载。
所有写操作仍要求独立 API 密钥和 Idempotency-Key。工控机与服务器包必须同时更新。
验证范围
自动化测试覆盖生成文件的循环计数、坐标符号、RA 单位、温控单位、滤镜位置、引用完整性、无曝光/非法步骤拒绝,以及图像流与解析路由。
真实设备、NINA 内部完整反序列化与整夜拍摄仍需在你的工控机验证;当前机器没有 .NET SDK,未编译 NINA 桌面程序。
首次使用先加载生成序列,在 NINA 核对可识别的指令和校验结果,再拍一张短曝光检查保存文件。
源码与文档: