feat(iot): 添加温度异常事件处理功能

- 在 RecordData 实体中添加处理记录数据的方法- 新增 TemperatureExceededEvent 类用于温度异常事件
- 在 DeviceController 中集成事件处理逻辑
- 更新数据库结构,增加参数对比类型和默认值字段
- 优化 Param 实体,添加 CompareType枚举
This commit is contained in:
zhuangtianxiang 2025-03-11 20:36:47 +08:00
parent 58a9f08c3b
commit 640e7f5286
9 changed files with 174 additions and 20 deletions

View File

@ -1,8 +1,6 @@
package com.zsc.edu.gateway.framework.message.sse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.http.MediaType;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

View File

@ -2,7 +2,6 @@ package com.zsc.edu.gateway.modules.iot.device.controller;
import com.alibaba.fastjson2.JSONException;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zsc.edu.gateway.framework.message.sse.SseConfig;
@ -13,15 +12,11 @@ import com.zsc.edu.gateway.modules.iot.device.dto.DeviceServeDto;
import com.zsc.edu.gateway.modules.iot.device.entity.Device;
import com.zsc.edu.gateway.modules.iot.device.query.DeviceQuery;
import com.zsc.edu.gateway.modules.iot.device.service.DeviceService;
import com.zsc.edu.gateway.modules.iot.device.vo.DeviceStatusVo;
import com.zsc.edu.gateway.modules.iot.device.vo.DeviceVo;
import com.zsc.edu.gateway.modules.iot.record.entity.DataWarningVo;
import com.zsc.edu.gateway.modules.iot.record.entity.RecordData;
import com.zsc.edu.gateway.modules.iot.record.entity.RecordDataStatusVo;
import com.zsc.edu.gateway.modules.iot.record.service.RecordDataService;
import jakarta.annotation.Resource;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;

View File

@ -0,0 +1,21 @@
package com.zsc.edu.gateway.modules.iot.record.entity;
import lombok.Getter;
import lombok.Setter;
import org.springframework.context.ApplicationEvent;
/**
* @author zhuang
*/
@Getter
@Setter
public class TemperatureExceededEvent extends ApplicationEvent {
private final RecordData recordData;
private final double reducedParameter;
public TemperatureExceededEvent(Object source, RecordData recordData, double reducedParameter) {
super(source);
this.recordData = recordData;
this.reducedParameter = reducedParameter;
}
}

View File

@ -5,16 +5,25 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zsc.edu.gateway.modules.iot.device.entity.Device;
import com.zsc.edu.gateway.modules.iot.device.repo.DeviceRepository;
import com.zsc.edu.gateway.modules.iot.record.entity.DataWarningVo;
import com.zsc.edu.gateway.modules.iot.record.entity.RecordData;
import com.zsc.edu.gateway.modules.iot.record.entity.RecordDataStatusVo;
import com.zsc.edu.gateway.modules.iot.record.entity.TemperatureExceededEvent;
import com.zsc.edu.gateway.modules.iot.record.repo.RecordDataRepository;
import com.zsc.edu.gateway.modules.iot.record.service.RecordDataService;
import com.zsc.edu.gateway.modules.iot.tsl.entity.Event;
import com.zsc.edu.gateway.modules.iot.tsl.entity.Param;
import com.zsc.edu.gateway.modules.iot.tsl.repo.EventRepository;
import jakarta.annotation.Resource;
import lombok.AllArgsConstructor;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
/**
* @author zhuang
@ -23,8 +32,12 @@ import java.util.List;
@Service
public class RecordDataServiceImpl extends ServiceImpl<RecordDataRepository, RecordData> implements RecordDataService {
private final RecordDataRepository recordDataRepository;
@Resource
private final ApplicationEventPublisher eventPublisher;
@Resource
private final DeviceRepository deviceRepository;
@Resource
private final EventRepository eventRepository;
@Override
public RecordData recordData(String clientId, JSONObject data) {
RecordData recordData = new RecordData();
@ -32,6 +45,7 @@ public class RecordDataServiceImpl extends ServiceImpl<RecordDataRepository, Rec
recordData.setContent(data);
recordData.setRecordTime(LocalDateTime.now());
baseMapper.insert(recordData);
processRecordData(recordData);
return recordData;
}
@ -64,6 +78,64 @@ public class RecordDataServiceImpl extends ServiceImpl<RecordDataRepository, Rec
public IPage<RecordData> query(Page<RecordData> page, String clientId) {
LambdaQueryWrapper<RecordData> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(RecordData::getClientId, clientId);
return recordDataRepository.selectPage(page, queryWrapper);
return baseMapper.selectPage(page, queryWrapper);
}
public void processRecordData(RecordData recordData) {
// 根据 clientId 查询设备信息
Device device = deviceRepository.selectOne(new LambdaQueryWrapper<Device>().eq(Device::getClientId, recordData.getClientId()));
// 获取产品下的所有事件
List<Event> events = eventRepository.selectList(new LambdaQueryWrapper<Event>().eq(Event::getProductId, device.getProductId()));
// 遍历每个事件
for (Event event : events) {
// 遍历事件的 outputs 列表中的每个参数
event.getOutputs().forEach(param -> {
processParam(recordData, param);
});
}
}
private void processParam(RecordData recordData, Param param) {
// 获取参数的默认值和比较类型
Double defaultValue = param.getDefaultValue();
Param.CompareType compareType = param.getCompareType();
String identifier = param.getIdentifier();
// 检查 recordData 的内容中是否包含该参数的标识符
if (recordData.getContent().get(identifier) != null) {
try {
// 获取参数的实际值
double value = Double.parseDouble(recordData.getContent().get(identifier).toString());
// 根据比较类型进行不同的处理
switch (compareType) {
case GT:
if (value > defaultValue) {
eventPublisher.publishEvent(new TemperatureExceededEvent(this, recordData, value));
}
break;
case LT:
if (value < defaultValue) {
eventPublisher.publishEvent(new TemperatureExceededEvent(this, recordData, value));
}
break;
case EQ:
if (value == defaultValue) {
eventPublisher.publishEvent(new TemperatureExceededEvent(this, recordData, value));
}
break;
default:
// 处理未知的比较类型
System.err.println("Unknown compare type: " + compareType);
break;
}
} catch (NumberFormatException e) {
// 处理数值转换异常
System.err.println("Failed to parse value for identifier: " + identifier + ". Error: " + e.getMessage());
}
}
}
}

View File

@ -44,6 +44,16 @@ public class Param extends BaseParam {
*/
private Long foreignId;
/**
* 对比类型
*/
private CompareType compareType;
/**
* 默认数值
*/
private Double defaultValue;
public enum Type implements IEnum<String>, IState<Type> {
/**
* 物模型输入
@ -109,4 +119,36 @@ public class Param extends BaseParam {
return this.description;
}
}
public enum CompareType implements IEnum<Integer>, IState<CompareType> {
/**
* 大于
*/
GT(1, ">"),
/**
* 小于
*/
LT(2, "<"),
/**
* 等于
*/
EQ(3, "=");
private final int value;
private final String description;
CompareType(int value, String description) {
this.value = value;
this.description = description;
}
@Override
public Integer getValue() {
return value;
}
@Override
public String toString() {
return this.description;
}
}
}

