9个文件已修改
13个文件已添加
976 ■■■■■ 已修改文件
pipIrr-platform/pipIrr-global/src/main/java/com/dy/pipIrrGlobal/daoLargeScreen/Ls4StatisticsMapper.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pipIrr-platform/pipIrr-global/src/main/java/com/dy/pipIrrGlobal/voMd/VoCropsSimple.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pipIrr-platform/pipIrr-global/src/main/java/com/dy/pipIrrGlobal/voMd/VoEt0Simple.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pipIrr-platform/pipIrr-global/src/main/resources/application-global.yml 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pipIrr-platform/pipIrr-global/src/main/resources/mapper/Ls4StatisticsMapper.xml 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pipIrr-platform/pipIrr-web/pipIrr-web-model/src/main/java/com/dy/pipIrrModel/modelCalculate/Hargreaves.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pipIrr-platform/pipIrr-web/pipIrr-web-statistics/src/main/java/com/dy/pipIrrStatistics/largeScreen/Ls4StatisticsCtrl.java 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pipIrr-platform/pipIrr-web/pipIrr-web-statistics/src/main/java/com/dy/pipIrrStatistics/largeScreen/Ls4StatisticsSv.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/command/MqttResultCtrl.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/common/Cd4MqttParameter.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/common/Com4MqttCtrl.java 193 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/common/Com4MqttSv.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/common/Dto4MqttBase.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/mqtt/MonitorMqttCdParam.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/mqtt/MonitorMqttDto.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/mqtt/MonitorMqttFaultCtrl.java 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/mqtt/MonitorMqttInjectCtrl.java 143 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/mqtt/MonitorMqttStirCtrl.java 143 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/mqtt/MonitorMqttSv.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/mqtt/VoManureLast.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/mqtt/VoSoilLast.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/mqtt/VoWeatherLast.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pipIrr-platform/pipIrr-global/src/main/java/com/dy/pipIrrGlobal/daoLargeScreen/Ls4StatisticsMapper.java
@@ -1,8 +1,11 @@
package com.dy.pipIrrGlobal.daoLargeScreen;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.dy.pipIrrGlobal.voMd.VoCrops;
import com.dy.pipIrrGlobal.voSpecial.VoTopXClient;
import com.dy.pipIrrGlobal.voSpecial.VoTopXIntake;
import com.dy.pipIrrGlobal.voMd.VoCropsSimple;
import com.dy.pipIrrGlobal.voMd.VoEt0Simple;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@@ -143,4 +146,19 @@
    List<VoTopXIntake> topXIntakeAtCertainDay(@Param("idStart") Long idStart, @Param("idEnd") Long idEnd, @Param("count") int count) ;
    /**
     * 所有作物
     * @return 实体集合
     */
    List<VoCropsSimple> allCropts() ;
    /**
     * 所有作物
     * @return 实体集合
     */
    List<VoEt0Simple> et0InWeek(@Param("cropId") Long cropId, @Param("startDate")String startDate, @Param("endDate")String endDate) ;
}
pipIrr-platform/pipIrr-global/src/main/java/com/dy/pipIrrGlobal/voMd/VoCropsSimple.java
New file
@@ -0,0 +1,32 @@
package com.dy.pipIrrGlobal.voMd;
import com.alibaba.fastjson2.annotation.JSONField;
import com.alibaba.fastjson2.writer.ObjectWriterImplToString;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import lombok.Data;
import java.io.Serializable;
/**
 * @Author: liurunyu
 * @Date: 2025/8/21 11:42
 * @Description
 */
@Data
@JsonPropertyOrder({"id", "name" })
public class VoCropsSimple implements Serializable {
    public static final long serialVersionUID = 202508211143001L;
    /**
     * 主键
     */
    @JSONField(serializeUsing= ObjectWriterImplToString.class)
    public Long id;
    /**
     * 作物名称
     */
    public String name;
}
pipIrr-platform/pipIrr-global/src/main/java/com/dy/pipIrrGlobal/voMd/VoEt0Simple.java
New file
@@ -0,0 +1,39 @@
package com.dy.pipIrrGlobal.voMd;
import com.alibaba.fastjson2.annotation.JSONField;
import com.alibaba.fastjson2.writer.ObjectWriterImplToString;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
 * @Author: liurunyu
 * @Date: 2025/8/21 11:44
 * @Description
 */
