Files
mqtt_power/LogBook.md
2025-06-07 21:37:31 +08:00

14 KiB
Raw Blame History

变更日志

YYYY-MM-DD

  • 初始化项目变更日志。
  • 确认采用 Gitea Webhook + Shell 脚本的 CI/CD 方案。
  • 部署脚本 (deploy.sh) 和相关配置已准备。

YYYY-MM-DD (请替换为实际日期)

  • 详细分析了项目整体结构,特别是单片机 (mqtt_esp32_client.ino) 与后端 (springboot-init-main) 之间基于 README.md 的 MQTT 通信流程和协议。
  • 核心理解:
    • 主题:
      • 上行 (设备 -> 后端): yupi_mqtt_power_project/robot/status/{spotUid} (状态/心跳/ACK)
      • 下行 (后端 -> 设备): yupi_mqtt_power_project/robot/command/{spotUid} (指令)
    • 消息格式: JSON。上行消息结构对应后端 com.yupi.project.model.dto.mqtt.RobotStatusMessage
    • 关键上行消息字段: robotUid, actualRobotStatus, taskId (for ACK), status (for ACK), activeTaskId (通常为 sessionId)。
    • 关键下行消息字段: commandType ("START_CHARGE", "STOP_CHARGE", 等), taskId, sessionId (for "START_CHARGE")。
    • 通信流程: 设备连接后订阅指令主题并上报初始状态。周期性上报状态和心跳。后端下发指令设备执行后通过ACK响应并更新状态。
    • activeTaskId 的作用: 该字段在单片机的状态上报和ACK中被用来传递当前有效的 sessionId,对于后端跟踪会话状态至关重要。
    • 单片机代码中包含对 MOVE_TO_SPOT 指令的处理,README.md 未明确列出,后端可能需同步支持。
  • 后续 Debug 将基于此理解进行。

YYYY-MM-DD (请替换为今天的实际日期)

  • 核心逻辑变更:"到达即充电"
    • 移除了原先设想的由后端发送 START_CHARGE MQTT 指令来启动充电的流程。
    • 新流程:机器人(单片机)在执行 MOVE_TO_SPOT 指令并成功到达车位后,立即将自身状态更新为 CHARGING 并上报。后端在收到 MOVE_TO_SPOT 任务的 ACK (其中应包含机器人已是 CHARGING 状态) 后将机器人DB状态更新为 CHARGING,并将充电会话状态更新为 CHARGING_STARTED
  • 代码修改:
    • mqtt_esp32_client.ino:
      • MOVE_TO_SPOT 指令处理逻辑修改:
        • 收到指令后,状态变为 MOVING 并上报。
        • 模拟移动到达后,状态变为 CHARGING
        • 发送的 ACK 消息中 actualRobotStatus 反映为 CHARGING
        • 再次上报 CHARGING 状态。
    • ChargingSessionServiceImpl.java:
      • handleRobotArrival 方法修改:
        • MOVE_TO_SPOT 任务完成后,将充电会话状态 (ChargingSession.status) 直接更新为 CHARGING_STARTED
        • 记录 robotArrivalTimechargeStartTime
        • 将数据库中机器人状态 (ChargingRobot.status) 更新为 CHARGING
        • 确保关联的 RobotTask (移动任务) 被正确处理和完成。
    • README.md:
      • 更新了MQTT通信约定、消息示例、单片机开发关键逻辑以及示例充电流程以反映"到达即充电"的新业务规则。
  • 待考虑/后续:
    • ChargingSessionServiceImpl.handleChargingStart 方法目前因 START_CHARGE 指令不再由后端主动发送而可能不再被主要流程调用,其定位和用途需要进一步明确或在未来重构中调整。
    • 前端界面和用户交互流程可能需要相应调整,以匹配后端"到达即充电"的逻辑(例如,可能不再需要用户在机器人到达后点击"开始充电"按钮)。

YYYY-MM-DD (自动填充日期)

ESP32 固件与后端通信逻辑校准与文档更新