View File

@ -9,7 +9,10 @@ import com.zsc.edu.gateway.modules.iot.tsl.mapper.EventMapper;
import com.zsc.edu.gateway.modules.iot.tsl.repo.EventRepository;
import com.zsc.edu.gateway.modules.iot.tsl.service.EventService;
import com.zsc.edu.gateway.modules.iot.tsl.service.ParamService;
import jakarta.annotation.Resource;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

View File

@ -934,5 +934,10 @@ ALTER TABLE iot_device
ALTER COLUMN longitude SET DEFAULT 113.39,
ALTER COLUMN latitude SET DEFAULT 22.52;
ALTER TABLE iot_param
ALTER COLUMN contrast_type SET DEFAULT NULL;
ALTER TABLE iot_param
ALTER COLUMN "default_value " SET DEFAULT NULL;

View File

@ -1,14 +1,20 @@
create table iot_param
(
id bigserial not null
id bigint generated by default as identity
constraint iot_param_name_pk
primary key,
data_type integer,
uint varchar,
type integer,
identifier varchar,
name varchar,
remark varchar
data_type integer,
uint varchar,
type varchar,
identifier varchar,
name varchar,
remark varchar,
foreign_id bigint,
foreign_type integer,
dept_id bigint,
create_id bigint,
contrast_type integer,
"default_value " double precision
);
comment on table iot_param is '参数';
@ -27,6 +33,18 @@ comment on column iot_param.name is '名称';
comment on column iot_param.remark is '备注';
comment on column iot_param.foreign_id is '联表id';
comment on column iot_param.foreign_type is '关联类型';
comment on column iot_param.dept_id is '部门权限id';
comment on column iot_param.create_id is '创建人id';
comment on column iot_param.contrast_type is '对比类型';
comment on column iot_param."default_value " is '默认数值';
alter table iot_param
owner to gitea;

View File

@ -60,9 +60,9 @@ public class ParamServiceTest {
@Test
void createParams() {
ParamDto dto = new ParamDto("PARAM_NAME_3", "测试1", "备注", DataType.DATE, Param.Type.OUTPUT);
// ParamDto dto = new ParamDto("PARAM_NAME_3", "测试1", "备注", DataType.DATE, Param.Type.OUTPUT);
List<ParamDto> params = new ArrayList<>();
params.add(dto);
// params.add(dto);
Long foreignId = 1L;
Boolean result = service.create(params, foreignId, null);
assertTrue(result);