@Data
@JsonPropertyOrder({"id", "dt", "et0"})
public class VoEt0Simple implements Serializable {
    public static final long serialVersionUID = 202508211143002L;
    /**
     * 主键
     */
    @JSONField(serializeUsing= ObjectWriterImplToString.class)
    public Long id;
    @JsonFormat(pattern = "yyyy-MM-dd")
    public Date dt;
    /**
     * 蒸腾量
     */
    @Schema(description = "本日作物蒸腾量", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
    @JsonFormat(shape = JsonFormat.Shape.NUMBER, pattern = "0.00")
    public Double et0;
}
pipIrr-platform/pipIrr-global/src/main/resources/application-global.yml
@@ -378,6 +378,8 @@
    ugCallbackUrl_rm: "http://127.0.0.1:8081/remote/rtuUpgradeStateReceiver/receive"
    #微信小程序应用中Rtu远程命令结果回调地址
    rtuCallbackUrl_wx: "http://127.0.0.1:8087/wx/comRes/receive"
    #MQTT远程命令结果回调地址
    mqttCallbackUrl_wx: "http://127.0.0.1:8087/wx/mqttRes/receive"
    waitMwRtnResultTimeout: 10 #等待中间件返回结果超时时间,单位秒钟
#不进行userToken过滤的URL,@ConfigurationProperties要求tokennofilter中所有字母都小写
pipIrr-platform/pipIrr-global/src/main/resources/mapper/Ls4StatisticsMapper.xml
@@ -321,4 +321,24 @@
        </trim>
    </select>
    <select id="allCropts" resultType="com.dy.pipIrrGlobal.voMd.VoCropsSimple">
        select mTb.id as id, mTb.name as name
        from md_crops mTb
        where mTb.deleted != 1
        order by mTb.id DESC
    </select>
    <select id="et0InWeek" resultType="com.dy.pipIrrGlobal.voMd.VoEt0Simple">
        select mTb.id as id, mTb.dt as dt, mTb.et0 as et0
        from md_et0 mTb
        <where>
            <if test="cropId != null">
                AND mTb.crop_id = #{cropId}
            </if>
            <if test = "startDate != null and startDate !='' and endDate != null and endDate != ''">
                AND mTb.dt BETWEEN #{startDate} AND #{endDate}
            </if>
        </where>
        order by mTb.id ASC
    </select>
</mapper>
pipIrr-platform/pipIrr-web/pipIrr-web-model/src/main/java/com/dy/pipIrrModel/modelCalculate/Hargreaves.java
@@ -121,11 +121,11 @@
    }
    public static void main(String[] args) {
        Double lat = 38.561976140977116 ;
        Integer dayIndex = 180 ;
        Double lat = 38.561976140977116 ;//纬度
        Integer dayIndex = 180 ;//年内日序数(比如1月1日为1,12月31日为365或366)
        Double kc = 0.41 ;//作物系数
        Double maxT = 40.1 ;//一日内最高温度
        Double minT = 40.1 ;//一日内最低温度
        Double minT = 28.1 ;//一日内最低温度
        Double fai = rad(lat);
        System.out.println(fai);
pipIrr-platform/pipIrr-web/pipIrr-web-statistics/src/main/java/com/dy/pipIrrStatistics/largeScreen/Ls4StatisticsCtrl.java
@@ -5,9 +5,13 @@
import com.dy.common.webUtil.BaseResponse;
import com.dy.common.webUtil.BaseResponseUtils;
import com.dy.common.webUtil.ResultCodeMsg;
import com.dy.pipIrrGlobal.pojoMd.MdEt0;
import com.dy.pipIrrGlobal.voLargeScreen.VoBaseInfo;
import com.dy.pipIrrGlobal.voLargeScreen.VoCurrentInfo;
import com.dy.pipIrrGlobal.voLargeScreen.VoMonitorInfo;
import com.dy.pipIrrGlobal.voMd.VoCrops;
import com.dy.pipIrrGlobal.voMd.VoCropsSimple;
import com.dy.pipIrrGlobal.voMd.VoEt0Simple;
import com.dy.pipIrrGlobal.voSpecial.VoTopXClient;
import com.dy.pipIrrGlobal.voSpecial.VoTopXIntake;
import io.swagger.v3.oas.annotations.Operation;
@@ -175,4 +179,45 @@
    }
    /**
     * 得到所有作物
     * @return 数据集合
     */
    @Operation(summary = "得到所有作物", description = "得到所有作物")
    @ApiResponses(value = {
            @ApiResponse(
                    responseCode = ResultCodeMsg.RsCode.SUCCESS_CODE,
                    description = "得到所有作物(BaseResponse.content:[VoTopXIntake{}])",
                    content = {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
                            schema = @Schema(implementation = VoCropsSimple.class))}
            )
    })
    @GetMapping(path = "allCropts")
    @SsoAop()
    public BaseResponse<List<VoCropsSimple>> allCropts(){
        List<VoCropsSimple> res = this.sv.allCropts();
        return BaseResponseUtils.buildSuccess(res);
    }
    /**
     * 得到一个作物一周内的蒸腾量
     * @return 数据集合
     */
    @Operation(summary = "一个作物一周内的蒸腾量", description = "一个作物一周内的蒸腾量")
    @ApiResponses(value = {
            @ApiResponse(
                    responseCode = ResultCodeMsg.RsCode.SUCCESS_CODE,
                    description = "一个作物一周内的蒸腾量(BaseResponse.content:[VoTopXIntake{}])",
                    content = {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
                            schema = @Schema(implementation = VoEt0Simple.class))}
            )
    })
    @GetMapping(path = "et0InWeek")
    @SsoAop()
    public BaseResponse<List<VoEt0Simple>> et0InWeek(Long cropId){
        List<VoEt0Simple> res = this.sv.et0InWeek(cropId);
        return BaseResponseUtils.buildSuccess(res);
    }
}
pipIrr-platform/pipIrr-web/pipIrr-web-statistics/src/main/java/com/dy/pipIrrStatistics/largeScreen/Ls4StatisticsSv.java
@@ -13,6 +13,8 @@
import com.dy.pipIrrGlobal.voLargeScreen.VoBaseInfo;
import com.dy.pipIrrGlobal.voLargeScreen.VoCurrentInfo;
import com.dy.pipIrrGlobal.voLargeScreen.VoMonitorInfo;
import com.dy.pipIrrGlobal.voMd.VoCropsSimple;
import com.dy.pipIrrGlobal.voMd.VoEt0Simple;
import com.dy.pipIrrGlobal.voSpecial.VoTopXClient;
import com.dy.pipIrrGlobal.voSpecial.VoTopXIntake;
import lombok.extern.slf4j.Slf4j;
@@ -170,4 +172,22 @@
        return this.dao.topXIntakeAtCertainDay(idStart, idEnd, 5) ;
    }
    /**
     * 所有作物
     * @return 实体集合
     */
    public List<VoCropsSimple> allCropts(){
        return this.dao.allCropts() ;
    }
    /**
     * 所有作物
     * @return 实体集合
     */
    public List<VoEt0Simple> et0InWeek(Long cropId){
        String startDate = DateTime.lastXDay_yyyy_MM_dd(8) ;//8天前
        String endDate = DateTime.lastXDay_yyyy_MM_dd(1) ;//昨天
        return this.dao.et0InWeek(cropId, startDate, endDate) ;
    }
}
pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/command/MqttResultCtrl.java
New file
@@ -0,0 +1,38 @@
package com.dy.pipIrrWechat.command;
import com.dy.common.mw.protocol4Mqtt.MqttSubMsg;
import com.dy.pipIrrGlobal.command.ComResultWait;
import com.dy.pipIrrGlobal.command.ComSupport;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.CompletableFuture;
/**
 * @author ZhuBaoMin
 * @date 2025/8/21 14:50
 * @Description
 */
