# ReinLoop 功能与接口 本文档描述 `ReinLoop/` Python 客户端当前提供的运行时功能与接口。 ## 约定 - 业务服务端地址由 `REINLOOP_API_URL` 指定,未设置时使用 `REINLOOP_SERVER_URL + /api`。 - 新许可证的设备标识为 `/`,在代码中通过 `api.the_folder` 使用。旧许可证才回退到 `REINLOOP_DEVICE_ID`。 - 所有服务端业务请求均使用 `POST /api`,通过请求体的 `type` 字段分发。 - 公司、产线、许可证签发/撤销、模型删除、审核反馈及配置提交均为 ControlPanel 管理端能力,客户端不提供对应的管理接口。旧微信云函数和其管理脚本 已移除。 ## 应用与设备连接 | 功能 | 接口 | 返回或行为 | | --- | --- | --- | | 启动桌面程序 | `main.main()` | 初始化 PySide6 主窗口、全局日志及异常处理。 | | 连接 MT2-AM8 | `ConnectionManager.connect(tcp_ip, tcp_port, pressure_addr, motor_addr, flowmeter_addr, pressure_range=400, flow_range=100)` | 返回 `bool`。建立 Modbus TCP 连接并保存模拟量通道配置。 | | 断开设备 | `ConnectionManager.disconnect()` | 关闭连接并通知状态回调。 | | 查询连接状态 | `ConnectionManager.is_connected()` | 返回 `bool`。 | | 读取压力 | `ConnectionManager.read_pressure()` | 返回压力值 `kPa`,失败时为 `None`。 | | 读取流量 | `ConnectionManager.read_flow()` | 返回流量 `L/min`;未配置流量计或失败时为 `None`。 | | 设置电机位置 | `ConnectionManager.set_motor_position(xa)` | 将目标行程写入模拟量输出,返回 `bool`。 | | 日志和连接回调 | `set_log_callback(callback)`、`set_status_callback(callback)` | 回调签名分别为 `callback(message)`、`callback(connected, status_text)`。 | 主运行路径使用 `ConnectionManager`。底层调试或独立脚本还可使用 `PcControl.py` 中的 `MT2AM8Client`、`Easy521ModbusClient`、 `MotorModbusRTUClient` 和 `PressureModbusRTUClient`。 ## 压力控制 | 功能 | 接口 | 返回或行为 | | --- | --- | --- | | 创建控制器 | `ControlEngine(pid)` | `pid` 为 `IncrementalPID` 实例。 | | 注入依赖 | `set_connection_manager(mgr)`、`set_model_manager(mgr)`、`set_data_collector(collector)` | 配置设备、RL 模型和数据采集服务。 | | 启动控制 | `ControlEngine.start()` | 要求设备已连接;RL 模式还要求模型已加载。 | | 执行一个周期 | `ControlEngine.control_tick()` | 读取压力、执行 PID/RL/手动控制、写入电机并更新显示。由 GUI 的 QTimer 调用。 | | 停止控制 | `ControlEngine.stop()` | 停止循环,并触发 `DataCollector.finalize_and_upload()`。 | | 查询运行状态 | `ControlEngine.is_running` | 只读属性,返回 `bool`。 | | 切换模式 | `engine.mode = "PID" / "RL" / "MANUAL"` | PID 闭环、RL 调参增强闭环或直接设置阀门开度。 | | 更新 PID 参数 | `IncrementalPID.update_parameters(kp, ki, kd)` | 重算增量 PID 系数。 | | 执行 PID 单步 | `IncrementalPID.update_pressure_values(current, target)`、`update(du_max=None)` | `update()` 返回受限后的阀门开度百分比。 | | 重置 PID 状态 | `IncrementalPID.reset()` | 清除误差历史与输出状态。 | | 设置单步限幅 | `IncrementalPID.set_du_max(value)` | 设置 PID 输出增量上限。 | `ControlEngine` 的常用配置字段包括 `target_pressure`、`flow`、`volume`、 `manual_valve`、`collect_data`、`dz`、`motor_max`、`xa_full` 和 `pressure_alpha`。 ## RL 模型管理 | 功能 | 接口 | 服务端请求 | | --- | --- | --- | | 刷新模型列表 | `ModelManager.scan_models()` | `listModels`,目录为 `/model_config`。异步执行。 | | 加载 SAC 模型 | `ModelManager.load_model(model_name)` | `downloadModel` 获取临时 URL,再下载并以 `SAC.load()` 加载。 | | 检查模型状态 | `ModelManager.is_model_loaded()` | 返回 `bool`。 | | 回调注册 | `set_models_loaded_callback(callback)`、`set_load_complete_callback(callback)` | 回调签名分别为 `callback(file_names)`、`callback(success, message)`。 | RL 模式下,`ControlEngine` 使用模型根据流量、当前压力和压力误差预测 `Kp/Ki`,随后继续使用 PID 计算阀门开度。 ## 控制过程数据采集与上传 | 功能 | 接口 | 返回或行为 | | --- | --- | --- | | 初始化一轮采集 | `DataCollector.reset()` | 清空 Episode 缓存。 | | 记录控制点 | `DataCollector.record_step(cycle_count, current_pressure, target_pressure, valve_opening, kp, ki, kd, q_in, v)` | 目标压力变化时自动切分 Episode。 | | 停止后异步上传 | `DataCollector.finalize_and_upload(flow, vol)` | 分片上传 Pickle 数据和 manifest 到 `/data_record/...`。 | | 上传凭证与直传 | `DataCollector._upload_to_cos(data_bytes, filename, folder)` | 内部接口;先请求上传凭证,再将对象直传。 | 上传地址通过服务端 `uploadDataFile` 获取。单个 Episode 数据文件超过约 5 MB 时会自动拆分。 ## 系统辨识 | 功能 | 接口 | 返回或行为 | | --- | --- | --- | | 下载辨识配置 | `download_identification_config(timeout=20)` | 下载并返回已校验的九参数配置字典。 | | 校验配置对象 | `validate_identification_config(config)` | 规范化后返回字典,非法参数抛出 `ValueError`。 | | 解析配置 CSV | `parse_identification_config_csv(csv_text)` | 解析 `parameter,value` 两列 CSV 并完成校验。 | | 启动辨识 | `IdentificationManager.start_identification(conn_mgr=..., running_flag_check=..., q_in_val=..., dt=..., n_order=..., t_c=..., levels=..., dead_area=..., xa_full=..., V_val=..., repeat=2)` | 返回 `bool`;后台依次执行行程预扫描、PRBS 采集并上传 CSV。 | | 停止辨识 | `IdentificationManager.stop()` | 请求正在运行的辨识/容积任务停止。 | | 查询任务状态 | `IdentificationManager.is_running` | 返回 `bool`。 | | 生成 PRBS | `generate_prbs(n_order=7, low_val=40, high_val=60, samples_per_bit=20, levels=None)` | 返回 NumPy 激励序列。 | | 生成复合激励 | `generate_composite_sequence(dt, n_order, t_c, levels)` | 返回闭阀、全开和多电平 PRBS 组合序列。 | | 执行 PRBS 采集 | `collect_data_with_prbs(conn_mgr, q_in_val, dt=0.05, n_order=7, t_c=1.0, levels=None, dead_area=240, xa_full=1062.5, V_val=None, should_stop=None, log=print, on_sample=None, repeat=2)` | 返回含 `t`、`u`、`p`、`csv_data`、`filename`、`samples` 和 `success` 的字典。 | 辨识流程会先按 `1000` 到 `0` 的行程档位扫描稳定压力,将结果上传到 `/ind_data`;随后上传 PRBS CSV 到同一目录。 ### 辨识审核反馈 | 功能 | 接口 | 服务端请求 | 返回 | | --- | --- | --- | --- | | 登记结果 | `register_identification_result(run_id, timeout=10)` | `registerIdentificationResult` | 成功时返回 `None`。 | | 查询审核 | `get_identification_feedback(run_id, timeout=10)` | `getIdentificationFeedback` | 未就绪返回 `None`;就绪返回 `0` 或 `1`。 | | 确认清理 | `acknowledge_identification_feedback(run_id, timeout=10)` | `ackIdentificationFeedback` | 成功时返回 `None`。 | ## 容积测量 | 功能 | 接口 | 返回或行为 | | --- | --- | --- | | 读取本地配置 | `load_volume_config(path=None)` | 读取 JSON 并返回八参数配置。 | | 校验配置 | `validate_volume_config(config)` | 返回规范化配置;错误时抛出 `ValueError`。 | | 执行单次测量 | `measure_volume(conn_mgr, q_in_slm=50.0, dt=0.1, xa=1000, p_max=200.0, fit_low=50.0, fit_high=150.0, T_delta=30.0, should_stop=None, log=print, on_sample=None)` | 返回拟合斜率、截距、`c1`、`volume_L`、原始压力曲线和 `success`。 | | 启动多次测量 | `IdentificationManager.start_volume_measurement(conn_mgr=..., running_flag_check=..., q_in_val=..., dt=..., p_max=..., fit_low=..., fit_high=..., T_delta=..., xa_full=1000, num_runs=3)` | 返回 `bool`;后台多次测量、计算平均值并上传 JSON。 | | 创建配置请求 | `create_volume_config_request(timeout=10)` | 返回 `{"request_id", "expires_at_ms"}`。 | | 查询配置请求 | `poll_volume_config_request(request_id, timeout=10)` | 返回 `{"ready", "expired"}`;就绪时额外包含 `config`。 | | 确认配置请求 | `acknowledge_volume_config_request(request_id, timeout=10)` | 成功时返回 `None`。 | 容积测量汇总结果上传到 `/V_config`。容积参数请求与确认是客户端和 ControlPanel 的一次性协作流程。 ## 许可证与设备标识 | 功能 | 接口 | 返回或行为 | | --- | --- | --- | | 本地验签 | `verify_license(lic_path=None)` | 验证 RSA-PSS/SHA-256 签名、载荷和有效期,返回许可证载荷。 | | 启动许可证检查 | `check_license(lic_path=None)` | 本地校验、在线校验并启动唯一的后台巡检线程;失败时退出程序。 | | 获取已验证载荷 | `get_verified_license()` | 返回缓存载荷副本,未验证时返回 `None`。 | | 在线校验 | `validate_license_online(payload)` | 调用 `validateLicense`;明确无效时抛出 `ExpiredError`。 | | 启动后台巡检 | `start_license_watchdog(interval_minutes=5)` | 幂等启动,最短巡检间隔为 5 分钟。 | | 注册生命周期回调 | `set_on_expired(callback)`、`set_on_grace(callback)`、`set_on_log(callback)` | 接收失效信息、宽限期小时数或许可证日志。 | 新许可证必须包含 `license_id`、`company_id`、`production_line_id`、 `device_id`。`device_id` 必须是两个安全路径段组成的 `/`。旧许可证仍可本地验签,但不支持在线撤销。 网络故障不会立即中断控制;离线时限由 `REINLOOP_LICENSE_OFFLINE_HOURS` 配置,默认 72 小时。 ## 客户端服务端协议 所有业务请求都发送至 `POST /api`。业务成功响应应至少包含 `success: true`。 | `type` | 请求关键字段 | 用途 | | --- | --- | --- | | `validateLicense` | `licenseId`, `deviceId` | 校验许可证是否为 `active` 状态。 | | `listModels` | `folder` | 列出 `/model_config` 中的模型。 | | `downloadModel` | `fileID` | 获取模型临时下载 URL。 | | `uploadDataFile` | `fileName`, `folder` | 获取对象存储直传凭证。 | | `getIdentificationConfig` | `deviceId` | 获取九项辨识参数 CSV 的下载 URL。 | | `registerIdentificationResult` | `deviceId`, `runId`, `fileName` | 登记待审核的辨识 CSV。 | | `getIdentificationFeedback` | `deviceId`, `runId` | 查询辨识审核结果。 | | `ackIdentificationFeedback` | `deviceId`, `runId` | 确认并清理已消费的审核结果。 | | `createVolumeConfigRequest` | `deviceId` | 创建一次性容积配置请求。 | | `getVolumeConfigRequest` | `deviceId`, `requestId` | 查询请求状态;就绪时取得配置下载 URL。 | | `ackVolumeConfigRequest` | `deviceId`, `requestId` | 确认或清理容积配置请求。 | ## 配置环境变量 | 变量 | 用途 | | --- | --- | | `REINLOOP_SERVER_URL` | 服务端根地址。 | | `REINLOOP_API_URL` | 完整 API 地址,优先级高于根地址。 | | `REINLOOP_DEVICE_ID` | 旧许可证或开发测试设备标识;新许可证中必须与 `device_id` 一致。 | | `REINLOOP_LICENSE_OFFLINE_HOURS` | 许可证在线校验的最大离线时长,默认 `72`。 | | `REINLOOP_VOLUME_CONFIG` | 本地容积配置 JSON 的覆盖路径。 |