2021与蓝度共同重构项目,服务端
fix
zhanzhiqin
2022-09-26 e6ca7ead72de88017eb786fbfc5d8450b8164878
fix
已修改5个文件
已添加4个文件
410 ■■■■■ 文件已修改
dao/src/main/java/com/sandu/ximon/dao/enums/MenuEnum.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/controller/LightController.java 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/amqp/processor/LightDataProcessor.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/report/A5LightOperationReportInnerFrame.java 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/request/A5LightSetCalendarReqInnerFrame.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/enums/A5LightDataEnum.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/param/LightSetCalendarParam.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/schedule/LightTimeSynchronizationSchedule.java 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/service/LightService.java 166 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
dao/src/main/java/com/sandu/ximon/dao/enums/MenuEnum.java
@@ -26,6 +26,7 @@
    GROUP_LIST("分组列表"),
    LIGHT_TASK_LIST("路灯任务列表"),
    LIGHT_DATA("单灯监控数据"),
    LIGHT_SETCALENDAR("单灯设置日历"),
    LIGHT_ERROR_LIST("单灯故障列表"),
    LED_LIST("LED屏列表"),
    LED_PROGRAM_LIST("节目列表"),
ximon-admin/src/main/java/com/sandu/ximon/admin/controller/LightController.java
@@ -3,10 +3,11 @@
import com.sandu.common.domain.CommonPage;
import com.sandu.common.domain.ResponseVO;
import com.sandu.common.object.BaseConditionVO;
import com.sandu.common.security.annotation.AnonymousAccess;
import com.sandu.common.util.ResponseUtil;
import com.sandu.ximon.admin.param.LightControlParam;
import com.sandu.ximon.admin.param.LightPowerSettingParam;
import com.sandu.ximon.admin.param.LightRemarkParam;
import com.sandu.common.util.SpringContextHolder;
import com.sandu.ximon.admin.param.*;
import com.sandu.ximon.admin.schedule.LightTimeSynchronizationSchedule;
import com.sandu.ximon.admin.security.PermissionConfig;
import com.sandu.ximon.admin.service.LightEnergyDataService;
import com.sandu.ximon.admin.service.LightReportDataService;
@@ -178,4 +179,24 @@
        return ResponseUtil.success(reportDataList);
    }
    /**
     * è®¾ç½®æ—¥åŽ†ï¼ˆåŒå¿ƒè·³åŒ…ä¸­çš„6字节日期时间)
     */
    @PostMapping("/SetCalendar")
    public ResponseVO<Object> SetCalendar(@RequestBody @Validated LightSetCalendarParam lightSetCalendarParam) {
        if (!permissionConfig.check(MenuEnum.LIGHT_SETCALENDAR.getCode())) {
            return ResponseUtil.fail("缺少对应用户权限");
        }
        return ResponseUtil.success(lightService.SetCalendar(lightSetCalendarParam.getLightId(), lightSetCalendarParam.getAddress()));
    }
    @AnonymousAccess
    @GetMapping("/test")
    public ResponseVO<Object> test() {
        SpringContextHolder.getBean(LightTimeSynchronizationSchedule.class).UserSubjectRefund();
        return ResponseUtil.success(null);
    }
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/amqp/processor/LightDataProcessor.java
@@ -49,9 +49,13 @@
            }
        } else if (A5LightReportEnum.Time_Synchronized.getCode().equals(functionCode)) {
//            log.info("请求时间同步");
            log.info("请求时间同步");
            A5LightTimeSyncReportInnerFrame syncRespInnerFrame = new A5LightTimeSyncReportInnerFrame().transformFrame(frame.getPayload());
//            log.info(syncRespInnerFrame.toString());
            log.info(syncRespInnerFrame.toString());
            if (syncRespInnerFrame.isValidate()) {
                SpringContextHolder.getBean(LightService.class).timeSynchronizationInitiative(deviceName, syncRespInnerFrame.getDestinationAddress());
            }
        } else if (A5LightReportEnum.Error_Code.getCode().equals(functionCode)) {
            log.info("故障码上报");
            A5LightErrorCodeReportInnerFrame codeRespInnerFrame = new A5LightErrorCodeReportInnerFrame().transformFrame(frame.getPayload());
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/report/A5LightOperationReportInnerFrame.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,68 @@
package com.sandu.ximon.admin.manager.iot.frame.inner.report;
import cn.hutool.core.util.StrUtil;
import com.sandu.ximon.admin.manager.iot.frame.inner.BaseResponseInnerFrame;
import com.sandu.ximon.admin.manager.iot.rrpc.util.CRC32Utils;
import lombok.Data;
import lombok.ToString;
/**
 * @author ZZQ
 * @date 2022/3/14 16:36
 * å•灯操作指令响应帧
 */
@Data
@ToString(callSuper = true)
public class A5LightOperationReportInnerFrame extends BaseResponseInnerFrame<A5LightOperationReportInnerFrame> {
    //MAC地址
    private String address;
    private String state;
    @Override
    public A5LightOperationReportInnerFrame transformFrame(String hex) {        //  é•¿åº¦ä¸ä¸€è‡´æ—¶ï¼Œè¿”回null
        if (StrUtil.isBlank(hex)) {
            return null;
        }
        // MQTT通信方式(1)
        setConnectType(hex.substring(0, 2));
        //  åŠŸèƒ½ç (1)
        setFunctionCode(hex.substring(2, 4));
        //  è´Ÿè·é•¿åº¦(2)
        setPayloadLength(hex.substring(4, 8));
        //MAC地址
        setAddress(hex.substring(8, 12));
        //硬件交互响应结果
        setState(returnState(hex.substring(12, 14)));
        setCrc32(hex.substring(hex.length() - 8));
        //  æ ¡éªŒCRC32
        String frame = hex.substring(2, hex.length() - 8);
        this.setValidate(CRC32Utils.validateFrame(frame, getCrc32()));
        return this;
    }
    public String returnState(String stateCode) {
        String State = "";
        switch (stateCode) {
            case "00":
                State = "操作成功";
                break;
            case "01":
                State = "校验码错误";
                break;
            case "02":
                State = "长度错误";
                break;
            case "03":
                State = "写Flash失败错误";
                break;
            case "FF":
                State = "其他错误";
                break;
            default:
                State = "未知错误";
        }
        return State;
    }
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/request/A5LightSetCalendarReqInnerFrame.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,34 @@
package com.sandu.ximon.admin.manager.iot.frame.inner.request;
import com.sandu.ximon.admin.manager.iot.frame.inner.IRequestInnerFrame;
import com.sandu.ximon.admin.manager.iot.rrpc.enums.A5LightDataEnum;
import com.sandu.ximon.admin.manager.iot.rrpc.enums.C3ChargingEnum;
import com.sandu.ximon.admin.manager.iot.rrpc.enums.MQTTConnectTypeEnum;
import com.sandu.ximon.admin.manager.iot.rrpc.util.CRC32Utils;
/**
 * å•灯设置日历
 *
 * @author ZZQ
 * @date 2022/3/3 16:43
 */
public class A5LightSetCalendarReqInnerFrame implements IRequestInnerFrame {
    private final String payload;
    public A5LightSetCalendarReqInnerFrame(String lightAddress, int year, int month, int day, int hour, int min, int sec) {
        payload = lightAddress + hex10To16(year) + hex10To16(month) + hex10To16(day) + hex10To16(hour) + hex10To16(min) + hex10To16(sec);
    }
    @Override
    public String getEncodeFrame() {
        String functionCode = A5LightDataEnum.SetCalendar.getCode();
        String payloadLength = "0008";
        String frame = functionCode + payloadLength + payload;
        return MQTTConnectTypeEnum.SYNCHRONIZATION.getCode() + frame.toUpperCase() + CRC32Utils.getCRC32(frame.toUpperCase());
    }
    private String hex10To16(int value) {
        return String.format("%02X", value);
    }
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/enums/A5LightDataEnum.java
@@ -14,10 +14,13 @@
    //  å…‰æ„ŸæŽ§åˆ¶
    LightSensorControl("04"),
    //设置定时控灯参数
    LightTimer("23"),
    // æ¸…除单灯累计数据
    LightReset("25"),
    //设置日历(同心跳包中的6字节日期时间)
    SetCalendar("28"),
    LIGHT_HEART_BEAT("LightReportData:light_heart_beat/");
    A5LightDataEnum(String code) {
ximon-admin/src/main/java/com/sandu/ximon/admin/param/LightSetCalendarParam.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,20 @@
package com.sandu.ximon.admin.param;
import lombok.Data;
import javax.validation.constraints.NotNull;
/**
 * @author ZZQ
 * @date 2022/3/3 18:07
 */
@Data
public class LightSetCalendarParam {
    @NotNull(message = "单灯ID不能为空")
    private Long lightId;
    /**
     * ç¯å¤´åœ°å€
     */
    private String address;
}
ximon-admin/src/main/java/com/sandu/ximon/admin/schedule/LightTimeSynchronizationSchedule.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,83 @@
package com.sandu.ximon.admin.schedule;
import com.alibaba.fastjson.JSONObject;
import com.sandu.common.util.SpringContextHolder;
import com.sandu.ximon.admin.service.LightService;
import com.sandu.ximon.admin.service.LightTaskPoleRelationService;
import com.sandu.ximon.dao.domain.Light;
import com.sandu.ximon.dao.domain.LightTask;
import com.sandu.ximon.dao.domain.LightTaskPoleRelation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.stream.Collectors;
/**
 * å•灯同步时间定时
 */
@Component
@Slf4j
@AllArgsConstructor
@EnableScheduling
public class LightTimeSynchronizationSchedule {
    private final LightService lightService;
    private final LightTaskPoleRelationService lightTaskPoleRelationService;
    //每天02:00 å¼€å§‹æ‰§è¡Œ
    @Scheduled(cron = "0 0 2 * * ? ")
    public void UserSubjectRefund() {
        //所有单灯数据
        List<Light> lightList = lightService.list();
        //单灯任务
        List<LightTaskPoleRelation> lightTaskPoleRelationList =
                lightTaskPoleRelationService.list();
        /**
         * åŽ»é™¤æ— æ•ˆæ•°æ®
         */
        lightTaskPoleRelationList = lightTaskPoleRelationList.stream().filter(bean -> bean.getDeviceScheduled() != null).collect(Collectors.toList());
        Map<String, LightTask> map = new HashMap<>();
        for (LightTaskPoleRelation bean : lightTaskPoleRelationList) {
            LightTask lightTask = JSONObject.parseObject(bean.getDeviceScheduled(), LightTask.class);
            map.put(bean.getDeviceCode() + bean.getLightAddress(), lightTask);
        }
        for (Light light : lightList) {
            if (map.get(light.getDeviceCode() + "0001") != null) {
                /**
                 * å‚æ•°1:单灯信息
                 * å‚æ•°2:单灯任务
                 */
                lightService.timeSynchronization(light, "0001", map.get(light.getDeviceCode() + "0001"));
            } else {
                /**
                 * å‚æ•°1:单灯信息
                 * å‚æ•°2:任务为null
                 */
                lightService.timeSynchronization(light, "0001", null);
            }
            if (map.get(light.getDeviceCode() + "0002") != null) {
                /**
                 * å‚æ•°1:单灯信息
                 * å‚æ•°2:单灯任务
                 */
                lightService.timeSynchronization(light, "0002", map.get(light.getDeviceCode() + "0002"));
            } else {
                /**
                 * å‚æ•°1:单灯信息
                 * å‚æ•°2:任务为null
                 */
                lightService.timeSynchronization(light, "0002", null);
            }
        }
    }
}
ximon-admin/src/main/java/com/sandu/ximon/admin/service/LightService.java
@@ -3,6 +3,7 @@
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.iot.model.v20180120.BatchGetDeviceStateResponse;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.PageHelper;
@@ -14,8 +15,11 @@
import com.sandu.ximon.admin.dto.LightTaskDto;
import com.sandu.ximon.admin.manager.iot.frame.A5Frame;
import com.sandu.ximon.admin.manager.iot.frame.inner.report.A5LightHeartbeatReportInnerFrame;
import com.sandu.ximon.admin.manager.iot.frame.inner.report.A5LightOperationReportInnerFrame;
import com.sandu.ximon.admin.manager.iot.frame.inner.request.A5LightBrightnessReqInnerFrame;
import com.sandu.ximon.admin.manager.iot.frame.inner.request.A5LightSetCalendarReqInnerFrame;
import com.sandu.ximon.admin.manager.iot.frame.inner.response.A5LightBrightnessRespInnerFrame;
import com.sandu.ximon.admin.manager.iot.rrpc.dto.CommonFrame;
import com.sandu.ximon.admin.manager.iot.rrpc.dto.WrapResponseCommonFrame;
import com.sandu.ximon.admin.manager.iot.rrpc.enums.A5OrderEnum;
import com.sandu.ximon.admin.manager.iot.rrpc.mainboard.MainBoardInvokeSyncService;
@@ -25,7 +29,6 @@
import com.sandu.ximon.admin.redis.DeviceRedisKey;
import com.sandu.ximon.admin.redis.LightKey;
import com.sandu.ximon.admin.security.SecurityUtils;
import com.sandu.ximon.admin.utils.RedisUtils;
import com.sandu.ximon.admin.utils.StoreOperationRecordsUtils;
import com.sandu.ximon.admin.vo.ControlLightCommandVO;
import com.sandu.ximon.admin.vo.EquipmentInfomation;
@@ -43,10 +46,7 @@
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.stream.Collectors;
/**
@@ -63,7 +63,6 @@
    private final LightReportDataService lightReportDataService;
    private final PoleBindingService bindingService;
    private final PoleService poleService;
    private final RedisUtils redisUtils;
    /**
     * å½•入当前设备码的路灯数据
@@ -961,4 +960,159 @@
    }
    /**
     * è®¾ç½®æ—¥åŽ†ï¼ˆåŒå¿ƒè·³åŒ…ä¸­çš„6字节日期时间)
     *
     * @return
     */
    public String SetCalendar(Long lightId, String address) {
        Calendar cal = Calendar.getInstance();
        //获取当前时间
        int year = cal.get(Calendar.YEAR);
        int month = cal.get(Calendar.MONTH);
        int day = cal.get(Calendar.DATE);
        int hour = cal.get(Calendar.HOUR_OF_DAY);
        int min = cal.get(Calendar.MINUTE);
        int sec = cal.get(Calendar.SECOND);
        if (!"0001".equals(address) && !"0002".equals(address)) {
            throw new BusinessException("灯头地址错误!");
        }
        Light one = getById(lightId);
        if (one == null) {
            System.out.println("单灯不存在!");
        }
        A5LightSetCalendarReqInnerFrame setCalendarReqInnerFrame =
                new A5LightSetCalendarReqInnerFrame(address, year, month, day, hour, min, sec);
        A5Frame a5Frame = new A5Frame(A5OrderEnum.REQUEST_LIGHT_DATA.getCode(), setCalendarReqInnerFrame);
        System.out.println(a5Frame + "            -----a5Frame");
        CommonFrame commonFrame;
        commonFrame = MainBoardInvokeSyncService.getInstance().sendRRPC(one.getDeviceCode(), a5Frame);
        StoreOperationRecordsUtils.storeInnerFrameData(one.getDeviceCode(), "单灯帧-设置日历", a5Frame, commonFrame);
        System.out.println(commonFrame + "            -----commonFrame");
        A5LightOperationReportInnerFrame operationReportInnerFrame = new A5LightOperationReportInnerFrame().transformFrame(commonFrame.getPayload());
        if (operationReportInnerFrame.isValidate()) {
            return operationReportInnerFrame.getState();
        } else {
            throw new BusinessException("数据校验错误,请重新请求");
        }
    }
    /**
     * å•灯主动同步时间请求
     */
    public void timeSynchronizationInitiative(String deviceCode, String lightAddress) {
        //单灯信息
        Light light = getLight(deviceCode);
        if (light == null) {
            log.error("单灯主动同步时间请求异常,单灯信息不存在!");
        }
        //单灯任务信息
        LightTaskPoleRelation lightTaskPoleRelation = SpringContextHolder.getBean(LightTaskPoleRelationService.class)
                .getOne(Wrappers.lambdaQuery(LightTaskPoleRelation.class)
                        .eq(LightTaskPoleRelation::getDeviceCode, deviceCode).eq(LightTaskPoleRelation::getLightAddress, lightAddress));
        LightTask lightTask = null;
        //灯头没有任务
        if (lightTaskPoleRelation != null) {
            if (lightTaskPoleRelation.getDeviceScheduled() != null) {
                lightTask = JSONObject.parseObject(lightTaskPoleRelation.getDeviceScheduled(), LightTask.class);
            }
        }
        timeSynchronization(light, lightAddress, lightTask);
    }
    /**
     * å•灯时间同步
     *
     * @param light     å•灯信息实体
     * @param lightTask å•灯任务实体(为空标识单灯没有定时任务)
     */
    public void timeSynchronization(Light light, String lightAddress, LightTask lightTask) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                //获取当前时间时、分
                Calendar cal = Calendar.getInstance();
                if (lightTask != null) {
                    String closeOrder = lightTask.getCloseOrder();
                    String openOrder = lightTask.getOpenOrder();
                    String controlOrder = lightTask.getControlOrder() == null ? null : lightTask.getControlOrder();
                    List<String> timeList = new ArrayList<>();
                    timeList.add(openOrder.substring(0, 4));
                    timeList.add(closeOrder.substring(0, 4));
                    if (controlOrder != null && controlOrder.length() % 7 == 0) {
                        for (int i = 0; i < controlOrder.length() / 7; i++) {
                            timeList.add(controlOrder.substring(i * 7, i * 7 + 4));
                        }
                    } else {
                        log.error("控灯指令不正确,数据长度不为7的倍数!");
                        return;
                    }
                    //时间排序
                    timeList = timeList.stream().sorted().collect(Collectors.toList());
                    int count = 0;
                    boolean haveTime = false;
                    while (!haveTime && count <= 144) {
                        haveTime = judgeTime(cal, timeList);
                        cal.add(Calendar.MINUTE, 10);
                        count++;
                    }
                    if (haveTime) {
                        try {
                            long longTime = cal.getTimeInMillis() - System.currentTimeMillis();
                            log.error("睡眠时间(毫秒):" + longTime);
                            Thread.sleep(longTime);
                            SetCalendar(light.getLightId(), lightAddress);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    } else {
                        log.error("灯杆ID为:" + light.getLightId() + ",灯头地址为:" + lightAddress + "没有找到可同步的时间,请检查任务!");
                    }
                } else {
                    SetCalendar(light.getLightId(), lightAddress);
                }
            }
        }).start();
    }
    /**
     * åˆ¤æ–­æ—¶é—´æ˜¯å¦å¯ä»¥æ‰§è¡ŒåŒæ­¥æŒ‡ä»¤
     *
     * @param time
     * @param timeList
     * @return true å¯ä»¥æ‰§è¡Œ  ,false  ä¸å¯æ‰§è¡Œ
     */
    private boolean judgeTime(Calendar time, List<String> timeList) {
        int hour = time.get(Calendar.HOUR_OF_DAY);
        int min = time.get(Calendar.MINUTE);
        int allMin = hour * 60 + min;
        for (String value : timeList) {
            int targetHour = Integer.valueOf(value.substring(0, 2));
            int targetMin = Integer.valueOf(value.substring(2, 4));
            int allTargetMin = targetHour * 60 + targetMin;
            if (allMin >= allTargetMin - 10 && allMin <= allTargetMin + 10) {
                return false;
            } else {
                continue;
            }
        }
        return true;
    }
}