主要变更点:

  1. MQTT ACK 消息格式校准 (关键):

    • 问题分析: 通过深入分析后端代码 (MqttMessageHandlerImpl.javaCommandTypeEnum.java)发现后端期望的MQTT ACK消息格式与之前README.md及单片机固件发送的格式存在显著差异。
      • 后端期望ACK中包含 command_ack 字段,其值为指令的中文描述 (例如 "移动到指定点"),用于 CommandTypeEnum.fromAck() 方法匹配。
      • 后端期望任务ID字段为 task_id (数字类型)。
      • 后端期望成功状态字段为 success (布尔类型)。
    • README.md 更新: 已更新 README.md (4.2.1节) 中的ACK消息示例以准确反映后端期望的格式。包括添加了 command_ack,并将 taskId 改为 task_idstatus (String) 改为 success (Boolean)。
    • 行动项 (开发者): 开发者需要修改 esp32_robot_firmware/mqtt_handler.cpp 中的 mqtt_publish_ack 函数使其发送的ACK JSON符合后端 MqttMessageHandlerImpl.java 的实际解析逻辑 (即包含中文描述的 command_ack,数字类型的 task_id,和布尔类型的 success)。
  2. MQTT 下行 MOVE_TO_SPOT 指令校准:

    • 问题分析: 后端 ChargingSessionServiceImpl.java 在发送移动指令时实际使用的payload是 {"command":"MOVE", ...},而 README.md 先前示例为 {"commandType":"MOVE_TO_SPOT", ...}
    • README.md 更新: 已更新 README.md (4.2.2节) 中移动指令的示例,以反映后端实际发送的 command: "MOVE"格式,并添加了说明指出单片机固件已做兼容处理。
    • 行动项 (开发者, 可选): 为保持一致性,可考虑更新后端 ChargingSessionServiceImpl.java,使其发送移动指令时使用 commandType: "MOVE_TO_SPOT"
  3. 文档整体一致性提升:

    • README.md 中关于单片机处理逻辑 (4.3节) 和示例流程 (4.4节) 的部分也相应作了调整以强调新的ACK格式要求和指令细节。

代码分析涉及文件:

  • springboot-init-main/src/main/java/com/yupi/project/service/impl/ChargingSessionServiceImpl.java (下行指令发送)
  • springboot-init-main/src/main/java/com/yupi/project/service/impl/MqttServiceImpl.java (下行指令封装与 taskId 注入)
  • springboot-init-main/src/main/java/com/yupi/project/mqtt/handler/MqttMessageHandlerImpl.java (上行消息及ACK处理核心逻辑)
  • springboot-init-main/src/main/java/com/yupi/project/model/enums/CommandTypeEnum.java (ACK中command_ack的解析方式)
  • esp32_robot_firmware/mqtt_handler.cpp (单片机ACK发送逻辑 - 需修改)
  • esp32_robot_firmware/esp32_robot_firmware.ino (单片机指令回调处理)

后续影响与建议:

  • 首要任务是修正单片机固件的ACK发送逻辑,确保与后端正确对接。
  • 在完成固件修改后建议进行完整的MQTT通信测试覆盖所有指令类型及其ACK流程。

2025-05-24: 后端会话管理核心逻辑强化

