2025-12-16 14:37:16 +08:00
|
|
|
|
package com.tuoheng.machine.config;
|
2025-12-16 13:47:32 +08:00
|
|
|
|
|
2025-12-16 14:37:16 +08:00
|
|
|
|
import com.tuoheng.machine.events.DroneEvent;
|
|
|
|
|
|
import com.tuoheng.machine.platform.factory.PlatformStrategyFactory;
|
|
|
|
|
|
import com.tuoheng.machine.platform.strategy.DronePlatformStrategy;
|
|
|
|
|
|
import com.tuoheng.machine.status.DroneState;
|
2025-12-16 17:40:31 +08:00
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
2025-12-16 13:47:32 +08:00
|
|
|
|
import org.springframework.context.annotation.Bean;
|
|
|
|
|
|
import org.springframework.context.annotation.Configuration;
|
|
|
|
|
|
import org.springframework.statemachine.StateMachine;
|
|
|
|
|
|
import org.springframework.statemachine.config.StateMachineBuilder;
|
|
|
|
|
|
import org.springframework.statemachine.config.StateMachineFactory;
|
|
|
|
|
|
|
|
|
|
|
|
import java.util.EnumSet;
|
|
|
|
|
|
import java.util.UUID;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 无人机状态机配置(多平台支持版本)
|
|
|
|
|
|
* 通过PlatformStrategyFactory动态获取平台特定的Guard、Action和Listener
|
|
|
|
|
|
*/
|
|
|
|
|
|
@Configuration
|
2025-12-16 17:40:31 +08:00
|
|
|
|
@Slf4j
|
2025-12-16 13:47:32 +08:00
|
|
|
|
public class DroneMachineConfig {
|
|
|
|
|
|
|
|
|
|
|
|
@Bean(name = "droneStateMachineFactory")
|
2025-12-16 15:01:38 +08:00
|
|
|
|
public StateMachineFactory<DroneState, DroneEvent> droneStateMachineFactory(
|
|
|
|
|
|
PlatformStrategyFactory platformStrategyFactory) throws Exception {
|
2025-12-16 13:47:32 +08:00
|
|
|
|
return new StateMachineFactory<DroneState, DroneEvent>() {
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public StateMachine<DroneState, DroneEvent> getStateMachine() {
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public StateMachine<DroneState, DroneEvent> getStateMachine(String machineId) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 根据无人机SN获取平台策略
|
|
|
|
|
|
DronePlatformStrategy strategy = platformStrategyFactory.getDroneStrategy(machineId);
|
|
|
|
|
|
|
|
|
|
|
|
StateMachineBuilder.Builder<DroneState, DroneEvent> builder = StateMachineBuilder.builder();
|
|
|
|
|
|
configureStateMachine(builder, strategy);
|
|
|
|
|
|
configureStates(builder);
|
|
|
|
|
|
configureTransitions(builder, strategy);
|
|
|
|
|
|
|
|
|
|
|
|
StateMachine<DroneState, DroneEvent> stateMachine = builder.build();
|
|
|
|
|
|
stateMachine.getExtendedState().getVariables().put("machineId", machineId);
|
|
|
|
|
|
return stateMachine;
|
|
|
|
|
|
} catch (Exception e) {
|
2025-12-16 17:40:31 +08:00
|
|
|
|
log.error("创建DRONE状态机失败 - 机器ID: {}", machineId, e);
|
2025-12-16 13:47:32 +08:00
|
|
|
|
throw new RuntimeException("Failed to create drone state machine for: " + machineId, e);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public StateMachine<DroneState, DroneEvent> getStateMachine(UUID uuid) {
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void configureStateMachine(
|
|
|
|
|
|
StateMachineBuilder.Builder<DroneState, DroneEvent> builder,
|
|
|
|
|
|
DronePlatformStrategy strategy) throws Exception {
|
|
|
|
|
|
builder.configureConfiguration()
|
|
|
|
|
|
.withConfiguration()
|
|
|
|
|
|
.autoStartup(true)
|
|
|
|
|
|
.listener(strategy.getListener());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void configureStates(StateMachineBuilder.Builder<DroneState, DroneEvent> builder) throws Exception {
|
|
|
|
|
|
builder.configureStates()
|
|
|
|
|
|
.withStates()
|
|
|
|
|
|
.initial(DroneState.UNKNOWN)
|
|
|
|
|
|
.states(EnumSet.of(
|
|
|
|
|
|
DroneState.UNKNOWN,
|
|
|
|
|
|
DroneState.OFFLINE,
|
|
|
|
|
|
DroneState.PREPARING,
|
|
|
|
|
|
DroneState.FLYING_PARENT,
|
|
|
|
|
|
DroneState.RETURNING_PARENT,
|
|
|
|
|
|
DroneState.POINTING_PARENT
|
|
|
|
|
|
))
|
|
|
|
|
|
// 飞行阶段子状态
|
|
|
|
|
|
.and()
|
|
|
|
|
|
.withStates()
|
|
|
|
|
|
.parent(DroneState.FLYING_PARENT)
|
|
|
|
|
|
.initial(DroneState.FLYING)
|
|
|
|
|
|
.states(EnumSet.of(
|
|
|
|
|
|
DroneState.FLYING,
|
|
|
|
|
|
DroneState.EMERGENCY_STOP,
|
|
|
|
|
|
DroneState.ARRIVED
|
|
|
|
|
|
))
|
|
|
|
|
|
// 返航阶段子状态
|
|
|
|
|
|
.and()
|
|
|
|
|
|
.withStates()
|
|
|
|
|
|
.parent(DroneState.RETURNING_PARENT)
|
|
|
|
|
|
.initial(DroneState.RETURNING)
|
|
|
|
|
|
.states(EnumSet.of(
|
|
|
|
|
|
DroneState.RETURNING,
|
|
|
|
|
|
DroneState.RETURN_EMERGENCY_STOP,
|
|
|
|
|
|
DroneState.RETURN_COMPLETED
|
|
|
|
|
|
))
|
|
|
|
|
|
// 指点操作子状态
|
|
|
|
|
|
.and()
|
|
|
|
|
|
.withStates()
|
|
|
|
|
|
.parent(DroneState.POINTING_PARENT)
|
|
|
|
|
|
.initial(DroneState.POINT_PREPARING)
|
|
|
|
|
|
.states(EnumSet.of(
|
|
|
|
|
|
DroneState.POINT_PREPARING,
|
|
|
|
|
|
DroneState.POINT_FLYING,
|
|
|
|
|
|
DroneState.POINT_COMPLETED,
|
|
|
|
|
|
DroneState.POINT_CANCELLED
|
|
|
|
|
|
));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void configureTransitions(
|
|
|
|
|
|
StateMachineBuilder.Builder<DroneState, DroneEvent> builder,
|
|
|
|
|
|
DronePlatformStrategy strategy) throws Exception {
|
|
|
|
|
|
builder.configureTransitions()
|
|
|
|
|
|
// ========== 从 UNKNOWN 到所有状态的转换(服务器重启后状态同步) ==========
|
|
|
|
|
|
// UNKNOWN -> OFFLINE
|
|
|
|
|
|
.withExternal()
|
|
|
|
|
|
.source(DroneState.UNKNOWN)
|
|
|
|
|
|
.target(DroneState.OFFLINE)
|
|
|
|
|
|
.event(DroneEvent.DRONE_OFFLINE)
|
|
|
|
|
|
.and()
|
|
|
|
|
|
|
|
|
|
|
|
// UNKNOWN -> PREPARING
|
|
|
|
|
|
.withExternal()
|
|
|
|
|
|
.source(DroneState.UNKNOWN)
|
|
|
|
|
|
.target(DroneState.PREPARING)
|
|
|
|
|
|
.event(DroneEvent.START_PREPARE)
|
|
|
|
|
|
.and()
|
|
|
|
|
|
|
|
|
|
|
|
// UNKNOWN -> FLYING_PARENT
|
|
|
|
|
|
.withExternal()
|
|
|
|
|
|
.source(DroneState.UNKNOWN)
|
|
|
|
|
|
.target(DroneState.FLYING_PARENT)
|
|
|
|
|
|
.event(DroneEvent.START_FLYING)
|
|
|
|
|
|
.and()
|
|
|
|
|
|
|
|
|
|
|
|
// UNKNOWN -> RETURNING_PARENT
|
|
|
|
|
|
.withExternal()
|
|
|
|
|
|
.source(DroneState.UNKNOWN)
|
|
|
|
|
|
.target(DroneState.RETURNING_PARENT)
|
|
|
|
|
|
.event(DroneEvent.START_RETURN)
|
|
|
|
|
|
.and()
|
|
|
|
|
|
|
|
|
|
|
|
// ========== 基本状态转换 ==========
|
|
|
|
|
|
// OFFLINE -> PREPARING
|
|
|
|
|
|
.withExternal()
|
|
|
|
|
|
.source(DroneState.OFFLINE)
|
|
|
|
|
|
.target(DroneState.PREPARING)
|
|
|
|
|
|
.event(DroneEvent.START_PREPARE)
|
|
|
|
|
|
.action(strategy.getStartPrepareAction())
|
|
|
|
|
|
.and()
|
|
|
|
|
|
|
|
|
|
|
|
// PREPARING -> FLYING_PARENT
|
|
|
|
|
|
.withExternal()
|
|
|
|
|
|
.source(DroneState.PREPARING)
|
|
|
|
|
|
.target(DroneState.FLYING_PARENT)
|
|
|
|
|
|
.event(DroneEvent.PREPARE_COMPLETED)
|
|
|
|
|
|
.action(strategy.getPrepareCompletedAction())
|
|
|
|
|
|
.and()
|
|
|
|
|
|
|
|
|
|
|
|
// ========== 飞行阶段内部转换 ==========
|
|
|
|
|
|
// FLYING -> EMERGENCY_STOP
|
|
|
|
|
|
.withExternal()
|
|
|
|
|
|
.source(DroneState.FLYING)
|
|
|
|
|
|
.target(DroneState.EMERGENCY_STOP)
|
|
|
|
|
|
.event(DroneEvent.EMERGENCY_STOP)
|
|
|
|
|
|
.action(strategy.getEmergencyStopAction())
|
|
|
|
|
|
.and()
|
|
|
|
|
|
|
|
|
|
|
|
// EMERGENCY_STOP -> FLYING (恢复飞行)
|
|
|
|
|
|
.withExternal()
|
|
|
|
|
|
.source(DroneState.EMERGENCY_STOP)
|
|
|
|
|
|
.target(DroneState.FLYING)
|
|
|
|
|
|
.event(DroneEvent.RESUME_FLYING)
|
|
|
|
|
|
.action(strategy.getResumeFlyingAction())
|
|
|
|
|
|
.and()
|
|
|
|
|
|
|
|
|
|
|
|
// FLYING -> ARRIVED
|
|
|
|
|
|
.withExternal()
|
|
|
|
|
|
.source(DroneState.FLYING)
|
|
|
|
|
|
.target(DroneState.ARRIVED)
|
|
|
|
|
|
.event(DroneEvent.ARRIVE)
|
|
|
|
|
|
.action(strategy.getArriveAction())
|
|
|
|
|
|
.and()
|
|
|
|
|
|
|
|
|
|
|
|
// 注意:EMERGENCY_STOP 不能直接到 ARRIVED(根据注释限制)
|
|
|
|
|
|
|
|
|
|
|
|
// ========== 飞行阶段 -> 指点操作 ==========
|
|
|
|
|
|
// FLYING -> POINTING_PARENT
|
|
|
|
|
|
.withExternal()
|
|
|
|
|
|
.source(DroneState.FLYING)
|
|
|
|
|
|
.target(DroneState.POINTING_PARENT)
|
|
|
|
|
|
.event(DroneEvent.START_POINTING)
|
|
|
|
|
|
.action(strategy.getStartPointingAction())
|
|
|
|
|
|
.guard(strategy.getCanPointGuard())
|
|
|
|
|
|
.and()
|
|
|
|
|
|
|
|
|
|
|
|
// EMERGENCY_STOP -> POINTING_PARENT
|
|
|
|
|
|
.withExternal()
|
|
|
|
|
|
.source(DroneState.EMERGENCY_STOP)
|
|
|
|
|
|
.target(DroneState.POINTING_PARENT)
|
|
|
|
|
|
.event(DroneEvent.START_POINTING)
|
|
|
|
|
|
.action(strategy.getStartPointingAction())
|
|
|
|
|
|
.guard(strategy.getCanPointGuard())
|
|
|
|
|
|
.and()
|
|
|
|
|
|
|
|
|
|
|
|
// ARRIVED -> POINTING_PARENT
|
|
|
|
|
|
.withExternal()
|
|
|
|
|
|
.source(DroneState.ARRIVED)
|
|
|
|
|
|
.target(DroneState.POINTING_PARENT)
|
|
|
|
|
|
.event(DroneEvent.START_POINTING)
|
|
|
|
|
|
.action(strategy.getStartPointingAction())
|
|
|
|
|
|
.guard(strategy.getCanPointGuard())
|
|
|
|
|
|
.and()
|
|
|
|
|
|
|
|
|
|
|
|
// ========== 飞行阶段 -> 返航 ==========
|
|
|
|
|
|
// FLYING -> RETURNING_PARENT
|
|
|
|
|
|
.withExternal()
|
|
|
|
|
|
.source(DroneState.FLYING)
|
|
|
|
|
|
.target(DroneState.RETURNING_PARENT)
|
|
|
|
|
|
.event(DroneEvent.START_RETURN)
|
|
|
|
|
|
.action(strategy.getStartReturnAction())
|
|
|
|
|
|
.and()
|
|
|
|
|
|
|
|
|
|
|
|
// EMERGENCY_STOP -> RETURNING_PARENT
|
|
|
|
|
|
.withExternal()
|
|
|
|
|
|
.source(DroneState.EMERGENCY_STOP)
|
|
|
|
|
|
.target(DroneState.RETURNING_PARENT)
|
|
|
|
|
|
.event(DroneEvent.START_RETURN)
|
|
|
|
|
|
.action(strategy.getStartReturnAction())
|
|
|
|
|
|
.and()
|
|
|
|
|
|
|
|
|
|
|
|
// ARRIVED -> RETURNING_PARENT
|
|
|
|
|
|
.withExternal()
|
|
|
|
|
|
.source(DroneState.ARRIVED)
|
|
|
|
|
|
.target(DroneState.RETURNING_PARENT)
|
|
|
|
|
|
.event(DroneEvent.START_RETURN)
|
|
|
|
|
|
.action(strategy.getStartReturnAction())
|
|
|
|
|
|
.and()
|
|
|
|
|
|
|
|
|
|
|
|
// ========== 返航阶段内部转换 ==========
|
|
|
|
|
|
// RETURNING -> RETURN_EMERGENCY_STOP
|
|
|
|
|
|
.withExternal()
|
|
|
|
|
|
.source(DroneState.RETURNING)
|
|
|
|
|
|
.target(DroneState.RETURN_EMERGENCY_STOP)
|
|
|
|
|
|
.event(DroneEvent.RETURN_EMERGENCY_STOP)
|
|
|
|
|
|
.action(strategy.getReturnEmergencyStopAction())
|
|
|
|
|
|
.and()
|
|
|
|
|
|
|
|
|
|
|
|
// RETURN_EMERGENCY_STOP -> RETURNING (恢复返航)
|
|
|
|
|
|
.withExternal()
|
|
|
|
|
|
.source(DroneState.RETURN_EMERGENCY_STOP)
|
|
|
|
|
|
.target(DroneState.RETURNING)
|
|
|
|
|
|
.event(DroneEvent.RESUME_RETURN)
|
|
|
|
|
|
.action(strategy.getResumeReturnAction())
|
|
|
|
|
|
.and()
|
|
|
|
|
|
|
|
|
|
|
|
// RETURNING -> RETURN_COMPLETED
|
|
|
|
|
|
.withExternal()
|
|
|
|
|
|
.source(DroneState.RETURNING)
|
|
|
|
|
|
.target(DroneState.RETURN_COMPLETED)
|
|
|
|
|
|
.event(DroneEvent.RETURN_COMPLETED)
|
|
|
|
|
|
.action(strategy.getReturnCompletedAction())
|
|
|
|
|
|
.and()
|
|
|
|
|
|
|
|
|
|
|
|
// 注意:返航中不能指点(根据注释限制)
|
|
|
|
|
|
// 注意:RETURN_COMPLETED 不能回退到 RETURNING 或 RETURN_EMERGENCY_STOP(根据注释限制)
|
|
|
|
|
|
|
|
|
|
|
|
// ========== 返航急停 -> 指点操作 ==========
|
|
|
|
|
|
// RETURN_EMERGENCY_STOP -> POINTING_PARENT (一键起飞和航线飞行都可以指点)
|
|
|
|
|
|
.withExternal()
|
|
|
|
|
|
.source(DroneState.RETURN_EMERGENCY_STOP)
|
|
|
|
|
|
.target(DroneState.POINTING_PARENT)
|
|
|
|
|
|
.event(DroneEvent.START_POINTING)
|
|
|
|
|
|
.action(strategy.getStartPointingAction())
|
|
|
|
|
|
.guard(strategy.getCanPointGuard())
|
|
|
|
|
|
.and()
|
|
|
|
|
|
|
|
|
|
|
|
// ========== 指点操作内部转换 ==========
|
|
|
|
|
|
// POINT_PREPARING -> POINT_FLYING
|
|
|
|
|
|
.withExternal()
|
|
|
|
|
|
.source(DroneState.POINT_PREPARING)
|
|
|
|
|
|
.target(DroneState.POINT_FLYING)
|
|
|
|
|
|
.event(DroneEvent.POINT_PREPARE_COMPLETED)
|
|
|
|
|
|
.action(strategy.getPointPrepareCompletedAction())
|
|
|
|
|
|
.and()
|
|
|
|
|
|
|
|
|
|
|
|
// POINT_FLYING -> POINT_COMPLETED
|
|
|
|
|
|
.withExternal()
|
|
|
|
|
|
.source(DroneState.POINT_FLYING)
|
|
|
|
|
|
.target(DroneState.POINT_COMPLETED)
|
|
|
|
|
|
.event(DroneEvent.POINT_FLYING_COMPLETED)
|
|
|
|
|
|
.action(strategy.getPointFlyingCompletedAction())
|
|
|
|
|
|
.and()
|
|
|
|
|
|
|
|
|
|
|
|
// 任何指点阶段 -> POINT_CANCELLED
|
|
|
|
|
|
.withExternal()
|
|
|
|
|
|
.source(DroneState.POINT_PREPARING)
|
|
|
|
|
|
.target(DroneState.POINT_CANCELLED)
|
|
|
|
|
|
.event(DroneEvent.CANCEL_POINT)
|
|
|
|
|
|
.action(strategy.getCancelPointAction())
|
|
|
|
|
|
.and()
|
|
|
|
|
|
|
|
|
|
|
|
.withExternal()
|
|
|
|
|
|
.source(DroneState.POINT_FLYING)
|
|
|
|
|
|
.target(DroneState.POINT_CANCELLED)
|
|
|
|
|
|
.event(DroneEvent.CANCEL_POINT)
|
|
|
|
|
|
.action(strategy.getCancelPointAction())
|
|
|
|
|
|
.and()
|
|
|
|
|
|
|
|
|
|
|
|
.withExternal()
|
|
|
|
|
|
.source(DroneState.POINT_COMPLETED)
|
|
|
|
|
|
.target(DroneState.POINT_CANCELLED)
|
|
|
|
|
|
.event(DroneEvent.CANCEL_POINT)
|
|
|
|
|
|
.action(strategy.getCancelPointAction())
|
|
|
|
|
|
.and()
|
|
|
|
|
|
|
|
|
|
|
|
// ========== 指点操作 -> 飞行/返航 ==========
|
|
|
|
|
|
// POINT_COMPLETED -> FLYING
|
|
|
|
|
|
.withExternal()
|
|
|
|
|
|
.source(DroneState.POINT_COMPLETED)
|
|
|
|
|
|
.target(DroneState.FLYING)
|
|
|
|
|
|
.event(DroneEvent.POINT_TO_FLYING)
|
|
|
|
|
|
.action(strategy.getPointToFlyingAction())
|
|
|
|
|
|
.and()
|
|
|
|
|
|
|
|
|
|
|
|
// POINT_CANCELLED -> FLYING
|
|
|
|
|
|
.withExternal()
|
|
|
|
|
|
.source(DroneState.POINT_CANCELLED)
|
|
|
|
|
|
.target(DroneState.FLYING)
|
|
|
|
|
|
.event(DroneEvent.POINT_TO_FLYING)
|
|
|
|
|
|
.action(strategy.getPointToFlyingAction())
|
|
|
|
|
|
.and()
|
|
|
|
|
|
|
|
|
|
|
|
// POINT_COMPLETED -> RETURNING_PARENT
|
|
|
|
|
|
.withExternal()
|
|
|
|
|
|
.source(DroneState.POINT_COMPLETED)
|
|
|
|
|
|
.target(DroneState.RETURNING_PARENT)
|
|
|
|
|
|
.event(DroneEvent.POINT_TO_RETURN)
|
|
|
|
|
|
.action(strategy.getPointToReturnAction())
|
|
|
|
|
|
.and()
|
|
|
|
|
|
|
|
|
|
|
|
// POINT_CANCELLED -> RETURNING_PARENT
|
|
|
|
|
|
.withExternal()
|
|
|
|
|
|
.source(DroneState.POINT_CANCELLED)
|
|
|
|
|
|
.target(DroneState.RETURNING_PARENT)
|
|
|
|
|
|
.event(DroneEvent.POINT_TO_RETURN)
|
|
|
|
|
|
.action(strategy.getPointToReturnAction())
|
|
|
|
|
|
.and()
|
|
|
|
|
|
|
|
|
|
|
|
// POINT_COMPLETED -> RETURN_EMERGENCY_STOP
|
|
|
|
|
|
.withExternal()
|
|
|
|
|
|
.source(DroneState.POINT_COMPLETED)
|
|
|
|
|
|
.target(DroneState.RETURN_EMERGENCY_STOP)
|
|
|
|
|
|
.event(DroneEvent.RETURN_EMERGENCY_STOP)
|
|
|
|
|
|
.action(strategy.getReturnEmergencyStopAction())
|
|
|
|
|
|
.and()
|
|
|
|
|
|
|
|
|
|
|
|
// POINT_COMPLETED -> RETURN_COMPLETED
|
|
|
|
|
|
.withExternal()
|
|
|
|
|
|
.source(DroneState.POINT_COMPLETED)
|
|
|
|
|
|
.target(DroneState.RETURN_COMPLETED)
|
|
|
|
|
|
.event(DroneEvent.RETURN_COMPLETED)
|
|
|
|
|
|
.action(strategy.getReturnCompletedAction())
|
|
|
|
|
|
.and()
|
|
|
|
|
|
|
|
|
|
|
|
// ========== 离线处理 ==========
|
|
|
|
|
|
// 任何状态 -> OFFLINE
|
|
|
|
|
|
.withExternal()
|
|
|
|
|
|
.source(DroneState.FLYING_PARENT)
|
|
|
|
|
|
.target(DroneState.OFFLINE)
|
|
|
|
|
|
.event(DroneEvent.DRONE_OFFLINE)
|
|
|
|
|
|
.action(strategy.getOfflineAction())
|
|
|
|
|
|
.and()
|
|
|
|
|
|
|
|
|
|
|
|
.withExternal()
|
|
|
|
|
|
.source(DroneState.RETURNING_PARENT)
|
|
|
|
|
|
.target(DroneState.OFFLINE)
|
|
|
|
|
|
.event(DroneEvent.DRONE_OFFLINE)
|
|
|
|
|
|
.action(strategy.getOfflineAction())
|
|
|
|
|
|
.and()
|
|
|
|
|
|
|
|
|
|
|
|
.withExternal()
|
|
|
|
|
|
.source(DroneState.POINTING_PARENT)
|
|
|
|
|
|
.target(DroneState.OFFLINE)
|
|
|
|
|
|
.event(DroneEvent.DRONE_OFFLINE)
|
|
|
|
|
|
.action(strategy.getOfflineAction());
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|