@Slf4j
@RestController
@RequestMapping(path="mqttRes")
public class MqttResultCtrl extends ComSupport {
    @PostMapping(path = "receive", consumes = MediaType.APPLICATION_JSON_VALUE)
    public void receive(@RequestBody MqttSubMsg subMsg) {
        if(subMsg != null){
            CompletableFuture<MqttSubMsg> feature = (CompletableFuture<MqttSubMsg>) ComResultWait.get(Long.parseLong(subMsg.commandId));
            if(feature != null) {
                feature.complete(subMsg);
            }else{
                //超时,feature被清除了
            }
        }else{
            log.error("mqtt协议消息为空");
        }
    }
}
pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/common/Cd4MqttParameter.java
New file
@@ -0,0 +1,15 @@
package com.dy.pipIrrWechat.common;
import lombok.Data;
import lombok.experimental.SuperBuilder;
/**
 * @Author: liurunyu
 * @Date: 2025/8/21 14:53
 * @Description
 */
@Data
@SuperBuilder
public class Cd4MqttParameter {
    public Integer no ;//设备编号
}
pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/common/Com4MqttCtrl.java
New file
@@ -0,0 +1,193 @@
package com.dy.pipIrrWechat.common;
import com.dy.common.mw.protocol.Command;
import com.dy.common.mw.protocol4Mqtt.MqttSubMsg;
import com.dy.common.util.Callback;
import com.dy.common.util.IDLongGenerator;
import com.dy.common.webUtil.BaseResponse;
import com.dy.common.webUtil.BaseResponseUtils;
import com.dy.pipIrrGlobal.command.ComResultWait;
import com.dy.pipIrrGlobal.pojoPr.PrStManure;
import com.dy.pipIrrGlobal.pojoRm.RmCommandHistory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.validation.BindingResult;
import org.springframework.web.client.RestTemplate;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
/**
 * @Author: liurunyu
 * @Date: 2025/8/21 14:50
 * @Description
 */
