单片机互通调试(未完成)
This commit is contained in:
@@ -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; // 重新抛出异常,以便事务回滚
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user