主要变更与决策:

  1. 明确用户充电请求流程与并发处理:

    • 用户请求充电时 (ChargingSessionController.requestCharging -> ChargingSessionServiceImpl.requestCharging -> assignRobotToSession),系统会检查车位可用性、用户状态,并尝试分配空闲机器人。
    • 机器人分配机制: ChargingRobotServiceImpl.assignIdleRobot() 负责查找空闲机器人并将其状态更新为 MOVING (或类似表示已分配的状态)。此操作与会话创建、车位预定、任务创建均在一个事务内。
    • 机器人繁忙处理: 如果没有空闲机器人,assignRobotToSession 将返回 null,随后 requestCharging 方法会将此会话标记为 CANCELLED_BY_SYSTEM 并向用户抛出明确的"无可用机器人"或"机器人繁忙"的错误。系统不会为此类请求创建等待执行的 RobotTask,用户需稍后重试。这简化了后端的任务管理和状态维护。
  2. MQTT 指令发送与任务状态同步 (MqttServiceImpl.sendCommand):

    • 任务预创建: sendCommand 方法要求调用者 (如 ChargingSessionServiceImpl) 必须预先创建状态为 PENDINGRobotTask并将任务ID (associatedTaskId) 传递给 sendCommand
    • 机器人繁忙校验: 在发送指令前,sendCommand 会调用 RobotTaskServiceImpl.hasOtherPendingOrSentTask() 检查目标机器人是否已有其他 PENDINGSENT 状态的任务(排除当前 associatedTaskId)。若是,则通常中止发送(STOP_CHARGE 指令除外,它具有优先权)。
    • Payload 增强: sendCommand 会自动向发送的MQTT JSON payload 中添加 taskId 字段,其值为 associatedTaskId。这有助于机器人端将ACK消息与特定任务关联。
    • 事务与数据一致性: sendCommand 标记为 @Transactional
      • MQTT消息成功发布后会调用 RobotTaskServiceImpl.markTaskAsSent() 将对应任务状态从 PENDING 更新为 SENT
      • 为确保数据一致性避免MQTT已发送但任务状态更新失败RobotTaskServiceImpl.markTaskAsSent() 方法已被修改:在其无法成功将任务标记为 SENT如任务不存在、原状态非PENDING、数据库更新失败会抛出 BusinessException。此异常会触发 sendCommand 所在事务的回滚从而撤销MQTT发送如果尚未实际完成网络传输或至少确保数据库层面的一致性。
  3. 会话状态流转与MQTT消息处理 (初步对齐):

    • "到达即充电"逻辑: 当前遵循此简化逻辑。当 MOVE_TO_SPOT 任务成功被机器人ACK后ChargingSessionServiceImpl.handleRobotArrival() 会直接将会话状态更新为 CHARGING_STARTED
    • MqttMessageHandler 在收到机器人的状态回报(特别是包含 taskId 的ACK会首先调用 RobotTaskService 更新任务状态,然后基于任务结果调用 ChargingSessionService 的相应方法来驱动会话状态的变更。
  4. 兼容性考虑:

    • 当前的修改重点在于增强后端逻辑的健壮性和数据一致性同时尽量维持现有的MQTT消息JSON结构 (仅在payload中增加 taskId,这是一个向后兼容的增强) 和主要的业务流程,以避免对前端和单片机代码产生破坏性变更。
    • MQTT指令名称 (如 MOVE vs MOVE_TO_SPOT) 与 CommandTypeEnum 的映射关系需要在后端处理,以适应单片机固件的期望。

后续关注点:

  • 详细实现 ChargingSessionService 中处理充电结束、取消、错误、超时的逻辑。
  • 设计和实现计费服务。
  • 确保 MqttMessageHandler 中对所有预期机器人回报的完整处理和对 ChargingSessionService 的正确调用。
  • 审阅并完善所有相关的 @Transactional 注解,确保事务边界和传播行为的正确性。

YYYY-MM-DD (请替换为今天的实际日期)

  • 新建 Arduino Nano 循迹避障项目 arduino_nano_tracker
    • 目标:实现单片机控制的循迹和避障功能。
    • 硬件配置:
      • TT 电机 x2 (PWM控制转速): 左电机引脚 9, 右电机引脚 10。
      • TRCT5000 循迹传感器 x2: 左传感器引脚 7, 右传感器引脚 8。
      • 超声波传感器 (HC-SR04): Trig 引脚 12, Echo 引脚 11。
      • 180度舵机 (SG90): 引脚 3。
    • arduino_nano_tracker/ 目录下创建了 arduino_nano_tracker.ino 文件,并包含基础的引脚定义和 setup()/loop() 结构。

YYYY-MM-DD (请替换为今天的实际日期)

  • 前端接口路径修复:
    • 修复了 charging_web_appmy-sessions 页面 (charging_web_app/src/app/(authenticated)/my-sessions/page.tsx) 获取用户充电记录列表的接口调用。
    • 问题:原请求路径为 /session/my/list/page,缺少了 API 代理前缀 /api
    • 解决:将请求路径修改为 /api/session/my/list/page,确保请求能正确通过 Next.js 代理到后端服务。

YYYY-MM-DD (请替换为今天的实际日期)

  • 管理员会话管理功能方案调整:
    • 根据决策,从《第五阶段:管理员会话管理功能开发方案》(springboot-init-main/doc/development_stages/stage_5_admin_session_management.md) 中移除了管理员直接删除充电会话的功能。
    • 主要移除内容包括相关的后端 Service 方法、Controller 接口定义以及前端对应的操作按钮和API调用封装。
    • 此举旨在降低误操作风险并保留完整的数据记录。
  • 前端管理员控制台界面调整:
    • 从管理员控制台页面 (charging_web_app/src/app/(authenticated)/admin/dashboard/page.tsx) 移除了"会话管理"导航卡片按钮,以匹配后端不再提供管理员直接删除会话功能的调整。

YYYY-MM-DD (请替换为今天的实际日期)

  • 新建 MG995 舵机测试项目 mg995_servo_test
    • 目标:测试 MG995 舵机与 ESP32-S3 的集成。
    • 硬件配置:
      • 主控ESP32-S3
      • 舵机MG995
      • 连接引脚:舵机信号线连接到 GPIO 18。
    • mg995_servo_test/ 目录下创建了 mg995_servo_test.ino 文件,实现了舵机在 0-180 度之间往复运动的测试程序。

YYYY-MM-DD (请替换为今天的实际日期)

  • 新建 Arduino Nano 的 MG995 舵机测试项目 mg995_nano_test
    • 目标:将舵机控制方案切换到 Arduino Nano 平台。
    • 硬件配置:
      • 主控Arduino Nano
      • 舵机MG995
      • 连接引脚:舵机信号线连接到 Nano 的 D9 PWM 引脚。
    • mg995_nano_test/ 目录下创建了 mg995_nano_test.ino 文件,使用标准 Servo.h 库实现舵机往复运动。
    • 重要提示:同样需要为 MG995 舵机提供独立的 5V 外部电源,并与 Nano 共地。

YYYY-MM-DD (请替换为今天的实际日期)

  • Fix: 修复了在充电会话结束时,由于在 calculateCostAndFinalizeSession 方法中存在冗余的车位状态检查和更新逻辑导致在特定事务场景下产生非法SQL语句 (UPDATE parking_spot 缺少 SET 子句) 的严重BUG。
  • Refactor: 重构了 ChargingSessionServiceImpl,将车位释放的逻辑完全保留在 handleChargingEnd 方法中,确保 calculateCostAndFinalizeSession 只负责计费,遵循单一职责原则,提高了代码的健壮性和可维护性。