public abstract class Com4MqttCtrl {
    @Autowired
    protected Environment env ;
    @Autowired
    protected RestTemplate restTemplate ;
    @Value("${mw.waitMwRtnResultTimeout}")
    protected int waitMwRtnResultTimeout ;
    @Value("${mw.mqttCallbackUrl_wx}")
    protected String mqttResultSendWebUrl;
    //水肥机对象
    protected PrStManure ctrlPo ;
    //异步等待器
    protected CompletableFuture<MqttSubMsg> feature;
    //命令名称
    protected String comName ;
    //命令日志id
    protected Long comId ;
    /**
     * 发送命令前-1:验证
     * @param comSv
     * @param comCode
     * @param dto
     * @param bindingResult
     * @return
     */
    public BaseResponse<Object> pre1(Com4MqttSv comSv, String comCode, Dto4MqttBase dto, BindingResult bindingResult) {
        if (bindingResult != null && bindingResult.hasErrors()) {
            return BaseResponseUtils.buildError(Objects.requireNonNull(bindingResult.getFieldError()).getDefaultMessage());
        }
        String msg = this.checkDto(dto) ;
        if(msg != null){
            return BaseResponseUtils.buildError("服务端出错," + msg) ;
        }
        return  null ;
    }
    /**
     * 发送命令前-2:获得数据
     * @param comSv
     * @param protocol
     * @param protocolVer
     * @param comCode
     * @param dto
     * @param bindingResult
     * @return
     */
    public BaseResponse<Object> pre2(Com4MqttSv comSv, String protocol, Short protocolVer, String comCode, Dto4MqttBase dto, BindingResult bindingResult) {
        //得到水肥机对象
        ctrlPo = comSv.getManure(dto.getManureId());
        if (ctrlPo == null) {
            return BaseResponseUtils.buildError("服务端出错,从数据库中未得到水肥机数据") ;
        }
        //检查协议
        String msg = comSv.checkProtocol(ctrlPo) ;
        if(msg != null) {
            return BaseResponseUtils.buildError("服务端出错," + msg) ;
        }
        //得到功能码对应的命令名称
        comName = comSv.getCommandName(comCode, protocol, protocolVer) ;
        if(comName == null) {
            return BaseResponseUtils.buildError("服务端出错,未得到功能码对应命令名称") ;
        }
        return  null ;
    }
    /**
     * 发送命令前-3:保存命令日志
     * @param comSv sv对象
     * @param manureId 水肥机ID
     * @param operator 当前用登录用户id(操作人)
     * @param protocol 协议
     * @param protocolVerion 协议
     * @param comCode 功能码
     * @param param 命令参数
     * @return
     */
    public BaseResponse<Object> pre3(Com4MqttSv comSv, Long manureId, Long operator, String protocol, Short protocolVerion, String comCode, Cd4MqttParameter param) {
        comId = new IDLongGenerator().generate();
        //生成并保存命令日志
        RmCommandHistory po = comSv.saveComHistoryPo(comId,
                protocol + protocolVerion ,
                comCode,
                comName,
                manureId,
                ctrlPo.fboxId ,
                param,
                operator);
        if(po == null){
            return BaseResponseUtils.buildError("服务端出错,未能生成并保存命令日志") ;
        }
        return  null ;
    }
    /**
     * 发送命令前-4:准备Feature
     * @return
     */
    public void pre4() {
        feature = new CompletableFuture<>();
        ComResultWait.put(comId, feature);
    }
    /**
     * 发送命令
     * @param comSv
     * @param com
     * @return
     */
    public BaseResponse<Object> doSend(Com4MqttSv comSv, Command com){
        //得到通信中间件发送命令的web URL
        String rqUrl = comSv.get2MwRequestUrl(env, comSv.ContextComSend) ;
        //向通信中间件发送web请求
        BaseResponse res = comSv.sendPostRequest2Mw(restTemplate, rqUrl, com) ;
        //处理通信中间件对web请求的响应
        String msg = comSv.dealMwDealResponse(res) ;
        if(msg != null) {
            return BaseResponseUtils.buildError(msg) ;
        }else{
            return null ;
        }
    }
    /**
     * 发送命令后
     * @return
     */
    public BaseResponse<Object> after(String comCode, Callback callback) {
        try{
            //等待通信中间件通知水肥机执行命令上行数据(命令结果)
            MqttSubMsg subMsg = feature.get(waitMwRtnResultTimeout, TimeUnit.SECONDS);
            return BaseResponseUtils.buildSuccess(this.dealComResult(comCode, subMsg, callback));
        }catch (Exception e){
            return BaseResponseUtils.buildFail("等待通信中间件通知命令结果超时");
        }
    }
    /**
     * 发送命令最后
     * @return
     */
    public void end(){
        try {
            //最后清除CompletableFuture缓存
            if(ComResultWait.contain(comId)){
                ComResultWait.remove(comId);
            }
        }catch (Exception ee){}
    }
    /**
     * 验证
     * @param dto
     * @return
     */
    protected abstract String checkDto(Dto4MqttBase dto) ;
    /**
     * 生成命令返回信息
     */
    protected abstract String dealComResult(String code, MqttSubMsg subMsg, Callback callback);
}
pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/common/Com4MqttSv.java
New file
@@ -0,0 +1,50 @@
package com.dy.pipIrrWechat.common;
import com.dy.pipIrrGlobal.command.Command4MqttSv;
import com.dy.pipIrrGlobal.daoPr.PrStManureMapper;
import com.dy.pipIrrGlobal.daoRm.RmCommandHistoryMapper;
import com.dy.pipIrrGlobal.pojoPr.PrStManure;
import com.dy.pipIrrGlobal.pojoRm.RmCommandHistory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
/**
 * @Author: liurunyu
 * @Date: 2025/8/21 14:46
 * @Description
 */
