单片机互通调试(未完成)

This commit is contained in:
2025-05-26 22:52:17 +08:00
parent 17cbec048e
commit 22e1109d81
5 changed files with 249 additions and 187 deletions

View File

@@ -17,14 +17,19 @@ import org.springframework.transaction.annotation.Transactional;
import java.nio.charset.StandardCharsets;
import java.util.Date;
/**
* MQTT 服务实现类
* 负责向 MQTT Broker 发送指令给机器人/设备
*/
@Service
@Slf4j
public class MqttServiceImpl implements MqttService {
private final MqttClient mqttClient; // Autowired by Spring from MqttConfig
private final MqttProperties mqttProperties;
private final RobotTaskService robotTaskService;
private final MqttClient mqttClient; // 由Spring从MqttConfig注入的MQTT客户端实例
private final MqttProperties mqttProperties; // MQTT相关的配置属性
private final RobotTaskService robotTaskService; // 机器人任务服务,用于创建和更新任务状态
// 构造函数注入依赖
public MqttServiceImpl(@Qualifier("mqttClientBean") MqttClient mqttClient,
MqttProperties mqttProperties,
RobotTaskService robotTaskService) {
@@ -33,67 +38,79 @@ public class MqttServiceImpl implements MqttService {
this.robotTaskService = robotTaskService;
}
/**
* 发送指令给指定的机器人/设备
*
* @param robotId 目标机器人的唯一标识符
* @param commandType 指令类型 (枚举)
* @param payloadJson 指令的JSON格式负载
* @param sessionId (可选) 与此指令关联的充电会话ID
* @return 指令是否发送成功 (注意这仅表示MQTT消息已发布不代表设备已执行)
* @throws Exception 如果发送过程中发生MQTT异常或其他意外异常
*/
@Override
@Transactional(rollbackFor = Exception.class) // Ensure rollback if MQTT publish fails after task creation
@Transactional(rollbackFor = Exception.class) // 如果MQTT发布失败或后续操作失败确保事务回滚例如任务创建
public boolean sendCommand(String robotId, CommandTypeEnum commandType, String payloadJson, Long sessionId) throws Exception {
log.info("Attempting to send command {} to robot {} with payload: {}", commandType, robotId, payloadJson);
log.info("尝试向机器人 {} 发送指令 {},负载: {}", commandType, robotId, payloadJson);
// 1. Check if the robot has pending or already sent tasks
// 步骤1首先检查机器人是否已有正在处理(PENDING)或已发送(SENT)的任务
if (robotTaskService.hasPendingOrSentTask(robotId)) {
// 添加优先级处理STOP_CHARGE 命令应该可以覆盖其他任务
// 特殊处理STOP_CHARGE (停止充电) 指令具有高优先级,可以覆盖其他任务
if (CommandTypeEnum.STOP_CHARGE.equals(commandType)) {
log.info("Robot {} has pending tasks, but STOP_CHARGE is a priority command, proceeding anyway.", robotId);
log.info("机器人 {} 有正在处理的任务,但 STOP_CHARGE 是优先指令,继续执行。", robotId);
} else {
log.warn("Robot {} is busy (has PENDING or SENT tasks). Command {} aborted.", robotId, commandType);
return false;
log.warn("机器人 {} 正忙 (存在PENDING或SENT状态的任务),指令 {} 已中止。", robotId, commandType);
return false; // 机器人忙,不发送新指令 (除非是停止指令)
}
}
// 2. Create a new task in PENDING state
// 步骤2如果机器人不忙或指令是STOP_CHARGE再创建新任务
RobotTask task = robotTaskService.createTask(robotId, commandType, payloadJson, sessionId);
if (task == null || task.getId() == null) {
log.error("Failed to create RobotTask for command {} to robot {}. Aborting send.", commandType, robotId);
return false;
log.error("为机器人 {} 的指令 {} 创建RobotTask失败。发送操作中止。", commandType, robotId);
return false; // 任务创建失败,不继续发送
}
log.info("Created PENDING RobotTask with ID: {} for command {} to robot {}.", task.getId(), commandType, robotId);
log.info("已为机器人 {} 的指令 {} 创建 PENDING 状态的 RobotTask任务ID: {}。", commandType, robotId, task.getId());
// 3. Construct the topic
// 3. 构建目标MQTT主题
// 主题格式: [mqttProperties.commandTopicBase]/[robotId]
// 例如: yupi_mqtt_power_project/robot/command/ESP32_SPOT_001
String topic = mqttProperties.getCommandTopicBase() + "/" + robotId;
// 4. Prepare the MQTT message
String effectivePayload = (payloadJson == null) ? "" : payloadJson;
// 4. 准备MQTT消息
String effectivePayload = (payloadJson == null) ? "" : payloadJson; // 确保payload不为null
MqttMessage mqttMessage = new MqttMessage(effectivePayload.getBytes(StandardCharsets.UTF_8));
mqttMessage.setQos(mqttProperties.getDefaultQos());
// mqttMessage.setRetained(false); // Default is false
mqttMessage.setQos(mqttProperties.getDefaultQos()); // 设置QoS级别从配置中读取
// mqttMessage.setRetained(false); // 保留消息标志默认为false通常指令不需要保留
try {
// 5. Publish the message
// 5. 发布MQTT消息
if (!mqttClient.isConnected()) {
log.error("MQTT client is not connected. Cannot send command {} to robot {}. Task ID: {}", commandType, robotId, task.getId());
// Task remains PENDING. A scheduled job might retry or mark as error later.
log.error("MQTT客户端未连接。无法向机器人 {} 发送指令 {}。任务ID: {}", commandType, robotId, task.getId());
// 任务将保持PENDING状态。后续可由定时任务重试或标记为错误。
return false;
}
log.debug("Publishing to topic: {}, QoS: {}, Payload: {}", topic, mqttMessage.getQos(), effectivePayload);
log.debug("正在向主题发布消息: {}, QoS: {}, 负载: {}", topic, mqttMessage.getQos(), effectivePayload);
mqttClient.publish(topic, mqttMessage);
log.info("Successfully published command {} to robot {} on topic {}. Task ID: {}", commandType, robotId, topic, task.getId());
log.info("成功向机器人 {} 在主题 {} 上发布指令 {}。任务ID: {}", commandType, robotId, topic, task.getId());
// 6. Mark the task as SENT
// 6. 将机器人任务的状态标记为 SENT (已发送)
boolean markedAsSent = robotTaskService.markTaskAsSent(task.getId(), new Date());
if (!markedAsSent) {
log.warn("Command {} published to robot {}, but failed to mark task {} as SENT. System might be in an inconsistent state.",
log.warn("指令 {} 已发布给机器人 {},但将任务 {} 标记为 SENT 失败。系统可能处于不一致状态。",
commandType, robotId, task.getId());
// This is a critical warning. The command was sent, but DB state doesn't reflect it.
// 这是一个严重警告。指令已发送,但数据库状态未正确反映。
}
return true; // Command sent and task status update was attempted
return true; // 指令已发送,并尝试更新了任务状态
} catch (MqttException e) {
log.error("MqttException while publishing command {} to robot {} (Task ID: {}). Error: {}",
log.error("向机器人 {} 发布指令 {} (任务ID: {}) 时发生MqttException。错误: {}",
commandType, robotId, task.getId(), e.getMessage(), e);
// The RobotTask remains PENDING. A retry mechanism or a timeout job could handle this later.
throw e; // Re-throw for transactional rollback
// RobotTask 将保持 PENDING 状态。重试机制或超时任务后续可以处理此问题。
throw e; // 重新抛出异常以便Spring的@Transactional进行事务回滚
} catch (Exception e) {
log.error("Unexpected exception while sending command {} to robot {} (Task ID: {}). Error: {}",
log.error("向机器人 {} 发送指令 {} (任务ID: {}) 时发生意外异常。错误: {}",
commandType, robotId, task.getId(), e.getMessage(), e);
throw e; // Re-throw for transactional rollback
throw e; // 重新抛出异常,以便事务回滚
}
}
}