MQTT通信修改 使用服务器数据库

This commit is contained in:
yuhaiming
2026-06-30 08:12:35 +08:00
parent 0098220a9a
commit 319ebd19ad
15 changed files with 328 additions and 70 deletions

View File

@@ -123,6 +123,11 @@
<groupId>org.dromara</groupId>
<artifactId>water-system</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

View File

@@ -14,7 +14,6 @@ import org.dromara.app.domain.bo.AppDeviceBo;
import org.dromara.app.domain.bo.AppScheduleBo;
import org.dromara.app.domain.bo.AppSchedulingDeviceBo;
import org.dromara.app.domain.bo.AppWateringLogBo;
import org.dromara.app.domain.mqtt.DeviceCommand;
import org.dromara.app.domain.vo.*;
import org.dromara.app.service.*;
import org.dromara.app.service.impl.AppScheduleServiceImpl;
@@ -37,11 +36,16 @@ import org.dromara.common.mybatis.helper.DataPermissionHelper;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.web.core.BaseController;
import org.dromara.system.domain.bo.SysUserBo;
import org.dromara.system.domain.vo.SysOssUploadVo;
import org.dromara.system.domain.vo.SysOssVo;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.domain.vo.UserInfoVo;
import org.dromara.system.service.ISysOssService;
import org.dromara.system.service.ISysUserService;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.*;
@@ -61,6 +65,7 @@ public class AppController extends BaseController {
private final ISysUserService userService;
private final IAppWateringLogService appWateringLogService;
private final IDeviceCommandService deviceCommandService;
private final ISysOssService ossService;
/**
*查询设备
@@ -243,10 +248,15 @@ public class AppController extends BaseController {
continue;
}
assertDeviceOwned(deviceNo);
if (appSchedulingDeviceService.queryByScheduleIdAndDeviceNo(scheduleId, deviceNo) != null) {
continue;
}
AppSchedulingDeviceBo schedulingDeviceBo = new AppSchedulingDeviceBo();
schedulingDeviceBo.setDeviceNo(deviceNo);
schedulingDeviceBo.setScheduleId(scheduleId);
appSchedulingDeviceService.insertByBo(schedulingDeviceBo);
if (appSchedulingDeviceService.insertByBo(schedulingDeviceBo)) {
deviceCommandService.sendScheduleBindCommand(deviceNo, buildScheduleBindPayload(scheduleId, deviceNo));
}
}
return R.ok();
} catch (Exception e) {
@@ -277,6 +287,47 @@ public class AppController extends BaseController {
.toList();
}
private Map<String, Object> buildScheduleBindPayload(Long scheduleId, String deviceNo) {
// AppScheduleVo schedule = getOwnedSchedule(scheduleId);
List<AppScheduleDetailVo> details = appScheduleDetailService.queryByScheduleIdByStatus(scheduleId);
// Map<String, Object> schedulePayload = new HashMap<>();
// schedulePayload.put("id", schedule.getId());
// schedulePayload.put("name", schedule.getName());
// schedulePayload.put("status", schedule.getStatus());
Map<String, Object> payload = new HashMap<>();
// payload.put("cmd", -1);
payload.put("deviceNo", deviceNo);
// payload.put("schedule", schedulePayload);
payload.put("details", toScheduleDetailPayload(details));
return payload;
// return toScheduleDetailPayload(details);
}
private List<Map<String, Object>> toScheduleDetailPayload(List<AppScheduleDetailVo> details) {
List<Map<String, Object>> detailPayload = new ArrayList<>();
if (details == null) {
return detailPayload;
}
for (AppScheduleDetailVo detail : details) {
List<Object> timeSlots = new ArrayList<>();
JSONArray timeArray = JSONUtil.parseArray(detail.getTimeData());
for (Object timeSlot : timeArray) {
timeSlots.add(timeSlot);
}
Map<String, Object> item = new HashMap<>();
item.put("id", detail.getId());
item.put("weekday", detail.getWeekday());
item.put("timeData", timeSlots);
item.put("triggerType", detail.getTriggerType());
item.put("status", detail.getStatus());
detailPayload.add(item);
}
return detailPayload;
}
/**
* 删除排程与设备绑定
* @param scheduleId,deviceNo
@@ -297,7 +348,17 @@ public class AppController extends BaseController {
Long scheduleIdValue = Long.valueOf(scheduleId);
assertScheduleOwned(scheduleIdValue);
assertDeviceOwned(deviceNo);
return toAjax(appSchedulingDeviceService.deleteWithValidByScheduleIdAndDeviceNo(scheduleIdValue, deviceNo));
Boolean deleted = appSchedulingDeviceService.deleteWithValidByScheduleIdAndDeviceNo(scheduleIdValue, deviceNo);
if (deleted) {
// 通知设备解绑排程
try {
deviceCommandService.sendScheduleUnbindCommand(deviceNo, scheduleIdValue);
} catch (Exception mqttEx) {
log.warn("[排程通知] 删除排程设备绑定后下发解绑命令失败 排程ID={} 设备编号={} 原因={}",
scheduleIdValue, deviceNo, mqttEx.getMessage());
}
}
return toAjax(deleted);
} catch (Exception e) {
return fail(e);
}
@@ -406,7 +467,12 @@ public class AppController extends BaseController {
try {
assertScheduleOwned(bo.getId());
bo.setUserId(LoginHelper.getUserId());
return toAjax(appScheduleService.updateStatusByBo(bo));
Boolean updated = appScheduleService.updateStatusByBo(bo);
if (updated) {
// 向所有绑定设备下发排程状态变更
notifyBoundDevicesScheduleUpdate(bo.getId());
}
return toAjax(updated);
} catch (Exception e) {
return fail(e);
}
@@ -424,6 +490,8 @@ public class AppController extends BaseController {
bo.setUserId(LoginHelper.getUserId());
Map<String, Object> map = appScheduleService.updateByBo(bo);
if (Boolean.valueOf(map.get("flag").toString())){
// 向所有绑定设备下发排程更新
notifyBoundDevicesScheduleUpdate(bo.getId());
return R.ok(map.get("appSchedule"));
}else {
return R.fail();
@@ -448,7 +516,17 @@ public class AppController extends BaseController {
for (Long id : ids) {
assertScheduleOwned(id);
}
return toAjax(appScheduleService.deleteWithValidByIds(List.of(ids), true));
Map<Long, List<String>> boundDeviceNosBySchedule = new HashMap<>();
for (Long id : ids) {
boundDeviceNosBySchedule.put(id, findBoundDeviceNos(id));
}
Boolean deleted = appScheduleService.deleteWithValidByIds(List.of(ids), true);
if (deleted) {
for (Map.Entry<Long, List<String>> entry : boundDeviceNosBySchedule.entrySet()) {
notifyScheduleUnbind(entry.getKey(), entry.getValue());
}
}
return toAjax(deleted);
} catch (Exception e) {
return fail(e);
}
@@ -475,7 +553,7 @@ public class AppController extends BaseController {
vo.setDeviceNo(appDeviceVo.getDeviceNo());
}
}
vo.setTriggerType(vo.getTriggerType().equals("0")?"排程":"手动");
// vo.setTriggerType(vo.getTriggerType().equals("0")?"排程":"手动");
l.add(vo);
}
appWateringLogVoTableDataInfo.setRows(l);
@@ -563,6 +641,31 @@ public class AppController extends BaseController {
}
}
/**
* 上传图片到OSS对象存储
*/
@PostMapping(value = "/uploadImage", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public R<SysOssUploadVo> uploadImage(@RequestPart("file") MultipartFile file) {
try {
if (file == null || file.isEmpty()) {
throw new ServiceException("上传图片不能为空");
}
String contentType = file.getContentType();
if (StringUtils.isBlank(contentType) || !contentType.toLowerCase(Locale.ROOT).startsWith("image/")) {
throw new ServiceException("只能上传图片文件");
}
SysOssVo oss = ossService.upload(file);
SysOssUploadVo uploadVo = new SysOssUploadVo();
uploadVo.setUrl(oss.getUrl());
uploadVo.setFileName(oss.getOriginalName());
uploadVo.setOssId(oss.getOssId() == null ? null : oss.getOssId().toString());
return R.ok(uploadVo);
} catch (Exception e) {
return fail(e);
}
}
/**
* 修改用户
*/
@@ -638,9 +741,6 @@ public class AppController extends BaseController {
@GetMapping("/test")
public R<Void> test (){
try {
DeviceCommand deviceCommand = new DeviceCommand();
String bindDevice = deviceCommandService.sendBindDeviceCommand("01");
// String s = deviceCommandService.sendSwitchCommand("01", "1", "2026-06-10 14:35:31", 20);
@@ -706,4 +806,48 @@ public class AppController extends BaseController {
}
}
/**
* 查找排程关联的所有设备编号
*/
private List<String> findBoundDeviceNos(Long scheduleId) {
AppSchedulingDeviceBo bo = new AppSchedulingDeviceBo();
bo.setScheduleId(scheduleId);
List<AppSchedulingDeviceVo> bindings = appSchedulingDeviceService.queryList(bo);
return bindings.stream()
.map(AppSchedulingDeviceVo::getDeviceNo)
.filter(StringUtils::isNotBlank)
.toList();
}
/**
* 向排程关联的所有设备重新下发排程信息(用于排程内容/状态变更)
*/
private void notifyBoundDevicesScheduleUpdate(Long scheduleId) {
List<String> deviceNos = findBoundDeviceNos(scheduleId);
for (String deviceNo : deviceNos) {
try {
deviceCommandService.sendScheduleBindCommand(deviceNo, buildScheduleBindPayload(scheduleId, deviceNo));
} catch (Exception e) {
log.warn("[排程通知] 下发排程更新失败 排程ID={} 设备编号={} 原因={}", scheduleId, deviceNo, e.getMessage());
}
}
}
/**
* 向排程关联的所有设备下发排程解绑通知
*/
private void notifyBoundDevicesScheduleUnbind(Long scheduleId) {
notifyScheduleUnbind(scheduleId, findBoundDeviceNos(scheduleId));
}
private void notifyScheduleUnbind(Long scheduleId, List<String> deviceNos) {
for (String deviceNo : deviceNos) {
try {
deviceCommandService.sendScheduleUnbindCommand(deviceNo, scheduleId);
} catch (Exception e) {
log.warn("[排程通知] 下发排程解绑失败 排程ID={} 设备编号={} 原因={}", scheduleId, deviceNo, e.getMessage());
}
}
}
}

View File

@@ -15,6 +15,7 @@ public class DeviceCommand implements Serializable {
private String commandId;
private String deviceNo;
private String deviceMac;
private String commandType;
private String topic;
private Map<String, Object> payload = new HashMap<>();

View File

@@ -81,14 +81,16 @@ public class DeviceDataHandler implements MqttTopicHandler {
/**
* 刷新设备在线状态到 Redis与 MqttCommandAckService 逻辑一致)
* 写入 Redis 后 TTL 到期自动过期 = 离线
* 写入幂等,未拿到锁则跳过由后续上报兜底
*/
private void refreshDeviceOnline(String deviceNo) {
RLock lock = RedisUtils.getClient().getLock(DEVICE_STATUS_LOCK_PREFIX + deviceNo);
boolean locked = false;
try {
lock.lock(10, TimeUnit.SECONDS);
locked = true;
locked = lock.tryLock(0, 10, TimeUnit.SECONDS);
if (!locked) {
return;
}
Map<String, Object> statusCache = new HashMap<>();
statusCache.put("deviceNo", deviceNo);
statusCache.put("status", "1");
@@ -103,6 +105,9 @@ public class DeviceDataHandler implements MqttTopicHandler {
.set(AppDevice::getStatus, "1")
.eq(AppDevice::getDeviceNo, deviceNo)
);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
log.warn("[MQTT] 刷新设备在线状态被中断 设备编号={}", deviceNo);
} finally {
if (locked && lock.isHeldByCurrentThread()) {
lock.unlock();

View File

@@ -47,8 +47,6 @@ DeviceRegisterHandler implements MqttTopicHandler {
@Value("${mqtt.command-ack.device-status-cache-ttl-seconds}")
private int deviceStatusCacheTtlSeconds;
private final DeviceIdentityResolver deviceIdentityResolver;
@Value("${mqtt.topics.publish-prefix:}")
private String mqttPublishPrefix;
@Override
public Pattern topicPattern() {
@@ -77,8 +75,7 @@ DeviceRegisterHandler implements MqttTopicHandler {
AppDeviceBo device = buildRegisterDevice(deviceNo, normalizedDeviceMac, dto);
appDeviceService.registerByMqtt(device);
refreshDeviceOnline(deviceNo);
String commandTarget = normalizedDeviceMac == null ? deviceIdentity : normalizedDeviceMac;
sendDeviceNoToDevice(commandTarget, deviceNo);
sendDeviceNoToDevice(deviceNo, normalizedDeviceMac);
log.info("[MQTT] 设备注册 时间={} MAC={} 设备编号={} 消息体={}",
HandlerLogTime.now(), normalizedDeviceMac, deviceNo, payload);
} catch (Exception e) {
@@ -115,19 +112,25 @@ DeviceRegisterHandler implements MqttTopicHandler {
return text.isBlank() ? null : text.toLowerCase(Locale.ROOT);
}
private void sendDeviceNoToDevice(String deviceMac, String deviceNo) {
private void sendDeviceNoToDevice(String deviceNo, String deviceMac) {
IDeviceCommandPublisher commandPublisher = commandPublisherProvider.getIfAvailable();
if (commandPublisher == null) {
log.warn("[MQTT] 设备编号下发失败,未找到命令发布器 时间={} MAC={} 设备编号={}",
HandlerLogTime.now(), deviceMac, deviceNo);
return;
}
if (deviceMac == null) {
log.warn("[MQTT] 设备编号下发失败,缺少设备 MAC 时间={} 设备编号={}",
HandlerLogTime.now(), deviceNo);
return;
}
try {
DeviceCommand command = new DeviceCommand();
command.setDeviceNo(deviceNo);
command.setDeviceMac(deviceMac);
command.setCommandType("registerDeviceNo");
command.setTopic(buildCommandTopic(deviceMac));
command.setTopic("/" + deviceMac.trim().toLowerCase(Locale.ROOT) + "/subscriber/cmd");
command.getPayload().put("deviceNo", deviceNo);
command.getPayload().put("deviceMac", deviceMac);
@@ -140,17 +143,6 @@ DeviceRegisterHandler implements MqttTopicHandler {
}
}
private String buildCommandTopic(String deviceMac) {
if (mqttPublishPrefix == null || mqttPublishPrefix.isBlank()) {
return "/" + deviceMac + "/subscriber/cmd";
}
String normalizedPrefix = mqttPublishPrefix.startsWith("/") ? mqttPublishPrefix : "/" + mqttPublishPrefix;
if (normalizedPrefix.endsWith("/")) {
normalizedPrefix = normalizedPrefix.substring(0, normalizedPrefix.length() - 1);
}
return normalizedPrefix + "/" + deviceMac + "/subscriber/cmd";
}
private String firstNotBlank(Object first, Object second) {
String firstText = valueAsString(first);
if (firstText != null && !firstText.isBlank()) {
@@ -165,14 +157,16 @@ DeviceRegisterHandler implements MqttTopicHandler {
}
/**
* 刷新设备在线状态到 Redis
* 刷新设备在线状态到 Redis;状态写入幂等,未拿到锁则跳过由后续上报兜底
*/
private void refreshDeviceOnline(String deviceNo) {
RLock lock = RedisUtils.getClient().getLock(DEVICE_STATUS_LOCK_PREFIX + deviceNo);
boolean locked = false;
try {
lock.lock(10, TimeUnit.SECONDS);
locked = true;
locked = lock.tryLock(0, 10, TimeUnit.SECONDS);
if (!locked) {
return;
}
Map<String, Object> statusCache = new HashMap<>();
statusCache.put("deviceNo", deviceNo);
statusCache.put("status", "1");
@@ -187,6 +181,9 @@ DeviceRegisterHandler implements MqttTopicHandler {
.set(AppDevice::getStatus, "1")
.eq(AppDevice::getDeviceNo, deviceNo)
);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
log.warn("[MQTT] 刷新设备在线状态被中断 设备编号={}", deviceNo);
} finally {
if (locked && lock.isHeldByCurrentThread()) {
lock.unlock();

View File

@@ -41,8 +41,26 @@ public interface IDeviceCommandService {
* @return commandId
*/
String sendCustomCommand(String deviceNo, String commandType, Map<String, Object> extra);
/**
* 下发排程绑定命令。
*
* @param deviceNo 设备编号
* @param payload 排程信息
* @return commandId
*/
String sendScheduleBindCommand(String deviceNo, Map<String, Object> payload);
String sendBindDeviceCommand(String deviceNo);
/**
* 下发排程解绑命令,通知设备清除指定排程。
*
* @param deviceNo 设备编号
* @param scheduleId 排程ID
* @return commandId
*/
String sendScheduleUnbindCommand(String deviceNo, Long scheduleId);
/**
* 下发设备初始化指令。用于解绑设备,允许设备未绑定用户时下发。
*

View File

@@ -142,6 +142,7 @@ public class AppDeviceServiceImpl implements IAppDeviceService {
try {
return baseMapper.insert(device) > 0;
} catch (org.springframework.dao.DuplicateKeyException ignored) {
device.setDeviceName(null);
return baseMapper.updateById(device) > 0;
}
}
@@ -219,8 +220,7 @@ public class AppDeviceServiceImpl implements IAppDeviceService {
throw new ServiceException("设备绑定失败,请重试");
}
//下发设备已绑定状态
//deviceCommandService.sendBindDeviceCommand(exists.getDeviceNo());
deviceCommandService.sendBindDeviceCommand(exists.getMacAddress());
deviceCommandService.sendBindDeviceCommand(exists.getDeviceNo());
return baseMapper.selectVoById(exists.getDeviceNo());
}
@@ -247,8 +247,7 @@ public class AppDeviceServiceImpl implements IAppDeviceService {
AppDeviceVo device = baseMapper.selectVoById(deviceNo);
if (ObjectUtil.isNotNull(device) && StringUtils.isNotBlank(device.getDeviceNo())) {
// 通过业务层统一下发命令(含浇水日志记录)
//String commandId = deviceCommandService.sendSwitchCommand(deviceNo, workStatus, startTime, durationMin);
String commandId = deviceCommandService.sendSwitchCommand(device.getMacAddress(), workStatus, startTime, durationMin);
String commandId = deviceCommandService.sendSwitchCommand(deviceNo, workStatus, startTime, durationMin);
log.info("[设备] 开关命令已下发 设备编号={} 命令编号={}", deviceNo, commandId);
}

View File

@@ -19,10 +19,7 @@ import org.springframework.stereotype.Service;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.*;
/**
* 设备命令下发业务实现。
@@ -49,6 +46,9 @@ public class DeviceCommandServiceImpl implements IDeviceCommandService {
@Override
public String sendCommand(DeviceCommand command) {
validate(command);
if (StringUtils.isBlank(command.getDeviceMac())) {
command.setDeviceMac(requireDeviceMac(command.getDeviceNo()));
}
String commandId = commandPublisher.send(command);
log.info("[命令] 命令已下发 设备编号={} 命令类型={} 命令编号={}",
command.getDeviceNo(), command.getCommandType(), commandId);
@@ -67,6 +67,7 @@ public class DeviceCommandServiceImpl implements IDeviceCommandService {
DeviceCommand command = new DeviceCommand();
command.setDeviceNo(deviceNo);
command.setDeviceMac(requireDeviceMac(deviceNo));
command.setCommandType("switchDevice");
command.getPayload().put("deviceNo", deviceNo);
command.getPayload().put("cmd", workStatus);
@@ -100,6 +101,7 @@ public class DeviceCommandServiceImpl implements IDeviceCommandService {
DeviceCommand command = new DeviceCommand();
command.setDeviceNo(deviceNo);
command.setDeviceMac(requireDeviceMac(deviceNo));
command.setCommandType(commandType);
if (extra != null) {
command.getPayload().putAll(extra);
@@ -107,15 +109,37 @@ public class DeviceCommandServiceImpl implements IDeviceCommandService {
return sendCommand(command);
}
@Override
public String sendScheduleBindCommand(String deviceNo, Map<String, Object> payload) {
AppDeviceVo device = requireCommandDevice(deviceNo);
if (StringUtils.isBlank(device.getMacAddress())) {
throw new ServiceException("设备未登记 MAC无法下发排程" + deviceNo);
}
DeviceCommand command = new DeviceCommand();
command.setDeviceNo(deviceNo);
command.setDeviceMac(device.getMacAddress());
command.setCommandType("bindSchedule");
command.setTopic(buildScheduleTopic(deviceNo));
if (payload != null) {
command.getPayload().putAll(payload);
}
return sendCommand(command);
}
@Override
public String sendBindDeviceCommand(String deviceNo) {
AppDeviceVo device = deviceService.queryById(deviceNo);
if (ObjectUtil.isNull(device)) {
throw new ServiceException("设备不存在:" + deviceNo);
}
if (StringUtils.isBlank(device.getMacAddress())) {
throw new ServiceException("设备未登记 MAC无法下发绑定命令" + deviceNo);
}
DeviceCommand command = new DeviceCommand();
command.setDeviceNo(deviceNo);
command.setDeviceMac(device.getMacAddress());
command.setCommandType("bindDevice");
Map<String, Object> objectObjectHashMap = new HashMap<>();
objectObjectHashMap.put("bindStatus", true);
@@ -125,15 +149,38 @@ public class DeviceCommandServiceImpl implements IDeviceCommandService {
return sendCommand(command);
}
@Override
public String sendScheduleUnbindCommand(String deviceNo, Long scheduleId) {
AppDeviceVo device = requireCommandDevice(deviceNo);
if (StringUtils.isBlank(device.getMacAddress())) {
throw new ServiceException("设备未登记 MAC无法下发排程解绑命令" + deviceNo);
}
DeviceCommand command = new DeviceCommand();
command.setDeviceNo(deviceNo);
command.setDeviceMac(device.getMacAddress());
command.setCommandType("unbindSchedule");
command.setTopic(buildScheduleTopic(deviceNo));
command.getPayload().put("cmd", -1);
command.getPayload().put("deviceNo", deviceNo);
command.getPayload().put("scheduleId", scheduleId);
command.getPayload().put("unbind", true);
return sendCommand(command);
}
@Override
public String sendInitDeviceCommand(String deviceNo) {
AppDeviceVo device = deviceService.queryById(deviceNo);
if (ObjectUtil.isNull(device)) {
throw new ServiceException("设备不存在:" + deviceNo);
}
if (StringUtils.isBlank(device.getMacAddress())) {
throw new ServiceException("设备未登记 MAC无法下发初始化命令" + deviceNo);
}
DeviceCommand command = new DeviceCommand();
command.setDeviceNo(deviceNo);
command.setDeviceMac(device.getMacAddress());
command.setCommandType("initDevice");
Map<String, Object> payload = new HashMap<>();
payload.put("deviceNo", deviceNo);
@@ -167,6 +214,29 @@ public class DeviceCommandServiceImpl implements IDeviceCommandService {
}
}
private String requireDeviceMac(String deviceNo) {
AppDeviceVo device = deviceService.queryById(deviceNo);
if (device == null || StringUtils.isBlank(device.getMacAddress())) {
throw new ServiceException("设备未登记 MAC无法下发命令" + deviceNo);
}
return device.getMacAddress();
}
private AppDeviceVo requireCommandDevice(String deviceNo) {
AppDeviceVo device = deviceService.queryById(deviceNo);
if (ObjectUtil.isNull(device)) {
throw new ServiceException("设备不存在:" + deviceNo);
}
if (device.getUserId() == null) {
throw new ServiceException("设备未绑定用户,无法下发命令:" + deviceNo);
}
return device;
}
private String buildScheduleTopic(String deviceNo) {
return "/" + deviceNo.trim().toLowerCase(Locale.ROOT) + "/subscriber/schedule";
}
private void assertSwitchStatus(String workStatus) {
if (!"0".equals(workStatus) && !"1".equals(workStatus)) {
throw new ServiceException("设备工作状态只能为0或1");