public class Com4MqttSv extends Command4MqttSv {
    @Autowired
    protected PrStManureMapper prStManureDao ;
    @Autowired
    protected RmCommandHistoryMapper rmCommandHistoryDao ;
    public PrStManure getManure(Long manureId){
        return this.getManure(prStManureDao, manureId);
    }
    /**
     * 创建命令日志对象
     *
     * @param comId       主键
     * @param commandCode 功能码
     * @param rtuAddr     阀控器地址
     * @param protocol    通讯协议名称
     * @param param       参数数据
     * @param operator    操作员
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public RmCommandHistory saveComHistoryPo(Long comId,
                                             String protocol,
                                             String commandCode,
                                             String commandName,
                                             Long manureId,
                                             String rtuAddr,
                                             Object param,
                                             Long operator) {
        return this.saveComHistoryPo(rmCommandHistoryDao, comId, protocol, commandCode, commandName, manureId, rtuAddr, param, operator) ;
    }
}
pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/common/Dto4MqttBase.java
New file
@@ -0,0 +1,31 @@
package com.dy.pipIrrWechat.common;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
/**
 * @Author: liurunyu
 * @Date: 2025/8/21 14:49
 * @Description
 */
@Data
public class Dto4MqttBase {
    public static final long serialVersionUID = 202506201459001L;
    /**
     * 水肥机ID
     */
    @NotNull(message = "水肥机不能为空")
    public Long manureId;
    /**
     * 水肥机名称
     */
    public String manureName;
    /**
     * 操作人
     */
    @NotNull(message = "操作人不能为空")
    public Long operator;
}
pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/mqtt/MonitorMqttCdParam.java
New file
@@ -0,0 +1,23 @@
package com.dy.pipIrrWechat.mqtt;
import com.dy.pipIrrWechat.common.Cd4MqttParameter;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import lombok.experimental.SuperBuilder;
/**
 * @Author: liurunyu
 * @Date: 2025/8/21 14:52
 * @Description
 */
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@SuperBuilder
public class MonitorMqttCdParam extends Cd4MqttParameter {
    //启停动作,true是,false否
    //可以执行功能码 00,01,02,03的动作
    public boolean startTrueStopFalse;//
}
pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/mqtt/MonitorMqttDto.java
New file
@@ -0,0 +1,17 @@
package com.dy.pipIrrWechat.mqtt;
import com.dy.pipIrrWechat.common.Dto4MqttBase;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * @Author: liurunyu
 * @Date: 2025/8/21 14:48
 * @Description
 */
@Data
@EqualsAndHashCode(callSuper=true)
public class MonitorMqttDto extends Dto4MqttBase {
    public static final long serialVersionUID = 202508211449001L;
}
pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/mqtt/MonitorMqttFaultCtrl.java
New file
@@ -0,0 +1,120 @@
package com.dy.pipIrrWechat.mqtt;
import com.alibaba.fastjson2.JSON;
import com.dy.common.aop.SsoAop;
import com.dy.common.mw.protocol.Command;
import com.dy.common.mw.protocol4Mqtt.MqttSubMsg;
import com.dy.common.mw.protocol4Mqtt.pSdV1.CodeSdV1;
import com.dy.common.mw.protocol4Mqtt.pSdV1.ProtocolConstantSdV1;
import com.dy.common.mw.protocol4Mqtt.pSdV1.upVos.ManureVo;
import com.dy.common.util.Callback;
import com.dy.common.webUtil.BaseResponse;
import com.dy.common.webUtil.BaseResponseUtils;
import com.dy.pipIrrWechat.common.Com4MqttCtrl;
import com.dy.pipIrrWechat.common.Dto4MqttBase;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.http.MediaType;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
/**
 * @Author: liurunyu
 * @Date: 2025/8/21 15:00
 * @Description
 */
@Slf4j
@Tag(name = "远程命令", description = "清除故障")
@RestController()
@RequestMapping(path = "mqttFault")
@RequiredArgsConstructor
@Scope("prototype") //因为有对象类属性,所以采用原型模式,每次请求新建一个实例对象
public class MonitorMqttFaultCtrl extends Com4MqttCtrl {
    private static final String RtuSuccessMsg = "控制器接收并执行命令成功,无返回数据";
    private static final String Protocol = ProtocolConstantSdV1.protocolName ;
    private static final Short ProtocolVersion = ProtocolConstantSdV1.protocolVer ;
    private static final String ComCode = CodeSdV1.cd_Fault ;
    @Autowired
    private MonitorMqttSv sv ;
    /**
     * 向设备(Mqtt中间件->FBox)发送命令
     * @param dto 前端发来的值对象
     * @param bindingResult 对dto验证的结果
     * @return 返回前端
     */
    @PostMapping(path = "clear", consumes = MediaType.APPLICATION_JSON_VALUE)
    @SsoAop()
    public BaseResponse<Object> send(@RequestBody @Valid MonitorMqttDto dto, BindingResult bindingResult) {
        BaseResponse<Object> res ;
        //发送命令前-1:验证
        res = super.pre1(sv, ComCode, dto, bindingResult);
        if(res == null) {
            //发送命令前-2:获得数据
            res = super.pre2(sv, Protocol, ProtocolVersion, ComCode, dto, bindingResult);
            if (res == null) {
                //发送命令前-3:保存命令日志
                MonitorMqttCdParam comParam = MonitorMqttCdParam.builder().no(ctrlPo.no).startTrueStopFalse(true).build();
                res = super.pre3(sv, dto.manureId, dto.getOperator(), Protocol, ProtocolVersion, ComCode, comParam);
                if (res == null) {
                    //发送命令前-4:准备Feature
                    super.pre4();
                    try {
                        //创建外部命令(发给MQTT->FBox)
                        Command com = sv.createMQTTCommand(ctrlPo.fboxId, "" + comId, Protocol, ProtocolVersion, ComCode);
                        com.rtuResultSendWebUrl = mqttResultSendWebUrl;
                        com.param = comParam ;
                        //发送命令
                        res = super.doSend(sv, com);
                        if (res == null) {
                            //发送命令后
                            res = super.after(ComCode, null);
                        }
                    } catch (Exception e) {
                        res = BaseResponseUtils.buildFail("服务端构造并向通信中间件发送请求时异常" + (e.getMessage() == null ? "" : e.getMessage()));
                    } finally {
                        //最终
                        super.end();
                    }
                }
            }
        }
        return res ;
    }
    @Override
    protected String checkDto(Dto4MqttBase dto) {
        return null;
    }
    @Override
    protected String dealComResult(String code, MqttSubMsg subMsg, Callback callback){
        String msg;
        if(subMsg != null){
            if(subMsg.vo4Up != null && Proxy.isProxyClass(subMsg.vo4Up.getClass())){
                // 获取代理的 InvocationHandler
                InvocationHandler handler = Proxy.getInvocationHandler(subMsg.vo4Up);
                String json = JSON.toJSONString(handler) ;
                ManureVo vo = JSON.parseObject(json, ManureVo.class);
                msg = vo.toString() ;
            }else{
                msg = RtuSuccessMsg ;
            }
        }else{
            msg = RtuSuccessMsg ;
        }
        return msg;
    }
}
pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/mqtt/MonitorMqttInjectCtrl.java
New file
@@ -0,0 +1,143 @@
package com.dy.pipIrrWechat.mqtt;
import com.alibaba.fastjson2.JSON;
import com.dy.common.aop.SsoAop;
import com.dy.common.mw.protocol.Command;
import com.dy.common.mw.protocol4Mqtt.MqttSubMsg;
import com.dy.common.mw.protocol4Mqtt.pSdV1.CodeSdV1;
import com.dy.common.mw.protocol4Mqtt.pSdV1.ProtocolConstantSdV1;
import com.dy.common.mw.protocol4Mqtt.pSdV1.upVos.ManureVo;
import com.dy.common.util.Callback;
import com.dy.common.webUtil.BaseResponse;
import com.dy.common.webUtil.BaseResponseUtils;
import com.dy.pipIrrWechat.common.Com4MqttCtrl;
import com.dy.pipIrrWechat.common.Dto4MqttBase;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.http.MediaType;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
/**
 * @Author: liurunyu
 * @Date: 2025/8/21 14:56
 * @Description
 */
@Slf4j
@Tag(name = "远程命令", description = "注肥启停")
@RestController()
@RequestMapping(path = "mqttInject")
@RequiredArgsConstructor
@Scope("prototype") //因为有对象类属性,所以采用原型模式,每次请求新建一个实例对象
public class MonitorMqttInjectCtrl extends Com4MqttCtrl {
    private static final String RtuSuccessMsg = "控制器接收并执行命令成功,无返回数据";
    private static final String Protocol = ProtocolConstantSdV1.protocolName ;
    private static final Short ProtocolVersion = ProtocolConstantSdV1.protocolVer ;
    private static final String ComCode = CodeSdV1.cd_Inject ;
    @Autowired
    private MonitorMqttSv sv ;
    /**
     * 向设备(Mqtt中间件->FBox)发送命令
     * @param dto 前端发来的值对象
     * @param bindingResult 对dto验证的结果
     * @return 返回前端
     */
    @PostMapping(path = "start", consumes = MediaType.APPLICATION_JSON_VALUE)
    @SsoAop()
    public BaseResponse<Object> start(@RequestBody @Valid MonitorMqttDto dto, BindingResult bindingResult) {
        return this.send(dto, bindingResult, true) ;
    }
    /**
     * 向设备(Mqtt中间件->FBox)发送命令
     * @param dto 前端发来的值对象
     * @param bindingResult 对dto验证的结果
     * @return 返回前端
     */
    @PostMapping(path = "stop", consumes = MediaType.APPLICATION_JSON_VALUE)
    @SsoAop()
    public BaseResponse<Object> stop(@RequestBody @Valid MonitorMqttDto dto, BindingResult bindingResult) {
        return this.send(dto, bindingResult, false) ;
    }
    /**
     * 向设备(Mqtt中间件->FBox)发送命令
     * @param dto 前端发来的值对象
     * @param bindingResult 对dto验证的结果
     * @return 返回前端
     */
    private BaseResponse<Object> send(MonitorMqttDto dto, BindingResult bindingResult, boolean startTrueStopFalse) {
        BaseResponse<Object> res ;
        //发送命令前-1:验证
        res = super.pre1(sv, ComCode, dto, bindingResult);
        if(res == null) {
            //发送命令前-2:获得数据
            res = super.pre2(sv, Protocol, ProtocolVersion, ComCode, dto, bindingResult);
            if (res == null) {
                //发送命令前-3:保存命令日志
                MonitorMqttCdParam comParam = MonitorMqttCdParam.builder().no(ctrlPo.no).startTrueStopFalse(startTrueStopFalse).build();
                res = super.pre3(sv, dto.manureId, dto.getOperator(), Protocol, ProtocolVersion, ComCode, comParam);
                if (res == null) {
                    //发送命令前-4:准备Feature
                    super.pre4();
                    try {
                        //创建外部命令(发给MQTT->FBox)
                        Command com = sv.createMQTTCommand(ctrlPo.fboxId, "" + comId, Protocol, ProtocolVersion, ComCode);
                        com.rtuResultSendWebUrl = mqttResultSendWebUrl;
                        com.param = comParam ;
                        //发送命令
                        res = super.doSend(sv, com);
                        if (res == null) {
                            //发送命令后
                            res = super.after(ComCode, null);
                        }
                    } catch (Exception e) {
                        res = BaseResponseUtils.buildFail("服务端构造并向通信中间件发送请求时异常" + (e.getMessage() == null ? "" : e.getMessage()));
                    } finally {
                        //最终
                        super.end();
                    }
                }
            }
        }
        return res ;
    }
    @Override
    protected String checkDto(Dto4MqttBase dto) {
        return null;
    }
    @Override
    protected String dealComResult(String code, MqttSubMsg subMsg, Callback callback){
        String msg;
        if(subMsg != null){
            if(subMsg.vo4Up != null && Proxy.isProxyClass(subMsg.vo4Up.getClass())){
                // 获取代理的 InvocationHandler
                InvocationHandler handler = Proxy.getInvocationHandler(subMsg.vo4Up);
                String json = JSON.toJSONString(handler) ;
                ManureVo vo = JSON.parseObject(json, ManureVo.class);
                msg = vo.toString() ;
            }else{
                msg = RtuSuccessMsg ;
            }
        }else{
            msg = RtuSuccessMsg ;
        }
        return msg;
    }
}
pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/mqtt/MonitorMqttStirCtrl.java
New file
@@ -0,0 +1,143 @@
package com.dy.pipIrrWechat.mqtt;
import com.alibaba.fastjson2.JSON;
import com.dy.common.aop.SsoAop;
import com.dy.common.mw.protocol.Command;
import com.dy.common.mw.protocol4Mqtt.MqttSubMsg;
import com.dy.common.mw.protocol4Mqtt.pSdV1.CodeSdV1;
import com.dy.common.mw.protocol4Mqtt.pSdV1.ProtocolConstantSdV1;
import com.dy.common.mw.protocol4Mqtt.pSdV1.upVos.ManureVo;
import com.dy.common.util.Callback;
import com.dy.common.webUtil.BaseResponse;
import com.dy.common.webUtil.BaseResponseUtils;
import com.dy.pipIrrWechat.common.Com4MqttCtrl;
import com.dy.pipIrrWechat.common.Dto4MqttBase;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.http.MediaType;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
/**
 * @Author: liurunyu
 * @Date: 2025/8/21 14:43
 * @Description
 */
@Slf4j
@Tag(name = "远程命令", description = "搅拌启停")
@RestController()
@RequestMapping(path = "mqttStir")
@RequiredArgsConstructor
@Scope("prototype") //因为有对象类属性,所以采用原型模式,每次请求新建一个实例对象
public class MonitorMqttStirCtrl extends Com4MqttCtrl {
    private static final String RtuSuccessMsg = "控制器接收并执行命令成功,无返回数据";
    private static final String Protocol = ProtocolConstantSdV1.protocolName ;
    private static final Short ProtocolVersion = ProtocolConstantSdV1.protocolVer ;
    private static final String ComCode = CodeSdV1.cd_Stir ;
    @Autowired
    private MonitorMqttSv sv ;
    /**
     * 向设备(Mqtt中间件->FBox)发送命令
     * @param dto 前端发来的值对象
     * @param bindingResult 对dto验证的结果
     * @return 返回前端
     */
    @PostMapping(path = "start", consumes = MediaType.APPLICATION_JSON_VALUE)
    @SsoAop()
    public BaseResponse<Object> start(@RequestBody @Valid MonitorMqttDto dto, BindingResult bindingResult) {
        return this.send(dto, bindingResult, true) ;
    }
    /**
     * 向设备(Mqtt中间件->FBox)发送命令
     * @param dto 前端发来的值对象
     * @param bindingResult 对dto验证的结果
     * @return 返回前端
     */
    @PostMapping(path = "stop", consumes = MediaType.APPLICATION_JSON_VALUE)
    @SsoAop()
    public BaseResponse<Object> stop(@RequestBody @Valid MonitorMqttDto dto, BindingResult bindingResult) {
        return this.send(dto, bindingResult, false) ;
    }
    /**
     * 向设备(Mqtt中间件->FBox)发送命令
     * @param dto 前端发来的值对象
     * @param bindingResult 对dto验证的结果
     * @return 返回前端
     */
    private BaseResponse<Object> send(MonitorMqttDto dto, BindingResult bindingResult, boolean startTrueStopFalse) {
        BaseResponse<Object> res ;
        //发送命令前-1:验证
        res = super.pre1(sv, ComCode, dto, bindingResult);
        if(res == null) {
            //发送命令前-2:获得数据
            res = super.pre2(sv, Protocol, ProtocolVersion, ComCode, dto, bindingResult);
            if (res == null) {
                //发送命令前-3:保存命令日志
                MonitorMqttCdParam comParam = MonitorMqttCdParam.builder().no(ctrlPo.no).startTrueStopFalse(startTrueStopFalse).build();
                res = super.pre3(sv, dto.manureId, dto.getOperator(), Protocol, ProtocolVersion, ComCode, comParam);
                if (res == null) {
                    //发送命令前-4:准备Feature
                    super.pre4();
                    try {
                        //创建外部命令(发给MQTT->FBox)
                        Command com = sv.createMQTTCommand(ctrlPo.fboxId, "" + comId, Protocol, ProtocolVersion, ComCode);
                        com.rtuResultSendWebUrl = mqttResultSendWebUrl;
                        com.param = comParam ;
                        //发送命令
                        res = super.doSend(sv, com);
                        if (res == null) {
                            //发送命令后
                            res = super.after(ComCode, null);
                        }
                    } catch (Exception e) {
                        res = BaseResponseUtils.buildFail("服务端构造并向通信中间件发送请求时异常" + (e.getMessage() == null ? "" : e.getMessage()));
                    } finally {
                        //最终
                        super.end();
                    }
                }
            }
        }
        return res ;
    }
    @Override
    protected String checkDto(Dto4MqttBase dto) {
        return null;
    }
    @Override
    protected String dealComResult(String code, MqttSubMsg subMsg, Callback callback){
        String msg;
        if(subMsg != null){
            if(subMsg.vo4Up != null && Proxy.isProxyClass(subMsg.vo4Up.getClass())){
                // 获取代理的 InvocationHandler
                InvocationHandler handler = Proxy.getInvocationHandler(subMsg.vo4Up);
                String json = JSON.toJSONString(handler) ;
                ManureVo vo = JSON.parseObject(json, ManureVo.class);
                msg = vo.toString() ;
            }else{
                msg = RtuSuccessMsg ;
            }
        }else{
            msg = RtuSuccessMsg ;
        }
        return msg;
    }
}
pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/mqtt/MonitorMqttSv.java
New file
@@ -0,0 +1,15 @@
package com.dy.pipIrrWechat.mqtt;
import com.dy.pipIrrWechat.common.Com4MqttSv;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
 * @Author: liurunyu
 * @Date: 2025/8/21 14:45
 * @Description
 */
@Slf4j
@Service()
public class MonitorMqttSv extends Com4MqttSv {
}
pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/mqtt/VoManureLast.java
@@ -2,6 +2,7 @@
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * @Author: liurunyu
@@ -16,6 +17,7 @@
        "manureFlow", "manureTime", "stirTime",
        "stirDuration", "injectDuration", "onLine"
})
@EqualsAndHashCode(callSuper=false)
public class VoManureLast extends com.dy.pipIrrGlobal.voRm.VoManure{
    public Boolean onLine ;
pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/mqtt/VoSoilLast.java
@@ -2,6 +2,7 @@
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * @Author: liurunyu
@@ -15,6 +16,7 @@
        "soilTemperature1", "soilTemperature2", "soilTemperature3", "soilTemperature4", "soilTemperature5",
        "onLine"
})
@EqualsAndHashCode(callSuper=false)
public class VoSoilLast extends com.dy.pipIrrGlobal.voRm.VoSoil{
    public Boolean onLine ;
pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/mqtt/VoWeatherLast.java
@@ -3,6 +3,7 @@
import com.alibaba.fastjson2.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * @Author: liurunyu
@@ -18,6 +19,7 @@
        "windDirection", "windDirectionStr",
        "onLine"
})
@EqualsAndHashCode(callSuper=false)
public class VoWeatherLast extends  com.dy.pipIrrGlobal.voRm.VoWeather{
    public Boolean onLine ;