package com.casic.service.impl; import cn.hutool.core.util.ObjectUtil; import com.alibaba.druid.util.StringUtils; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.casic.dao.AlarmRecordMapper; import com.casic.dao.BusWellInfoMapper; import com.casic.dao.DataH2sMapper; import com.casic.enums.H2sParamsEnum; import com.casic.model.AlarmRecord; import com.casic.model.BusWellInfo; import com.casic.model.DataH2s; import com.casic.model.User; import com.casic.service.ThirdDataService; import com.casic.util.RedisCommon; import com.casic.util.SMSSendUtil; import com.casic.util.WebSocket; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.dao.DataAccessException; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.*; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; @Service @Slf4j @RequiredArgsConstructor public class ThirdDataServiceImpl extends ServiceImpl<DataH2sMapper, DataH2s> implements ThirdDataService, H2sParamsEnum { private final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA); private final RedisCommon redisCommon; private final AlarmRecordMapper alarmRecordMapper; private final BusWellInfoMapper wellMapper; private final WebSocket webSocket; private final SMSSendUtil smsUtil; private final DataScopeBuilder dataScopeBuilder; @Value("${casic.device.apn}") private String apn; private final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 60, TimeUnit.SECONDS, new LinkedBlockingDeque<>(10)); @Override public Object h2sData(Map<String, String> h2sDataMap) { try { if (h2sDataMap.containsKey(ICCID)) { //开机上报->存储映射管理->查询是否有下发配置-进行回应 return powerOnReport(h2sDataMap); } else if (h2sDataMap.containsKey(H2S_VALUE)) { //数据上报 if (ObjectUtils.isNotEmpty(h2sDataMap.get(DEVCODE))) { String devcode = ((String) h2sDataMap.get(DEVCODE)).toUpperCase(); //清除离线-清除报警-报警-存库-查询是否有下发配置-进行回应 return dataSave(h2sDataMap, devcode); } } } catch (DataAccessException dae) { log.error("设备上报数据异常,设备传入的json是{},异常信息{}", h2sDataMap, dae.getMessage()); } return defaultDeliveryConfig(null); } @Override public void configConfirm(Map<String, String> configConfirmMap) { if (configConfirmMap.containsKey(DEVCODE) && !StringUtils.isEmpty(configConfirmMap.get(DEVCODE))) { String devcode = ((String) configConfirmMap.get(DEVCODE)).toUpperCase(); this.baseMapper.configConfirm(devcode); } } private Map<String, Object> defaultDeliveryConfig(Map<String, Object> configDataMap) { Map<String, Object> map = new HashMap(); //必带参数,否则会被thingsboard舍弃 map.put("method", "setParams"); //判断是否有下发配置必须 map.put("status", ObjectUtils.isNotEmpty(configDataMap) ? 200 : 201); if (ObjectUtils.isNotEmpty(configDataMap) && configDataMap.containsKey("interval")) { configDataMap.put("interval", String.valueOf(configDataMap.get("interval"))); configDataMap.put("port", String.valueOf(configDataMap.get("port"))); configDataMap.put("apn", apn); configDataMap.put("period", String.valueOf(configDataMap.get("period")) ); configDataMap.put("repeat", String.valueOf(configDataMap.get("repeat")) ); configDataMap.put("thresh", String.valueOf(configDataMap.get("thresh")) ); } map.put("params", configDataMap); //可省略 map.put("timeout", 30000); if (ObjectUtils.isNotEmpty(configDataMap)) { log.info("发送配置信息到things board: {}", map); } return map; } /** * 开机上报->储存,是否有下发配置,选择合适的格式返回 * * @param h2sDataMap */ private Map<String, Object> powerOnReport(Map<String, String> h2sDataMap) { /** * 三码上报 */ String iccid = (String) h2sDataMap.get(ICCID); String imei = (String) h2sDataMap.get(IMEI); String devcode = (String) h2sDataMap.get(DEVCODE); //清除离线 this.baseMapper.clearOnline(devcode); //先查,是否有数据,有数据直接覆盖,否则插入数据 String isImei = this.baseMapper.getImeiByDevcode(devcode); int save = StringUtils.isEmpty(isImei) ? this.baseMapper.addImeiDevcode(devcode, imei, iccid) : this.baseMapper.updateImeiDevcode(devcode, imei, iccid); if (save > 0) { //保存三码关系 Map<String, Object> configDataMap = redisCommon.getMsg((String) h2sDataMap.get(DEVCODE)); if (ObjectUtils.isNotEmpty(configDataMap)) { return defaultDeliveryConfig(configDataMap); } } else { throw new RuntimeException("三码上传保存异常,异常数据为" + JSON.toJSON(h2sDataMap)); } return defaultDeliveryConfig(null); } private Map<String, Object> dataSave(Map<String, String> h2sDataMap, String devcode) { DataH2s dataH2s = initH2sData(h2sDataMap, devcode); this.baseMapper.clearOnline(devcode); if (ObjectUtils.isNotEmpty(dataH2s)) { checkAlarm(dataH2s); Map<String, Object> configDataMap = redisCommon.getMsg(devcode); if (ObjectUtils.isNotEmpty(configDataMap)) { log.info("有需要下发的配置项: {}", configDataMap); return defaultDeliveryConfig(configDataMap); } } return defaultDeliveryConfig(null); } private DataH2s initH2sData(Map<String, String> h2sDataMap, String devcode) { DataH2s dataH2s = new DataH2s(); String wellCode = this.baseMapper.getWellCode(devcode); dataH2s.setWellCode(wellCode); dataH2s.setDevcode(devcode); dataH2s.setSnr(h2sDataMap.get(SIGNAL_STRENGTH)); dataH2s.setStrength((String) h2sDataMap.get(H2S_VALUE)); dataH2s.setCell((String) h2sDataMap.get(BATTERY_VALUE)); dataH2s.setUptime(dateFormat.format(new Date())); dataH2s.setLogtime(dateFormat.format(new Date())); this.baseMapper.insert(dataH2s); return dataH2s; } /** * 检查是否有报警 * * @param dataH2s */ private void checkAlarm(DataH2s dataH2s) { final Float ruleValue = this.baseMapper.getRuleValue("14"); if (ruleValue == null) { return; } if (!StringUtils.isEmpty(dataH2s.getStrength()) && !"null".equals(dataH2s.getStrength())) { String status = "0"; int currAlarmCount = this.baseMapper.cancelAlarm(dataH2s.getDevcode(), status); if (Float.parseFloat(dataH2s.getStrength()) > ruleValue) { Long id = this.baseMapper.getDeviceId(dataH2s.getDevcode()); alarmRecordMapper.insert(buildAlarmRecord(dataH2s, id)); // 推送websocket 一直超限可以一直推送websocket消息 threadPoolExecutor.execute(() -> sendAlarm("硫化氢浓度超限", dataH2s.getDevcode(), dataH2s.getStrength(), this.baseMapper.getDeptIdsByDevcode(dataH2s.getDevcode()))); // 是新报警的时候才推送报警短信 if (currAlarmCount == 0) { threadPoolExecutor.execute(() -> sendAlarmSms("检测到硫化氢浓度超限", dataH2s.getWellCode(), dataH2s.getStrength(), dataH2s.getUptime())); } } } } private AlarmRecord buildAlarmRecord(DataH2s dataH2s, Long deviceId) { AlarmRecord alarmRecord = AlarmRecord.builder() .devcode(dataH2s.getDevcode()) .wellCode(dataH2s.getWellCode()) .alarmMessage("浓度超限") .alarmValue(dataH2s.getStrength()) .deviceId(deviceId) .alarmType("1") .alarmContent("浓度超限") .status("1") .build(); return alarmRecord; } // PC推送 private void sendAlarm(String msg, String devCode, String value, Long deptId) { List<String> userIds = new ArrayList<>(); List<User> userList = dataScopeBuilder.DataScopeProvider(deptId); for (User user : userList) { userIds.add(user.getId().toString()); } if (userIds.size() > 0) { Map<String, Object> map = new HashMap<String, Object>(); map.put("message", msg); map.put("type", "alarm"); map.put("deviceNo", devCode); map.put("value", value); webSocket.sendListMessage(userIds, JSON.toJSONString(map)); } else { log.info("告警消息找不到责任人,pc端未推送:" + msg); } } private void sendAlarmSms(String msg, String wellCode, String value, String alarmTime) { BusWellInfo wellInfo = wellMapper.getWellListByCode(wellCode); if (null != wellInfo && ObjectUtil.isNotEmpty(wellInfo.getTel())) { // 拼接报警信息 String content = msg + "," + // 发现硫化氢泄漏, "点位:" + wellInfo.getWellName() + ",详细位置:" + wellInfo.getPosition() + "," + // 点位:名称,位置, "浓度值:" + value + "ppm," + // 浓度值 "时间:" + alarmTime + "," + // 时间 "请及时处理。"; // 请及时处理。 smsUtil.sendSms(wellInfo.getTel(), content); } } }