From 84043dad83ea5193179e82227b191e522496bae5 Mon Sep 17 00:00:00 2001
From: czt <czt18638530771@163.com>
Date: 星期五, 09 一月 2026 15:43:47 +0800
Subject: [PATCH] 料位总览提交2-IOT协议

---
 fzzy-igdss-core/src/main/java/com/fzzy/igds/utils/ContextUtil.java                     |   29 
 fzzy-igdss-io/src/main/java/com/fzzy/igds/io/notify/NotifyWebInvoker.java              |    2 
 fzzy-igdss-view/src/main/java/models/core.model.xml                                    |   27 
 fzzy-igdss-core/src/main/java/com/fzzy/igds/service/QuantityService.java               |    8 
 fzzy-igdss-core/src/main/java/com/fzzy/igds/domain/WeatherConf.java                    |   93 +++
 fzzy-igdss-core/src/main/java/com/fzzy/igds/service/FileService.java                   |    1 
 fzzy-igdss-io/src/main/java/com/fzzy/igds/iot/server/IotServerEngine.java              |   69 ++
 fzzy-igdss-io/src/main/java/com/fzzy/igds/io/notify/NotifyWebInvokerImpl.java          |    2 
 fzzy-igdss-io/src/main/java/com/fzzy/igds/iot/analysis/AnalysisService.java            |  265 ++++++++
 fzzy-igdss-core/src/main/java/com/fzzy/igds/service/WeatherService.java                |  284 +++++++++
 fzzy-igdss-io/src/main/java/com/fzzy/igds/iot/analysis/builder/ReMessageBuilder.java   |   72 ++
 fzzy-igdss-view/src/main/java/com/fzzy/igds/DepotConf.view.xml                         |   15 
 fzzy-igdss-core/src/main/java/com/fzzy/igds/utils/SpringUtil.java                      |   58 +
 fzzy-igdss-core/src/main/java/com/fzzy/igds/mapper/WeatherConfMapper.java              |   14 
 fzzy-igdss-io/src/main/java/com/fzzy/igds/iot/server/IotSessionListener.java           |   40 +
 fzzy-igdss-core/src/main/java/com/fzzy/igds/domain/WeatherInfo.java                    |   85 ++
 fzzy-igdss-core/src/main/java/com/fzzy/igds/domain/Depot.java                          |   12 
 fzzy-igdss-io/src/main/java/com/fzzy/igds/io/notify/NotifyGrainInvoker.java            |   57 +
 fzzy-igdss-io/src/main/java/com/fzzy/igds/iot/analysis/message/DeviceAttrInfo.java     |   16 
 fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/analysis/AnalysisService.java       |    3 
 fzzy-igdss-io/src/main/java/com/fzzy/igds/io/notify/NotifyWebParent.java               |   20 
 fzzy-igdss-core/src/main/java/com/fzzy/igds/service/GrainService.java                  |  116 +++
 fzzy-igdss-io/src/main/java/com/fzzy/igds/iot/analysis/message/DeviceAttr.java         |   26 
 fzzy-igdss-io/src/main/java/com/fzzy/igds/iot/server/ServerUtils.java                  |   23 
 fzzy-igdss-core/src/main/java/com/fzzy/igds/domain/WeatherCity.java                    |   58 +
 fzzy-igdss-io/src/main/java/com/fzzy/igds/iot/analysis/message/IoMessage.java          |   30 +
 fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/command/BhznRemoteQuantityImpl.java |    2 
 fzzy-igdss-io/src/main/java/com/fzzy/igds/ServerRunner.java                            |   11 
 fzzy-igdss-view/src/main/java/com/fzzy/igds/Depot.view.xml                             |   29 
 fzzy-igdss-view/src/main/java/com/fzzy/igds/DeviceIot.view.xml                         |    2 
 fzzy-igdss-core/src/main/java/com/fzzy/igds/mapper/WeatherCityMapper.java              |   14 
 fzzy-igdss-io/src/main/java/com/fzzy/igds/iot/server/IotMessageConsumer.java           |   42 +
 fzzy-igdss-io/src/main/java/com/fzzy/igds/io/notify/NotifyGrainInvokerImpl.java        |  167 +++++
 fzzy-igdss-io/src/main/java/com/fzzy/igds/io/notify/ServerNotifyInvoker.java           |   39 +
 fzzy-igdss-core/src/main/java/com/fzzy/igds/domain/DepotConf.java                      |    8 
 fzzy-igdss-core/src/main/java/com/fzzy/igds/mapper/WeatherInfoMapper.java              |   14 
 36 files changed, 1,699 insertions(+), 54 deletions(-)

diff --git a/fzzy-igdss-core/src/main/java/com/fzzy/igds/domain/Depot.java b/fzzy-igdss-core/src/main/java/com/fzzy/igds/domain/Depot.java
index 7ce60e0..72de220 100644
--- a/fzzy-igdss-core/src/main/java/com/fzzy/igds/domain/Depot.java
+++ b/fzzy-igdss-core/src/main/java/com/fzzy/igds/domain/Depot.java
@@ -97,6 +97,18 @@
     @TableField("bulk_weight")
     private Double bulkWeight;
 
+    @Column(name = "length", columnDefinition = "decimal(20,2) COMMENT '闀�/鐩村緞(鍗曚綅锛氱背)'")
+    @TableField("length")
+    private Double length = 0.0;
+
+    @Column(name = "width", columnDefinition = "decimal(20,2) COMMENT '瀹�(鍗曚綅锛氱背)'")
+    @TableField("width")
+    private Double width = 0.0;
+
+    @Column(name = "height", columnDefinition = "decimal(20,2) COMMENT '楂樺害(鍗曚綅锛氱背)'")
+    @TableField("height")
+    private Double height = 0.0;
+
     @Column(name = "store_keeper", columnDefinition = "varchar(40) COMMENT '淇濈鍛�'")
     @TableField("store_keeper")
     private String storeKeeper;
diff --git a/fzzy-igdss-core/src/main/java/com/fzzy/igds/domain/DepotConf.java b/fzzy-igdss-core/src/main/java/com/fzzy/igds/domain/DepotConf.java
index 6bd8ebf..43b0d38 100644
--- a/fzzy-igdss-core/src/main/java/com/fzzy/igds/domain/DepotConf.java
+++ b/fzzy-igdss-core/src/main/java/com/fzzy/igds/domain/DepotConf.java
@@ -107,12 +107,4 @@
     @TableField("is_only_th")
     private String isOnlyTH = Constant.YN_N;
 
-    @Column(name = "diameter", columnDefinition = "decimal(20,2) COMMENT '绛掍粨鐩村緞(鍗曚綅锛氱背)'")
-    @TableField("diameter")
-    private Double diameter = 0.0;
-
-    @Column(name = "height", columnDefinition = "decimal(20,2) COMMENT '绛掍粨楂樺害(鍗曚綅锛氱背)'")
-    @TableField("height")
-    private Double height = 0.0;
-
 }
diff --git a/fzzy-igdss-core/src/main/java/com/fzzy/igds/domain/WeatherCity.java b/fzzy-igdss-core/src/main/java/com/fzzy/igds/domain/WeatherCity.java
new file mode 100644
index 0000000..a1aff2d
--- /dev/null
+++ b/fzzy-igdss-core/src/main/java/com/fzzy/igds/domain/WeatherCity.java
@@ -0,0 +1,58 @@
+package com.fzzy.igds.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import java.io.Serializable;
+
+/**
+ * @Description
+ * @Author CZT
+ * @Date 2026/01/09 11:55
+ */
+@Data
+@Entity
+@Table(name = "d_weather_city")
+@TableName("d_weather_city")
+@EqualsAndHashCode(callSuper = false)
+public class WeatherCity  extends BizBaseEntity implements Serializable {
+
+	/**
+	 *
+	 */
+	private static final long serialVersionUID = 1L;
+
+	@Id
+	@Column(name = "id", columnDefinition = "varchar(40) COMMENT '涓婚敭'")
+	@TableField("id")
+	private String id;
+
+	@Column(name = "city_en", columnDefinition = "varchar(40) COMMENT '鍩庡競缂栫爜'")
+	@TableField("city_en")
+	private String cityEn;
+
+	@Column(name = "city_zh", columnDefinition = "varchar(40) COMMENT '鍩庡競鍚嶇О'")
+	@TableField("city_zh")
+	private String cityZh;
+
+	@Column(name = "province_en", columnDefinition = "varchar(40) COMMENT '鐪佷唤缂栫爜'")
+	@TableField("province_en")
+	private String provinceEn;
+
+	@Column(name = "province_zh", columnDefinition = "varchar(40) COMMENT '鐪佷唤鍚嶇О'")
+	@TableField("province_zh")
+	private String provinceZh;
+
+	@Column(name = "lat", columnDefinition = "varchar(40) COMMENT '鍧愭爣'")
+	@TableField("lat")
+	private String lat;
+
+	@Column(name = "lon", columnDefinition = "varchar(40) COMMENT '鍧愭爣'")
+	@TableField("lon")
+	private String lon;
+}
diff --git a/fzzy-igdss-core/src/main/java/com/fzzy/igds/domain/WeatherConf.java b/fzzy-igdss-core/src/main/java/com/fzzy/igds/domain/WeatherConf.java
new file mode 100644
index 0000000..980faf2
--- /dev/null
+++ b/fzzy-igdss-core/src/main/java/com/fzzy/igds/domain/WeatherConf.java
@@ -0,0 +1,93 @@
+package com.fzzy.igds.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fzzy.igds.constant.Constant;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import java.io.Serializable;
+
+/**
+ * @Description
+ * @Author CZT
+ * @Date 2026/01/09 11:55
+ */
+@Data
+@Entity
+@Table(name = "d_weather_conf")
+@TableName("d_weather_conf")
+@EqualsAndHashCode(callSuper = false)
+public class WeatherConf extends BizBaseEntity implements Serializable  {
+    /**
+     *
+     */
+    private static final long serialVersionUID = 1L;
+
+    @Id
+    @Column(name = "id", columnDefinition = "varchar(40) COMMENT '涓婚敭'")
+    @TableField("id")
+    private String id;
+
+    @Column(name = "dept_id", columnDefinition = "varchar(40) COMMENT '鎵�灞炲簱鍖�'")
+    @TableField("dept_id")
+    private String deptId;
+
+    @Column(name = "name", columnDefinition = "varchar(40) COMMENT '璁惧鍚嶇О'")
+    @TableField("name")
+    private String name;
+
+    @Column(name = "ip", columnDefinition = "varchar(40) COMMENT 'IP鍦板潃'")
+    @TableField("ip")
+    private String ip;
+
+    @Column(name = "port", columnDefinition = "int COMMENT '绔彛鍙�'")
+    @TableField("port")
+    private Integer port;
+
+    @Column(name = "mac_status", columnDefinition = "varchar(40) COMMENT '璁惧鐘舵��'")
+    @TableField("mac_status")
+    private String macStatus = Constant.STATUS_NONE;
+
+    @Column(name = "protocol", columnDefinition = "varchar(40) COMMENT '鎵�灞炲崗璁�'")
+    @TableField("protocol")
+    private String protocol;
+
+    @Column(name = "wan_tag", columnDefinition = "varchar(40) COMMENT '澶栫綉姘旇薄'")
+    @TableField("wan_tag")
+    private String wanTag = Constant.YN_N;
+
+    @Column(name = "city", columnDefinition = "varchar(40) COMMENT '姘旇薄鍩庡競'")
+    @TableField("city")
+    private String city;
+
+    @Column(name = "city_id", columnDefinition = "varchar(40) COMMENT '姘旇薄鍩庡競'")
+    @TableField("city_id")
+    private String cityId;
+
+    @Column(name = "account", columnDefinition = "varchar(40) COMMENT '璐﹀彿'")
+    @TableField("account")
+    private String account;
+
+    @Column(name = "password", columnDefinition = "varchar(40) COMMENT '瀵嗙爜'")
+    @TableField("password")
+    private String password;
+
+    public WeatherConf() {
+        super();
+    }
+
+    public WeatherConf(String deptId) {
+        super();
+        this.deptId = deptId;
+    }
+
+    public WeatherConf(String deptId, String cityId) {
+        super();
+        this.deptId = deptId;
+        this.cityId = cityId;
+    }
+}
diff --git a/fzzy-igdss-core/src/main/java/com/fzzy/igds/domain/WeatherInfo.java b/fzzy-igdss-core/src/main/java/com/fzzy/igds/domain/WeatherInfo.java
new file mode 100644
index 0000000..ecad91b
--- /dev/null
+++ b/fzzy-igdss-core/src/main/java/com/fzzy/igds/domain/WeatherInfo.java
@@ -0,0 +1,85 @@
+package com.fzzy.igds.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import javax.persistence.*;
+import java.io.Serializable;
+
+
+/**
+ * @Description 姘旇薄淇℃伅锛屾皵璞′俊鎭潵婧愬寘鎷缃戝拰搴撳尯姘旇薄绔欙紝褰撳墠瀹氫箟鍗充綔涓篋ATA鍙堜綔涓篋TO浣跨敤鍥犳浼氬畾涔夎櫄鎷熺殑鎵╁睍瀛楁
+ * @Author CZT
+ * @Date 2026/01/09 11:55
+ */
+@Data
+@Entity
+@Table(name = "d_weather_info")
+@TableName("d_weather_info")
+@EqualsAndHashCode(callSuper = false)
+public class WeatherInfo extends BizBaseEntity implements Serializable {
+
+	/**
+	 *
+	 */
+	private static final long serialVersionUID = 1L;
+
+	@Id
+	@Column(name = "id", columnDefinition = "varchar(40) COMMENT '涓婚敭'")
+	@TableField("id")
+	private String id;
+
+	@Column(name = "dept_id", columnDefinition = "varchar(40) COMMENT '鎵�灞炲簱鍖�'")
+	@TableField("dept_id")
+	private String deptId;
+
+	@Column(name = "city", columnDefinition = "varchar(40) COMMENT '鎵�灞炲煄甯�'")
+	@TableField("city")
+	private String city;
+
+	@Column(name = "temp", columnDefinition = "varchar(40) COMMENT '娓╁害'")
+	@TableField("temp")
+	private String temp = "0.0鈩�";
+
+	@Column(name = "humidity", columnDefinition = "varchar(40) COMMENT '婀垮害'")
+	@TableField("humidity")
+	private String humidity = "0.0%";
+
+	@Column(name = "wind_speed", columnDefinition = "varchar(40) COMMENT '椋庣骇'")
+	@TableField("wind_speed")
+	private String windSpeed = "0绾�";
+
+	@Column(name = "wind_meter", columnDefinition = "varchar(40) COMMENT '椋庨��'")
+	@TableField("wind_meter")
+	private String windMeter = "0km/h";
+
+	@Column(name = "wind_direction", columnDefinition = "varchar(40) COMMENT '椋庡悜'")
+	@TableField("wind_direction")
+	private String windDirection = "鏃犻";
+
+	@Column(name = "weather", columnDefinition = "varchar(40) COMMENT '澶╂皵'")
+	@TableField("weather")
+	private String weather = "鏅村ぉ";
+
+	@Column(name = "rainfall", columnDefinition = "varchar(40) COMMENT '闆ㄩ噺'")
+	@TableField("rainfall")
+	private String rainfall = "0.0mm/h";
+
+	@Column(name = "pm25", columnDefinition = "varchar(40) COMMENT 'PM2.5'")
+	@TableField("pm25")
+	private String pm25 = "0渭g/m3";
+
+	@Column(name = "air_level", columnDefinition = "varchar(40) COMMENT '绌烘皵璐ㄩ噺绛夌骇'")
+	@TableField("air_level")
+	private String airLevel = "浼�";
+
+	@Column(name = "pressure", columnDefinition = "varchar(40) COMMENT '澶ф皵鍘�'")
+	@TableField("pressure")
+	private String pressure;
+
+	@Column(name = "source", columnDefinition = "varchar(40) COMMENT '淇℃伅鏉ユ簮:01-搴撳尯姘旇薄绔欙紝02-澶栫綉'")
+	@TableField("source")
+	private String source = "01";
+
+}
diff --git a/fzzy-igdss-core/src/main/java/com/fzzy/igds/mapper/WeatherCityMapper.java b/fzzy-igdss-core/src/main/java/com/fzzy/igds/mapper/WeatherCityMapper.java
new file mode 100644
index 0000000..2a162ec
--- /dev/null
+++ b/fzzy-igdss-core/src/main/java/com/fzzy/igds/mapper/WeatherCityMapper.java
@@ -0,0 +1,14 @@
+package com.fzzy.igds.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fzzy.igds.domain.WeatherCity;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * @Description
+ * @Author CZT
+ * @Date 2026/01/09 11:55
+ */
+@Mapper
+public interface WeatherCityMapper extends BaseMapper<WeatherCity> {
+}
diff --git a/fzzy-igdss-core/src/main/java/com/fzzy/igds/mapper/WeatherConfMapper.java b/fzzy-igdss-core/src/main/java/com/fzzy/igds/mapper/WeatherConfMapper.java
new file mode 100644
index 0000000..da2db0e
--- /dev/null
+++ b/fzzy-igdss-core/src/main/java/com/fzzy/igds/mapper/WeatherConfMapper.java
@@ -0,0 +1,14 @@
+package com.fzzy.igds.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fzzy.igds.domain.WeatherConf;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * @Description
+ * @Author CZT
+ * @Date 2026/01/09 11:55
+ */
+@Mapper
+public interface WeatherConfMapper extends BaseMapper<WeatherConf> {
+}
diff --git a/fzzy-igdss-core/src/main/java/com/fzzy/igds/mapper/WeatherInfoMapper.java b/fzzy-igdss-core/src/main/java/com/fzzy/igds/mapper/WeatherInfoMapper.java
new file mode 100644
index 0000000..0b45230
--- /dev/null
+++ b/fzzy-igdss-core/src/main/java/com/fzzy/igds/mapper/WeatherInfoMapper.java
@@ -0,0 +1,14 @@
+package com.fzzy.igds.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fzzy.igds.domain.WeatherInfo;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * @Description
+ * @Author CZT
+ * @Date 2026/01/09 11:55
+ */
+@Mapper
+public interface WeatherInfoMapper extends BaseMapper<WeatherInfo> {
+}
diff --git a/fzzy-igdss-core/src/main/java/com/fzzy/igds/service/FileService.java b/fzzy-igdss-core/src/main/java/com/fzzy/igds/service/FileService.java
index bf579a2..e6e82f4 100644
--- a/fzzy-igdss-core/src/main/java/com/fzzy/igds/service/FileService.java
+++ b/fzzy-igdss-core/src/main/java/com/fzzy/igds/service/FileService.java
@@ -79,6 +79,7 @@
 
             //鏂囦欢鍏ㄨ矾寰�
             String filePath = getFileSavePath(pathTag) + data.getFileName();
+
             filePath = filePath.replace(FrameworkConfig.getProfile(), "/profile/");
             data.setFilePath(filePath);
 
diff --git a/fzzy-igdss-core/src/main/java/com/fzzy/igds/service/GrainService.java b/fzzy-igdss-core/src/main/java/com/fzzy/igds/service/GrainService.java
index a1a2d4c..9ff3f5c 100644
--- a/fzzy-igdss-core/src/main/java/com/fzzy/igds/service/GrainService.java
+++ b/fzzy-igdss-core/src/main/java/com/fzzy/igds/service/GrainService.java
@@ -2,21 +2,25 @@
 
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.fzzy.igds.constant.OrderRespEnum;
+import com.fzzy.igds.constant.RedisConst;
+import com.fzzy.igds.data.GrainData;
 import com.fzzy.igds.data.GrainParam;
-import com.fzzy.igds.data.InoutParam;
+import com.fzzy.igds.domain.Depot;
 import com.fzzy.igds.domain.Grain;
-import com.fzzy.igds.domain.InoutRecord;
 import com.fzzy.igds.mapper.GrainMapper;
 import com.fzzy.igds.utils.ContextUtil;
 import com.fzzy.igds.utils.DateUtil;
+import com.fzzy.igds.websocket.WebSocketPacket;
+import com.fzzy.igds.websocket.WebSocketServer;
+import com.ruoyi.common.core.redis.RedisCache;
 import com.ruoyi.common.utils.StringUtils;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.time.DateFormatUtils;
+import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
 import javax.annotation.Resource;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 /**
  * @Description
@@ -29,6 +33,10 @@
 
     @Resource
     private GrainMapper grainMapper;
+    @Resource
+    private RedisCache redisCache;
+    @Resource
+    private DepotService depotService;
 
     /**
      * 鏌ヨ鏁版嵁
@@ -93,4 +101,100 @@
         grainMapper.selectPage(page, queryWrapper);
     }
 
+    /**
+     * JPA - 鏇存柊鏁版嵁
+     * @param data
+     */
+    public void saveOrUpdateGrain(Grain data, String batchTag) {
+        if (StringUtils.isEmpty(data.getCompanyId())) {
+            data.setCompanyId(ContextUtil.getCompanyId());
+        }
+        if (StringUtils.isEmpty(data.getBatchId())) {
+            data.setBatchId(DateFormatUtils.format(data.getReceiveDate(), "yyyyMMddHHmm"));
+        }
+        if(StringUtils.isEmpty(batchTag)){
+            //鑷姩鐢熸垚
+            batchTag = "01";
+        }
+
+        if(StringUtils.isBlank(data.getCreateBy())){
+            data.setCreateBy(ContextUtil.getLoginUserName());
+            data.setCreateTime(new Date());
+        }
+
+        data.setUpdateBy(ContextUtil.getLoginUserName());
+        data.setUpdateTime(new Date());
+
+        data.setBatchTag(batchTag);
+        int insert = grainMapper.updateById(data);
+        if(insert == 0){
+            grainMapper.insert(data);
+        }
+
+        updateCacheGrainData(data);
+    }
+
+
+    /**
+     * 鏇存柊缂撳瓨涓渶鏂扮殑绮儏妫�娴嬫暟鎹�
+     *
+     * @param data 褰撳墠鏁版嵁涓烘爣鍑嗙殑Grain鏁版嵁锛屾病鏈夊仛鏇存柊鐐逛綅淇℃伅
+     * @return key=鍙傝�冪紪鐮�
+     */
+    public void updateCacheGrainData(Grain data) {
+
+        GrainData grainData = new GrainData();
+        BeanUtils.copyProperties(data, grainData);
+
+        String key = RedisConst.buildKey(data.getCompanyId(),
+                RedisConst.KEY_GRAIN, grainData.getDepotId());
+        redisCache.setCacheObject(key, grainData);
+
+
+        //鎺ㄩ�佸ぇ灞�
+        String deptId = data.getDeptId();
+        if (null == deptId) {
+            Depot depot = depotService.getCacheDepot(data.getCompanyId(), data.getDepotId());
+            if (null == depot) {
+                return;
+            }
+            deptId = depot.getDeptId();
+        }
+        Map<String, GrainData> mapData = this.getCacheGrainDateMap(data.getCompanyId(), deptId);
+        WebSocketPacket packet = new WebSocketPacket();
+        packet.setBizType("screen");
+        packet.setCompanyId(ContextUtil.getCompanyId());
+        packet.setDeptId(deptId);
+        packet.setBizId("grain");
+        packet.setOrderResp(OrderRespEnum.ORDER_INPROGRESS.getCode());
+        packet.setData(mapData);
+        WebSocketServer.sendByPocket(packet);
+    }
+
+    /**
+     * 鑾峰彇缂撳瓨涓渶鏂扮殑绮儏妫�娴嬫暟鎹�
+     *
+     * @param companyId
+     * @return key=鍙傝�冪紪鐮�
+     */
+    public Map<String, GrainData> getCacheGrainDateMap(String companyId, String deptId) {
+        if (null == companyId || null == deptId) return null;
+
+        String pattern = RedisConst.buildKey(companyId, RedisConst.KEY_GRAIN) + "*";
+
+        Collection<String> keys = redisCache.keys(pattern);
+
+        if (null == keys || keys.isEmpty()) return null;
+
+        Map<String, GrainData> result = new HashMap<>();
+        GrainData data;
+        for (String key : keys) {
+            data = (GrainData) redisCache.getCacheObject(key);
+            if (null == data) continue;
+
+            result.put(data.getDepotId(), data);
+        }
+        return result;
+    }
+
 }
diff --git a/fzzy-igdss-core/src/main/java/com/fzzy/igds/service/QuantityService.java b/fzzy-igdss-core/src/main/java/com/fzzy/igds/service/QuantityService.java
index 9f3a91c..cbe55e4 100644
--- a/fzzy-igdss-core/src/main/java/com/fzzy/igds/service/QuantityService.java
+++ b/fzzy-igdss-core/src/main/java/com/fzzy/igds/service/QuantityService.java
@@ -94,6 +94,14 @@
      * @param data
      */
     public void saveData(Quantity data) {
+
+        data.setUpdateBy(ContextUtil.getLoginUserName());
+        data.setUpdateTime(new Date());
+
+        if(StringUtils.isBlank(data.getCreateBy())){
+            data.setCreateBy(ContextUtil.getLoginUserName());
+            data.setCreateTime(new Date());
+        }
         quantityMapper.insert(data);
     }
 
diff --git a/fzzy-igdss-core/src/main/java/com/fzzy/igds/service/WeatherService.java b/fzzy-igdss-core/src/main/java/com/fzzy/igds/service/WeatherService.java
new file mode 100644
index 0000000..76fb7ff
--- /dev/null
+++ b/fzzy-igdss-core/src/main/java/com/fzzy/igds/service/WeatherService.java
@@ -0,0 +1,284 @@
+package com.fzzy.igds.service;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.fzzy.igds.constant.RedisConst;
+import com.fzzy.igds.domain.WeatherCity;
+import com.fzzy.igds.domain.WeatherConf;
+import com.fzzy.igds.domain.WeatherInfo;
+import com.fzzy.igds.mapper.WeatherCityMapper;
+import com.fzzy.igds.mapper.WeatherConfMapper;
+import com.fzzy.igds.mapper.WeatherInfoMapper;
+import com.fzzy.igds.utils.ContextUtil;
+import com.ruoyi.common.core.redis.RedisCache;
+import com.ruoyi.common.utils.StringUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.time.DateFormatUtils;
+import org.springframework.stereotype.Service;
+import javax.annotation.Resource;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @Description
+ * @Author CZT
+ * @Date 2026/01/09 11:55
+ */
+@Slf4j
+@Service
+public class WeatherService {
+
+    @Resource
+    private WeatherInfoMapper weatherInfoMapper;
+    @Resource
+    private WeatherConfMapper weatherConfMapper;
+    @Resource
+    private WeatherCityMapper weatherCityMapper;
+    @Resource
+    private RedisCache redisCache;
+
+    /**
+     * 鏌ヨ閰嶇疆淇℃伅
+     *
+     * @param companyId
+     * @param deptId
+     * @return
+     */
+    public List<WeatherConf> getConfData(String companyId, String deptId) {
+        if (StringUtils.isEmpty(companyId)) {
+            companyId = ContextUtil.getCompanyId();
+        }
+        if (StringUtils.isEmpty(deptId)) {
+            deptId = ContextUtil.subDeptId(null);
+        }
+
+        QueryWrapper<WeatherConf> queryWrapper = new QueryWrapper<>();
+
+        queryWrapper.eq("company_id", companyId);
+
+        queryWrapper.eq("dept_id", deptId);
+
+        return weatherConfMapper.selectList(queryWrapper);
+    }
+
+    /**
+     * 鏌ヨ閰嶇疆淇℃伅
+     *
+     * @return
+     */
+    public List<WeatherConf> getConfData() {
+        QueryWrapper<WeatherConf> queryWrapper = new QueryWrapper<>();
+        return weatherConfMapper.selectList(queryWrapper);
+    }
+
+    /**
+     * 淇濆瓨閰嶇疆淇℃伅
+     *
+     * @param data
+     * @return
+     */
+    public String saveConf(WeatherConf data) {
+        if (StringUtils.isEmpty(data.getId())) {
+            data.setId(ContextUtil.generateId());
+            data.setCompanyId(ContextUtil.getCompanyId());
+            data.setDeptId(ContextUtil.subDeptId(null));
+        }
+        if(StringUtils.isBlank(data.getCreateBy())){
+            data.setCreateBy(ContextUtil.getLoginUserName());
+            data.setCreateTime(new Date());
+        }
+        if(StringUtils.isBlank(data.getUpdateBy())){
+            data.setUpdateBy(ContextUtil.getLoginUserName());
+            data.setUpdateTime(new Date());
+        }
+        weatherConfMapper.insert(data);
+        return null;
+    }
+
+    /**
+     * 鍒犻櫎閰嶇疆淇℃伅
+     *
+     * @param data
+     * @return
+     */
+    public String delConf(WeatherConf data) {
+        weatherConfMapper.deleteById(data);
+        return null;
+    }
+
+    /**
+     * 淇濆瓨姘旀伅淇℃伅
+     *
+     * @param data
+     */
+    private void addWeatherInfo(WeatherInfo data) {
+
+        if(StringUtils.isBlank(data.getId())){
+            data.setId(ContextUtil.UUID());
+        }
+        if(StringUtils.isBlank(data.getCreateBy())){
+            data.setCreateBy(ContextUtil.getLoginUserName());
+            data.setCreateTime(new Date());
+        }
+        if(StringUtils.isBlank(data.getUpdateBy())){
+            data.setUpdateBy(ContextUtil.getLoginUserName());
+            data.setUpdateTime(new Date());
+        }
+        weatherInfoMapper.insert(data);
+    }
+
+    /**
+     * 鍒嗛〉鏌ヨ鏁版嵁
+     * @param page
+     * @param param
+     */
+    public void getInfoData(Page<WeatherInfo> page, Map<String, Object> param) {
+
+        QueryWrapper<WeatherInfo> queryWrapper = new QueryWrapper<>();
+
+        queryWrapper.eq("company_id", ContextUtil.getCompanyId());
+        queryWrapper.eq("dept_id", ContextUtil.subDeptId(null));
+
+        weatherInfoMapper.selectPage(page, queryWrapper);
+    }
+
+    /**
+     * 鍒嗛〉鏌ヨ鏁版嵁
+     * @param page
+     * @param param
+     */
+    public void pageCity(Page<WeatherCity> page, Map<String, Object> param) {
+
+        QueryWrapper<WeatherCity> queryWrapper = new QueryWrapper<>();
+
+        weatherCityMapper.selectPage(page, queryWrapper);
+    }
+
+    /**
+     * 鍒ゆ柇姘旇薄淇℃伅鏄惁闇�瑕佷繚瀛�
+     *
+     * @param weather
+     */
+    public void updateCacheAndSave(WeatherInfo weather) {
+        if (null == weather.getCompanyId()) {
+            weather.setCompanyId(ContextUtil.getCompanyId());
+        }
+        try {
+            // 鏇存柊缂撳瓨
+            updateCacheWeather(weather);
+            // 鍒ゆ柇鏄笉鏄渶瑕佷繚瀛�
+            if (this.isSave(weather.getUpdateTime())) {
+                addWeatherInfo(weather);
+            }
+
+        } catch (Exception e) {
+            String msg = e.getMessage();
+            if (msg.indexOf("PRIMARY") > 0) {
+                log.error("鎸佷箙鍖栨皵璞′俊鎭紓甯革紝涓婚敭鍐茬獊锛岃娉ㄦ剰鏇存柊鏃堕棿锛屽嚭鐜板紓甯告槸鍚﹀悎鐞�");
+            } else {
+                log.error("鏇存柊淇濆瓨姘旇薄淇℃伅寮傚父锛�", e);
+            }
+        }
+
+    }
+
+
+    /**
+     * 鏍规嵁缁勭粐缂栫爜璁剧疆缂撳瓨
+     *
+     * @param weather
+     */
+    public void updateCacheWeather(WeatherInfo weather) {
+        if (null == weather.getCompanyId()) {
+            weather.setCompanyId(ContextUtil.getCompanyId());
+        }
+        String key = RedisConst.buildKey(weather.getCompanyId(), RedisConst.KEY_WEATHER_INFO);
+        log.debug("姘旇薄淇℃伅鏇存柊鍒扮紦瀛樹腑锛宨nfo={}", weather.toString());
+        redisCache.setCacheObject(key, weather);
+    }
+
+    /**
+     * 鏍规嵁cityId璁剧疆缂撳瓨
+     *
+     * @param weather
+     * @param cityId
+     */
+    public void setCacheWeatherByCityId(WeatherInfo weather, String cityId) {
+        String key = RedisConst.buildKey(RedisConst.KEY_WEATHER_INFO, cityId);
+
+        log.debug("姘旇薄淇℃伅鏇存柊鍒扮紦瀛樹腑锛宨nfo={}", weather.toString());
+        redisCache.setCacheObject(key, weather, 60 * 30, TimeUnit.MICROSECONDS);
+    }
+
+    /**
+     * 鏍规嵁cityId鑾峰彇缂撳瓨淇℃伅
+     *
+     * @param cityId
+     * @return
+     */
+    public WeatherInfo getCacheWeatherByCityId(String cityId) {
+        String key = RedisConst.buildKey(RedisConst.KEY_WEATHER_INFO, cityId);
+        WeatherInfo info = (WeatherInfo) redisCache.getCacheObject(key);
+        if (null == info) {
+            log.error("缂撳瓨涓病鏈夎幏鍙栧埌姘旇薄淇℃伅锛侊紒");
+        }
+        return info;
+    }
+
+    /**
+     * 鏍规嵁companyId鑾峰彇缂撳瓨淇℃伅
+     *
+     * @param companyId
+     * @return
+     */
+    public WeatherInfo getCacheWeather(String companyId) {
+        String key = RedisConst
+                .buildKey(companyId, RedisConst.KEY_WEATHER_INFO);
+        WeatherInfo info = (WeatherInfo) redisCache.getCacheObject(key);
+        if (null == info) {
+            log.error("缂撳瓨涓病鏈夎幏鍙栧埌姘旇薄淇℃伅锛侊紒");
+        }
+        return info;
+    }
+
+    /**
+     * 鍒涘缓杩炴帴
+     *
+     * @param address
+     * @param port
+     */
+    public void onCreate(String address, Integer port) {
+        log.debug("姘旇薄绔欒嚜鍔ㄨ繛鎺ラ�氱煡鏆備笉澶勭悊鈥︹��");
+    }
+
+    /**
+     * 閿�姣侀摼鎺�
+     *
+     * @param address
+     * @param port
+     */
+    public void onDestroy(String address, Integer port) {
+        log.debug("姘旇薄绔欒嚜鍔ㄦ柇寮�閫氱煡鏆備笉澶勭悊鈥︹��");
+    }
+
+    /**
+     * 鍒ゆ柇褰撳墠姘旇薄淇℃伅鏄惁闇�瑕佹寔涔呭寲锛岄粯璁ょ郴缁熷彧淇濆瓨鍦ㄤ笂鍗�8鐐� 鍜屼笅鍗�3鐐圭殑姘旇薄淇°��
+     *
+     * @param updateTime
+     * @return
+     */
+    public static boolean isSave(Date updateTime) {
+
+        String tag = DateFormatUtils.format(updateTime, "HHmm");
+        String tag1 = "0800";
+        String tag2 = "1500";
+
+        if (tag.equals(tag1) || tag.equals(tag2)) {
+            return true;
+        }
+
+        return false;
+    }
+}
diff --git a/fzzy-igdss-core/src/main/java/com/fzzy/igds/utils/ContextUtil.java b/fzzy-igdss-core/src/main/java/com/fzzy/igds/utils/ContextUtil.java
index b021503..d98af1e 100644
--- a/fzzy-igdss-core/src/main/java/com/fzzy/igds/utils/ContextUtil.java
+++ b/fzzy-igdss-core/src/main/java/com/fzzy/igds/utils/ContextUtil.java
@@ -1,6 +1,7 @@
 package com.fzzy.igds.utils;
 
 import com.fzzy.igds.camera.data.ydqly.YdQlyNode;
+import com.fzzy.igds.constant.GrainFrequence;
 import com.ruoyi.common.config.FrameworkConfig;
 import com.ruoyi.common.core.domain.entity.SysUser;
 import com.ruoyi.common.utils.ShiroUtils;
@@ -197,6 +198,34 @@
     }
 
 
+    /**
+     * 鏍规嵁绯荤粺閰嶇疆鐨勬壒娆¢鐜囪幏鍙栨壒娆$紪鍙�
+     *
+     * @param freq
+     * @return
+     */
+    public static String getBatchIdByFireq(String freq) {
+        // 涓�澶╀竴娆�
+        if (GrainFrequence.FREQ_02.getCode().equals(freq)) {
+            return DateFormatUtils.format(new Date(), "yyyyMMdd") + "1801";
+        }
+
+        // 涓�澶╀袱娆�
+        if (GrainFrequence.FREQ_03.getCode().equals(freq)) {
+            String hour = DateFormatUtils.format(new Date(), "HH");
+            if (Integer.valueOf(hour) >= 0 && Integer.valueOf(hour) <= 12) {
+                return DateFormatUtils.format(new Date(), "yyyyMMdd") + "1301";
+            } else {
+                return DateFormatUtils.format(new Date(), "yyyyMMdd") + "1802";
+            }
+        }
+        return getDefaultBatchId();
+    }
+
+    public static String getDefaultBatchId() {
+        return DateFormatUtils.format(new Date(), "yyyyMMddHHmm");
+    }
+
     public static void main(String[] args) {
         for (int i = 0; i < 10; i++){
             String id = generateId();
diff --git a/fzzy-igdss-core/src/main/java/com/fzzy/igds/utils/SpringUtil.java b/fzzy-igdss-core/src/main/java/com/fzzy/igds/utils/SpringUtil.java
new file mode 100644
index 0000000..0f97d15
--- /dev/null
+++ b/fzzy-igdss-core/src/main/java/com/fzzy/igds/utils/SpringUtil.java
@@ -0,0 +1,58 @@
+package com.fzzy.igds.utils;
+
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.stereotype.Component;
+
+@Component
+public class SpringUtil implements ApplicationContextAware {
+
+	private static ApplicationContext applicationContext;
+
+	@Override
+	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+		if (SpringUtil.applicationContext == null) {
+			SpringUtil.applicationContext = applicationContext;
+		}
+	}
+
+	/**
+	 * 鑾峰彇applicationContext
+	 * @return
+	 */
+	public static ApplicationContext getApplicationContext() {
+		return applicationContext;
+	}
+
+	/**
+	 * 閫氳繃name鑾峰彇 Bean.
+	 * @param name
+	 * @return
+	 */
+	public static Object getBean(String name) {
+		return getApplicationContext().getBean(name);
+	}
+
+	/**
+	 * 閫氳繃class鑾峰彇Bean.
+	 * @param clazz
+	 * @param <T>
+	 * @return
+	 */
+	public static <T> T getBean(Class<T> clazz) {
+		return getApplicationContext().getBean(clazz);
+	}
+
+	/**
+	 * 閫氳繃name,浠ュ強Clazz杩斿洖鎸囧畾鐨凚ean
+	 * @param name
+	 * @param clazz
+	 * @param <T>
+	 * @return
+	 */
+	public static <T> T getBean(String name, Class<T> clazz) {
+		return getApplicationContext().getBean(name, clazz);
+	}
+
+}
diff --git a/fzzy-igdss-io/src/main/java/com/fzzy/igds/ServerRunner.java b/fzzy-igdss-io/src/main/java/com/fzzy/igds/ServerRunner.java
index 5803d50..469a99a 100644
--- a/fzzy-igdss-io/src/main/java/com/fzzy/igds/ServerRunner.java
+++ b/fzzy-igdss-io/src/main/java/com/fzzy/igds/ServerRunner.java
@@ -1,5 +1,6 @@
 package com.fzzy.igds;
 
+import com.fzzy.igds.iot.server.IotServerEngine;
 import com.fzzy.igds.quantity.server.BhznQuantityServerEngine;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.CommandLineRunner;
@@ -20,12 +21,18 @@
     public static final String BEAN_ID = "quantity.serverRunner";
 
     @Resource
-    private BhznQuantityServerEngine serverEngine;
+    private BhznQuantityServerEngine quantityServerEngine;
+    @Resource
+    private IotServerEngine iotServerEngine;
 
     @Override
     public void run(String... strings) throws Exception {
 
-        serverEngine.start(BhznQuantityServerEngine.PORT);
+        //鏁伴噺妫�娴嬬鍙�
+        quantityServerEngine.start(BhznQuantityServerEngine.PORT);
+
+        //IOT璁惧绔彛
+        iotServerEngine.start(IotServerEngine.PORT);
 
     }
 }
diff --git a/fzzy-igdss-io/src/main/java/com/fzzy/igds/io/notify/NotifyGrainInvoker.java b/fzzy-igdss-io/src/main/java/com/fzzy/igds/io/notify/NotifyGrainInvoker.java
new file mode 100644
index 0000000..2793a3a
--- /dev/null
+++ b/fzzy-igdss-io/src/main/java/com/fzzy/igds/io/notify/NotifyGrainInvoker.java
@@ -0,0 +1,57 @@
+package com.fzzy.igds.io.notify;
+
+import com.fzzy.igds.constant.OrderRespEnum;
+import com.fzzy.igds.domain.Depot;
+import com.fzzy.igds.domain.DepotConf;
+import com.fzzy.igds.domain.Grain;
+import com.fzzy.igds.request.ExeBaseRequest;
+
+/**
+ * @author Andy
+ */
+public interface NotifyGrainInvoker {
+
+
+    /**
+     * 绮儏瑙f瀽鎴愬姛鍚庨�氱煡锛岀郴缁熷紑濮嬫墽琛屼繚瀛樺垽鏂瓑鎿嶄綔
+     *
+     * @param grain          瑙f瀽鍚庣殑绮儏淇℃伅
+     * @param depotConf      浠撳簱閰嶇疆淇℃伅锛屼笉鍙负绌�
+     * @return 鎵ц寮傚父淇℃伅锛屾甯歌繑鍥濶ULL
+     */
+    String analysisSuccess(Grain grain, DepotConf depotConf, Depot depot, boolean isNotifyWeb, ExeBaseRequest request);
+
+    /**
+     * 鏇存柊绮儏锛屼粎浠呯伯鎯呬俊鎭�
+     *
+     * @param grain
+     * @param depot   浠撳簱淇℃伅
+     */
+    String analysisSuccess(Grain grain, Depot depot);
+
+    /**
+     * 鏇存柊绮儏锛屼粎浠呯伯鎯呬俊鎭�
+     *
+     * @param grain
+     * @param request 璇锋眰鍛戒护淇℃伅
+     */
+    String analysisSuccess(Grain grain, Depot depot, ExeBaseRequest request);
+
+    /**
+     * 鏇存柊绮儏锛屼粎浠呯伯鎯呬俊鎭�
+     *
+     * @param grain
+     * @param request 璇锋眰鍛戒护淇℃伅
+     */
+    String analysisSuccess(Grain grain, Depot depot, ExeBaseRequest request, DepotConf depotConf);
+
+
+    /**
+     * 鐩存帴閫氱煡椤甸潰
+     *
+     * @param companyId
+     * @param orderResp
+     * @param notifyMsg
+     */
+    void notifyWeb(String companyId, OrderRespEnum orderResp, String bizType, String notifyMsg);
+}
diff --git a/fzzy-igdss-io/src/main/java/com/fzzy/igds/io/notify/NotifyGrainInvokerImpl.java b/fzzy-igdss-io/src/main/java/com/fzzy/igds/io/notify/NotifyGrainInvokerImpl.java
new file mode 100644
index 0000000..943303e
--- /dev/null
+++ b/fzzy-igdss-io/src/main/java/com/fzzy/igds/io/notify/NotifyGrainInvokerImpl.java
@@ -0,0 +1,167 @@
+package com.fzzy.igds.io.notify;
+
+import com.fzzy.igds.constant.GrainFrequence;
+import com.fzzy.igds.constant.OrderRespEnum;
+import com.fzzy.igds.domain.Depot;
+import com.fzzy.igds.domain.DepotConf;
+import com.fzzy.igds.domain.Grain;
+import com.fzzy.igds.domain.WeatherInfo;
+import com.fzzy.igds.io.order.ExeOrderService;
+import com.fzzy.igds.request.ExeBaseRequest;
+import com.fzzy.igds.service.GrainService;
+import com.fzzy.igds.service.WeatherService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+
+@Slf4j
+@Component
+public class NotifyGrainInvokerImpl extends NotifyWebParent implements NotifyGrainInvoker {
+
+    @Resource
+    private GrainService grainService;
+    @Resource
+    private ExeOrderService exeRequestService;
+    @Resource
+    private WeatherService weatherService;
+
+    @Override
+    public String analysisSuccess(Grain grain, DepotConf depotConf, Depot depot, boolean isNotifyWeb, ExeBaseRequest exeRequest) {
+        grain = addWeatherInfo(grain);
+        try {
+            // 濡傛灉鏄竴鏃ュ娆�
+            if (null == depotConf) {
+                grainService.saveOrUpdateGrain(grain, null);
+            } else {
+                if (depotConf.getGrainFreq().equals(
+                        GrainFrequence.FREQ_01.getCode())) {
+                    grainService.saveOrUpdateGrain(grain, null);
+                } else {
+                    grainService.saveOrUpdateGrain(grain, null);
+                }
+            }
+            String notifyMsg = depot.getName() + " 绮儏閲囬泦骞惰В鏋愭垚鍔燂紝鎵规鍙�=" + grain.getBatchId();
+            //瀹屾垚
+            exeRequest.setExeMsg(notifyMsg);
+            exeRequestService.completeCache(exeRequest, false);
+
+            notifyWeb(depotConf.getCompanyId(), OrderRespEnum.MSG_SUCCESS, "grain", notifyMsg);
+
+            log.info(depot.getName() + "绮儏瑙f瀽鎴愬姛:" + grain.getBatchId());
+
+        } catch (Exception e) {
+            String notifyMsg = depot.getName() + "-淇濆瓨澶辫触锛岃鍕�2鍒嗛挓鍐呴噸澶嶉噰闆�";
+            //瀹屾垚
+            exeRequest.setErrorMsg(notifyMsg);
+            exeRequestService.completeCache(exeRequest, false);
+            notifyWeb(depotConf.getCompanyId(), OrderRespEnum.MSG_ERROR, "grain", notifyMsg);
+            log.error(depot.getName() + "绮儏瑙f瀽淇濆瓨澶辫触锛�" + e);
+        }
+        return null;
+    }
+
+    @Override
+    public String analysisSuccess(Grain grain, Depot depot) {
+        grain = addWeatherInfo(grain);
+
+        try {
+            grainService.saveOrUpdateGrain(grain,null);
+
+            String notifyMsg = depot.getName() + " 鏀跺埌鎺ㄩ�佺伯鎯呬俊鎭苟瑙f瀽鎴愬姛锛屾壒娆″彿=" + grain.getBatchId();
+
+            notifyWeb(grain.getCompanyId(), OrderRespEnum.MSG_SUCCESS, "grain", notifyMsg);
+
+        } catch (Exception e) {
+            String notifyMsg = depot.getName() + "-淇濆瓨澶辫触锛岃鍕�2鍒嗛挓鍐呴噸澶嶉噰闆�";
+            this.notifyWeb(grain.getCompanyId(), OrderRespEnum.MSG_ERROR, "grain", notifyMsg);
+
+            log.error("绮儏瑙f瀽淇濆瓨澶辫触锛�" + e);
+            return notifyMsg;
+        }
+        return null;
+    }
+
+    @Override
+    public String analysisSuccess(Grain grain, Depot depot, ExeBaseRequest exeRequest) {
+
+        grain = addWeatherInfo(grain);
+        try {
+            grainService.saveOrUpdateGrain(grain,null);
+
+            String notifyMsg = exeRequest.getDepotName() + " 绮儏閲囬泦骞惰В鏋愭垚鍔燂紝鎵规鍙�=" + grain.getBatchId();
+
+            //瀹屾垚
+            exeRequest.setExeMsg(notifyMsg);
+            exeRequestService.completeCache(exeRequest, false);
+
+        } catch (Exception e) {
+            String notifyMsg = exeRequest.getDepotName() + "-淇濆瓨澶辫触锛岃鍕�2鍒嗛挓鍐呴噸澶嶉噰闆�";
+            //瀹屾垚
+            exeRequest.setErrorMsg(notifyMsg);
+            exeRequestService.completeCache(exeRequest, false);
+            return notifyMsg;
+        }
+        return null;
+    }
+
+    @Override
+    public String analysisSuccess(Grain grain, Depot depot, ExeBaseRequest exeRequest, DepotConf depotConf) {
+
+        grain = addWeatherInfo(grain);
+        try {
+            grainService.saveOrUpdateGrain(grain,null);
+
+            String notifyMsg = exeRequest.getDepotName() + " 绮儏閲囬泦骞惰В鏋愭垚鍔燂紝鎵规鍙�=" + grain.getBatchId();
+
+            //瀹屾垚
+            exeRequest.setExeMsg(notifyMsg);
+            exeRequestService.completeCache(exeRequest, false);
+
+            notifyWeb(depotConf.getCompanyId(), OrderRespEnum.MSG_SUCCESS, "grain", notifyMsg);
+            log.info(depot.getName() + "绮儏瑙f瀽鎴愬姛:" + grain.getBatchId());
+        } catch (Exception e) {
+            String notifyMsg = exeRequest.getDepotName() + "-淇濆瓨澶辫触锛岃鍕�2鍒嗛挓鍐呴噸澶嶉噰闆�";
+
+            //瀹屾垚
+            exeRequest.setErrorMsg(notifyMsg);
+            exeRequestService.completeCache(exeRequest, false);
+
+            notifyWeb(depotConf.getCompanyId(), OrderRespEnum.MSG_ERROR, "grain", notifyMsg);
+
+            log.error(depot.getName() + "绮儏瑙f瀽淇濆瓨澶辫触锛�" + e);
+            return notifyMsg;
+        }
+        return null;
+    }
+
+
+    // 浠庣紦瀛樹腑鑾峰彇褰撳墠鐨勫娓╁害澶栭儴婀垮害
+    private Grain addWeatherInfo(Grain grain) {
+        if(grain.getHumidityOut() != null && grain.getTempOut() != null){
+            return grain;
+        }
+        WeatherInfo weatherInfo = weatherService.getCacheWeather(grain.getCompanyId());
+        Double tOut = -100.0, hOut = -100.0;
+        if (null != weatherInfo) {
+            if (weatherInfo.getTemp().indexOf("鈩�") > 0) {
+                weatherInfo.setTemp(weatherInfo.getTemp().replace("鈩�", ""));
+            }
+            if (weatherInfo.getHumidity().indexOf("%") > 0) {
+                weatherInfo.setHumidity(weatherInfo.getHumidity().replace("%",
+                        ""));
+            }
+            tOut = Double.valueOf(weatherInfo.getTemp());
+            hOut = Double.valueOf(weatherInfo.getHumidity());
+            grain.setWeather(weatherInfo.getWeather());
+        }
+        if(grain.getHumidityOut() == null || grain.getHumidityOut() == 0.0){
+            grain.setHumidityOut(hOut);
+        }
+        if(grain.getTempOut() == null || grain.getTempOut() == 0.0){
+            grain.setTempOut(tOut);
+        }
+        return grain;
+    }
+
+}
diff --git a/fzzy-igdss-core/src/main/java/com/fzzy/igds/notify/NotifyWebInvoker.java b/fzzy-igdss-io/src/main/java/com/fzzy/igds/io/notify/NotifyWebInvoker.java
similarity index 93%
rename from fzzy-igdss-core/src/main/java/com/fzzy/igds/notify/NotifyWebInvoker.java
rename to fzzy-igdss-io/src/main/java/com/fzzy/igds/io/notify/NotifyWebInvoker.java
index 65535c4..175d276 100644
--- a/fzzy-igdss-core/src/main/java/com/fzzy/igds/notify/NotifyWebInvoker.java
+++ b/fzzy-igdss-io/src/main/java/com/fzzy/igds/io/notify/NotifyWebInvoker.java
@@ -1,4 +1,4 @@
-package com.fzzy.igds.notify;
+package com.fzzy.igds.io.notify;
 
 import com.fzzy.igds.constant.OrderRespEnum;
 import com.fzzy.igds.data.QuantityProgressData;
diff --git a/fzzy-igdss-core/src/main/java/com/fzzy/igds/notify/NotifyWebInvokerImpl.java b/fzzy-igdss-io/src/main/java/com/fzzy/igds/io/notify/NotifyWebInvokerImpl.java
similarity index 97%
rename from fzzy-igdss-core/src/main/java/com/fzzy/igds/notify/NotifyWebInvokerImpl.java
rename to fzzy-igdss-io/src/main/java/com/fzzy/igds/io/notify/NotifyWebInvokerImpl.java
index 1878fa6..b83b34d 100644
--- a/fzzy-igdss-core/src/main/java/com/fzzy/igds/notify/NotifyWebInvokerImpl.java
+++ b/fzzy-igdss-io/src/main/java/com/fzzy/igds/io/notify/NotifyWebInvokerImpl.java
@@ -1,4 +1,4 @@
-package com.fzzy.igds.notify;
+package com.fzzy.igds.io.notify;
 
 import com.fzzy.igds.constant.OrderRespEnum;
 import com.fzzy.igds.data.QuantityProgressData;
diff --git a/fzzy-igdss-io/src/main/java/com/fzzy/igds/io/notify/NotifyWebParent.java b/fzzy-igdss-io/src/main/java/com/fzzy/igds/io/notify/NotifyWebParent.java
new file mode 100644
index 0000000..a35b7e7
--- /dev/null
+++ b/fzzy-igdss-io/src/main/java/com/fzzy/igds/io/notify/NotifyWebParent.java
@@ -0,0 +1,20 @@
+package com.fzzy.igds.io.notify;
+
+import com.fzzy.igds.constant.OrderRespEnum;
+import com.fzzy.igds.websocket.WebSocketPacket;
+import com.fzzy.igds.websocket.WebSocketServer;
+
+public class NotifyWebParent {
+
+	public void notifyWeb(String companyId, OrderRespEnum orderResp,
+			String bizType, String notifyMsg) {
+		// 閫氱煡鍓嶇
+		WebSocketPacket packet = new WebSocketPacket();
+		packet.setBizType(bizType);
+		packet.setCompanyId(companyId);
+		packet.setOrderResp(orderResp.getCode());
+		packet.setData(notifyMsg);
+		WebSocketServer.sendByPocket(packet);
+	}
+
+}
diff --git a/fzzy-igdss-io/src/main/java/com/fzzy/igds/io/notify/ServerNotifyInvoker.java b/fzzy-igdss-io/src/main/java/com/fzzy/igds/io/notify/ServerNotifyInvoker.java
new file mode 100644
index 0000000..f164bea
--- /dev/null
+++ b/fzzy-igdss-io/src/main/java/com/fzzy/igds/io/notify/ServerNotifyInvoker.java
@@ -0,0 +1,39 @@
+package com.fzzy.igds.io.notify;
+
+import com.fzzy.igds.domain.DeviceSer;
+
+/**
+ * 鏈嶅姟閫氱煡绋嬪簭璋冪敤锛岀敤浜庨�氱煡鍒嗘満涓婄嚎鍜岀绾垮鐞�
+ * @author Andy
+ *
+ */
+public interface ServerNotifyInvoker {
+	
+	public static final String BEAN_ID = "serverNotifyInvoker";
+
+	/**
+	 * 杩炴帴琚攢姣佸悗閫氱煡淇℃伅
+	 * @param businessKey TCP涓氬姟KEY
+	 * @param ip 璁惧IP
+	 * @param port 璁惧绔彛鍙�
+	 */
+	void connectDestory(String businessKey, String ip, Integer port);
+
+	/**
+	 * 杩炴帴琚縺娲荤殑閫氱煡
+	 * @param businessKey TCP涓氬姟KEY
+	 * @param address 璁惧IP
+	 * @param port 璁惧绔彛鍙�
+	 */
+	void connectActive(String businessKey, String address, Integer port);
+
+
+	/**
+	 * 鏍规嵁淇℃伅鑾峰彇鎺у埗鏌滀俊鎭�
+	 * @param companyId
+	 * @param address
+	 * @param port
+	 * @return
+	 */
+	DeviceSer getDeviceSer(String companyId, String address, Integer port);
+}
diff --git a/fzzy-igdss-io/src/main/java/com/fzzy/igds/iot/analysis/AnalysisService.java b/fzzy-igdss-io/src/main/java/com/fzzy/igds/iot/analysis/AnalysisService.java
new file mode 100644
index 0000000..79f312c
--- /dev/null
+++ b/fzzy-igdss-io/src/main/java/com/fzzy/igds/iot/analysis/AnalysisService.java
@@ -0,0 +1,265 @@
+package com.fzzy.igds.iot.analysis;
+
+import com.fzzy.igds.constant.Constant;
+import com.fzzy.igds.constant.OrderRespEnum;
+import com.fzzy.igds.constant.RedisConst;
+import com.fzzy.igds.data.GrainData;
+import com.fzzy.igds.domain.*;
+import com.fzzy.igds.io.notify.NotifyGrainInvoker;
+import com.fzzy.igds.iot.analysis.builder.ReMessageBuilder;
+import com.fzzy.igds.iot.analysis.message.DeviceAttr;
+import com.fzzy.igds.iot.analysis.message.DeviceAttrInfo;
+import com.fzzy.igds.io.notify.NotifyWebInvoker;
+import com.fzzy.igds.service.*;
+import com.fzzy.igds.utils.ContextUtil;
+import com.ruoyi.common.core.redis.RedisCache;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import javax.annotation.Resource;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @Description 瑙f瀽鍏ュ彛
+ * @Author CZT
+ * @Date 2025/11/11 18:20
+ */
+@Slf4j
+@Component(AnalysisService.BEAN_ID)
+public class AnalysisService {
+
+    public static final String BEAN_ID = "iot.analysisService";
+
+    @Resource
+    private DeviceSerService deviceSerService;
+    @Resource
+    private DeviceIotService deviceIotService;
+    @Autowired
+    private DepotService depotService;
+    @Autowired
+    private NotifyWebInvoker notifyWebInvoker;
+    @Autowired
+    private DepotConfService depotConfService;
+    @Autowired
+    private NotifyGrainInvoker notifyGrainInvoker;
+    @Resource
+    private QuantityService quantityService;
+
+    @Resource
+    private RedisCache redisCache;
+
+    /**
+     * @param sessionKey ip:port
+     * @param msg
+     */
+    public void analysis(String sessionKey, String msg) throws Exception {
+        String[] attr = sessionKey.split(":");
+        String ip = attr[0];
+        Integer port = Integer.valueOf(attr[1]);
+
+        DeviceAttr reMessage = ReMessageBuilder.getInstance().buildMessage( ip, port, msg);
+
+        if (null == reMessage || null == reMessage.getOrgId()) {
+            log.error("IOT缃戝叧----->>>骞冲彴锛氳繑鍥炰俊鎭病鏈夎幏鍙栫粍缁囩紪鐮佷俊鎭紝鏃犳硶缁х画瑙f瀽----{}", sessionKey);
+            return;
+        }
+
+        DeviceSer ser = deviceSerService.getCacheSerBySn(reMessage.getOrgId(),reMessage.getSn());
+        if (null == ser) {
+            String info = "IOT缃戝叧=" + reMessage.getDeviceId() + "杩斿洖淇℃伅娌℃湁鍖归厤鍒板垎鏈猴紝蹇界暐娑堟伅銆�";
+            log.error("IOT缃戝叧----->>>骞冲彴锛�" + info);
+            notifyWebInvoker.notifyWeb(reMessage.getOrgId(), OrderRespEnum.MSG_ERROR,"SYS", info);
+            // 娓呴櫎缂撳瓨骞堕攢姣侀摼鎺�
+            return;
+        }
+
+        //鏇存柊鍒嗘満鐘舵��
+        ser.setIp(ip);
+        ser.setPort(port);
+        ser.setStatus(Constant.YN_Y);
+        deviceSerService.updateByData(ser);
+        log.debug("IOT缃戝叧----->>>骞冲彴锛氭墍灞炵粍缁�-{}锛屽垎鏈�-{} 杩斿洖鐨勫懡浠や俊鎭�={}", ser.getCompanyId(), ser.getName(), reMessage.toString());
+        List<DeviceIot> deviceIots = deviceIotService.getCacheDeviceIotBySerId(ser.getCompanyId(),ser.getId());
+        if(deviceIots == null || deviceIots.size() <= 0){
+            log.error("IOT缃戝叧----->>>骞冲彴锛�" + "娌℃湁鑾峰彇鍒板垎鏈轰笅闈㈡湁璁惧!");
+            return ;
+        }
+
+        DeviceIot deviceIot = deviceIots.stream().filter(item -> (item.getPassCode()+"").equals(reMessage.getDeviceId())).findAny().orElse(null);
+        if(deviceIot == null ){
+            log.error("IOT缃戝叧----->>>骞冲彴锛�" + "娌℃湁鑾峰彇鍒拌澶囧崟涓�!");
+            return ;
+        }
+
+        log.info("IOT缃戝叧----->>>骞冲彴锛�"+ "寮�濮嬭В鏋愭暟鎹�" + reMessage.toString());
+        if(StringUtils.isEmpty(reMessage.getType())){
+            //娑蹭綅瑙f瀽
+            analysisHeight(reMessage, ser,deviceIot);
+        }
+        if("2".equals(reMessage.getType()) || "02".equals(reMessage.getType())){
+            //娌规俯瑙f瀽
+            analysisOilGrain(reMessage, ser,deviceIot);
+        }else {
+            //娑蹭綅瑙f瀽
+            analysisHeight(reMessage, ser,deviceIot);
+        }
+    }
+
+    /**
+     * 缃戠娌规儏瑙f瀽
+     * @param deviceAttr
+     * @param ser
+     */
+    public void analysisOilGrain(DeviceAttr deviceAttr, DeviceSer ser, DeviceIot deviceIot) {
+        try {
+            log.info("IOT缃戝叧----->>>骞冲彴锛�"+ "寮�濮嬭В鏋愭俯搴︽暟鎹�" + deviceAttr.toString());
+            List<DeviceAttrInfo> list = deviceAttr.getTerminalAttrInfoList();
+            if(null ==  list || list.isEmpty()){
+                log.error("IOT缃戝叧----->>>骞冲彴锛�" + "娌规儏鏁版嵁涓虹┖锛屼笉瑙f瀽!");
+                return;
+            }
+
+            Integer ceng = 0;
+            String points = "";
+            Double max = null, min = null, sumT = 0.0;
+            Double temp = 0.0;
+            for (DeviceAttrInfo iotInfo : list) {
+                if("1".equals(iotInfo.getPasscode()) || "2".equals(iotInfo.getPasscode())){
+                    //閫氶亾鍙蜂负1鎴栬��2鏃讹紝鏄�氫俊鐘舵�佸拰鍛婅鐘舵�侊紝涓嶈В鏋�
+                    continue;
+                }
+                points += iotInfo.getValue() + ",";
+                ceng ++;
+
+                temp = Double.valueOf(iotInfo.getValue());
+                if(null == max){
+                    max = temp;
+                }
+                if(null == min){
+                    min = temp;
+                }
+                if (temp > max) {
+                    max = temp;
+                }
+                if (temp < min) {
+                    min = temp;
+                }
+                sumT += temp;
+            }
+
+            DepotConf depotConf = depotConfService.getCacheDepotConfByDepotId(ser.getCompanyId(), deviceIot.getDepotId());
+            Depot depot = depotService.getCacheDepot(ser.getCompanyId(), deviceIot.getDepotId());
+            Grain grain = new Grain();
+            grain.setBatchId(ContextUtil.getBatchIdByFireq(depotConf.getGrainFreq()));
+            grain.setReceiveDate(new Date());
+            grain.setCable("1");
+            grain.setCableCir(ceng + "");
+            grain.setPoints(points);
+            grain.setCheckUser("绯荤粺");
+            grain.setDepotId(deviceIot.getDepotId());
+            grain.setCompanyId(depotConf.getCompanyId());
+
+            grain.setHumidityIn(-100.0);
+            grain.setTempIn(-100.0);
+
+            grain.setTempAve(sumT/ceng);
+            grain.setTempMax(max);
+            grain.setTempMin(min);
+            grain.setDeptId(depot.getDeptId());
+
+            //娌圭綈 娑蹭綅楂樺害锛屾湁灏辫祴鍊�
+            GrainData data = (GrainData) redisCache.getCacheObject(RedisConst.buildKey(ser.getCompanyId(),RedisConst.KEY_DEPOT_HEIGHT,grain.getDepotId()));
+            if(data!= null && StringUtils.isNotEmpty(data.getOilHeight())){
+                grain.setOilHeight(data.getOilHeight());
+            }
+
+            // 鐢ㄦ埛灏佽濂芥暟鎹嵆鍙�
+            notifyGrainInvoker.analysisSuccess(grain, depot);
+            log.info("IOT缃戝叧----->>>骞冲彴锛氭补娓╄В鏋愬畬鎴愶細" + data);
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+        }
+    }
+
+    /**
+     * 缃戠娑蹭綅楂樺害瑙f瀽
+     * @param deviceAttr
+     * @param ser
+     */
+    public void analysisHeight(DeviceAttr deviceAttr, DeviceSer ser, DeviceIot deviceIot) {
+        try {
+            Depot depot = depotService.getCacheDepot(ser.getCompanyId(), deviceIot.getDepotId());
+            if(null == depot){
+                log.error("IOT缃戝叧----->>>骞冲彴锛�" + "鏈幏鍙栦粨搴撲俊鎭紝涓嶈В鏋�!");
+                return;
+            }
+
+            List<DeviceAttrInfo> list = deviceAttr.getTerminalAttrInfoList();
+            if(null ==  list || list.isEmpty()){
+                log.error("IOT缃戝叧----->>>骞冲彴锛�" + "娌规儏鏁版嵁涓虹┖锛屼笉瑙f瀽!");
+                return;
+            }
+
+            Double diameter = 0.0;   //鐩村緞
+            Double volume = 0.0;     //浣撶Н
+            Double bulkWeight = 0.0; //瀹归噸
+            Double realHeight = 0.0; //椤甸潰楂樺害
+            Double maxHeight = 0.0;  //鏈�澶ч珮搴�
+            Double storage = 0.0;    //璁$畻鍌ㄩ噺
+            Double heightPer = 0.0;    //楂樺害鐧惧垎姣�
+
+            if(null != depot.getHeight()){
+                maxHeight = depot.getHeight();
+            }
+            if(null != depot.getLength()){
+                diameter = depot.getLength();
+            }
+            if(null != depot.getBulkWeight()){
+                bulkWeight = depot.getBulkWeight();
+            }
+            //瑙f瀽鐪熷疄楂樺害
+            realHeight = Double.valueOf(list.get(2).getValue());
+
+            //璁$畻浣撶Н
+            volume = 3.14159 * Math.pow(diameter / 2, 2) * realHeight;
+            //鍒ゆ柇浣撶Н鏄惁涓鸿礋锛屼负璐熷�煎垯涓嶈绠楋紝閲嶇疆涓�0
+            if (volume < 0) {
+                volume = 0.0;
+            }
+
+            //璁$畻閲嶉噺
+            storage = volume * bulkWeight;
+            storage = Double.valueOf(String.format("%.2f", storage));
+
+            //楂樺害鐧惧垎姣�
+            if(maxHeight > 0){
+                heightPer = Double.valueOf(String.format("%.2f", realHeight/maxHeight * 100));
+            }
+
+            Quantity data = new Quantity();
+
+            data.setBatchId(depot + ContextUtil.generateId());
+            data.setCompanyId(ser.getCompanyId());
+            data.setDeptId(depot.getDeptId());
+            data.setDepotId(deviceIot.getDepotId());
+
+            data.setDiameter(depot.getLength());
+            data.setHeightPer(heightPer);
+            data.setHeight(realHeight);
+            data.setBulk(volume);
+            data.setWeight(storage);
+
+            data.setReceiveDate(new Date());
+            data.setCheckUser("绯荤粺");
+
+            quantityService.saveData( data);
+
+            log.info("楂樺害瑙f瀽瀹屾垚锛�" + data);
+
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+        }
+    }
+}
\ No newline at end of file
diff --git a/fzzy-igdss-io/src/main/java/com/fzzy/igds/iot/analysis/builder/ReMessageBuilder.java b/fzzy-igdss-io/src/main/java/com/fzzy/igds/iot/analysis/builder/ReMessageBuilder.java
new file mode 100644
index 0000000..eec196a
--- /dev/null
+++ b/fzzy-igdss-io/src/main/java/com/fzzy/igds/iot/analysis/builder/ReMessageBuilder.java
@@ -0,0 +1,72 @@
+package com.fzzy.igds.iot.analysis.builder;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.fzzy.igds.iot.analysis.message.DeviceAttr;
+import com.fzzy.igds.iot.analysis.message.DeviceAttrInfo;
+import com.fzzy.igds.iot.analysis.message.IoMessage;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @Description  鏍规嵁鎺ユ敹鍒扮殑淇℃伅杩涜灏佽
+ * @Author CZT
+ * @Date 2025/11/11 18:15
+ */
+public class ReMessageBuilder {
+    public static final String CHARSET = "UTF-8";
+    public static final String PREFIX = "<FZZY>";
+    public static final String SUFFIX = "<EEEE>";
+    public  final static  String ERROR_TAG = "null";
+    public  final static  String ERROR_STR = "#";
+    private final static ReMessageBuilder instance = new ReMessageBuilder();
+
+    private ReMessageBuilder() {
+    }
+
+    public static ReMessageBuilder getInstance() {
+        return instance;
+    }
+
+    /**
+     * @param ip
+     * @param port
+     * @param message
+     * @return
+     */
+    public DeviceAttr buildMessage( String ip, int port, String message) throws Exception {
+        IoMessage ioMessage = JSON.parseObject(message, IoMessage.class);
+        JSONArray passCodeArray = JSON.parseArray(ioMessage.getContent());
+        if (passCodeArray == null || passCodeArray .size() == 0) {
+            return null;
+        }
+        List<DeviceAttrInfo> terminalAttrInfoList = new ArrayList<>();
+        JSONObject passCode = null;
+        for(int i = 0; i< passCodeArray.size(); i++ ){
+            passCode = passCodeArray.getJSONObject(i);
+            if(passCode == null){
+                continue;
+            }
+            DeviceAttrInfo terminalAttrInfo = new DeviceAttrInfo();
+            terminalAttrInfo.setPasscode(passCode.getString("passcode"));
+            terminalAttrInfo.setTime(ioMessage.getTime());
+            String value = passCode.getString("value");
+            // null 鍊兼浛鎹负#鍙�
+            if(ERROR_TAG.equals(value))value = ERROR_STR;
+            terminalAttrInfo.setValue(value);
+            terminalAttrInfoList.add(terminalAttrInfo);
+        }
+        DeviceAttr request = new DeviceAttr();
+        request.setSn(ioMessage.getSn());
+        request.setOrderId(ioMessage.getOrderId());
+        request.setOrgId(ioMessage.getOrgId());
+        request.setGroupId(ioMessage.getGroupId());
+        request.setGatewayId(ioMessage.getIedId());
+        request.setDeviceId(ioMessage.getDeviceId());
+        request.setTerminalAttrInfoList(terminalAttrInfoList);
+        request.setType(ioMessage.getType());
+        return request;
+    }
+}
diff --git a/fzzy-igdss-io/src/main/java/com/fzzy/igds/iot/analysis/message/DeviceAttr.java b/fzzy-igdss-io/src/main/java/com/fzzy/igds/iot/analysis/message/DeviceAttr.java
new file mode 100644
index 0000000..c657efe
--- /dev/null
+++ b/fzzy-igdss-io/src/main/java/com/fzzy/igds/iot/analysis/message/DeviceAttr.java
@@ -0,0 +1,26 @@
+package com.fzzy.igds.iot.analysis.message;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.List;
+
+/**
+ * @Description 杩滅▼鏇存柊缁堢璁惧鐨勫睘鎬у�硷紝鍐欏叆鍜屾帶鍒朵娇鐢�
+ * @Author CZT
+ * @Date 2025/11/11 18:12
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class DeviceAttr {
+
+	private String orderId;// 璁㈠崟鍙凤紝瀹㈡埛绔繚璇佸敮涓�
+	private String orgId;//鎵�灞炵粍缁�
+	private String groupId;//鎵�灞炲垎缁�
+	private String gatewayId;//缃戝叧涓�鏍囪瘑
+	private String sn;
+	private String deviceId;// 缁堢缂栧彿
+	private String type;// 绫诲瀷:01-娑蹭綅楂樺害锛�02-娓╁害淇℃伅
+	private List<DeviceAttrInfo> terminalAttrInfoList;
+	private DeviceAttrInfo deviceAttrInfo;
+}
diff --git a/fzzy-igdss-io/src/main/java/com/fzzy/igds/iot/analysis/message/DeviceAttrInfo.java b/fzzy-igdss-io/src/main/java/com/fzzy/igds/iot/analysis/message/DeviceAttrInfo.java
new file mode 100644
index 0000000..4b96baa
--- /dev/null
+++ b/fzzy-igdss-io/src/main/java/com/fzzy/igds/iot/analysis/message/DeviceAttrInfo.java
@@ -0,0 +1,16 @@
+package com.fzzy.igds.iot.analysis.message;
+
+import lombok.Data;
+
+/**
+ * @Description 缁堢璁惧鐨勫睘鎬т俊鎭�
+ * @Author CZT
+ * @Date 2025/11/11 18:09
+ */
+@Data
+public class DeviceAttrInfo {
+    private String name;//閫氶亾鍚嶇О锛屽嵆灞炴�у悕绉�
+    private String passcode;//閫氶亾缂栫爜锛屽嵆灞炴�х紪鐮�
+    private String value;//灞炴�у��
+    private String time;//鏃堕棿 鐢ㄦ潵鏍囪瘑灞炴�ф槸鍚︿骇鐢熶簡鍙樺寲
+}
diff --git a/fzzy-igdss-io/src/main/java/com/fzzy/igds/iot/analysis/message/IoMessage.java b/fzzy-igdss-io/src/main/java/com/fzzy/igds/iot/analysis/message/IoMessage.java
new file mode 100644
index 0000000..ce50d43
--- /dev/null
+++ b/fzzy-igdss-io/src/main/java/com/fzzy/igds/iot/analysis/message/IoMessage.java
@@ -0,0 +1,30 @@
+package com.fzzy.igds.iot.analysis.message;
+
+import lombok.Data;
+
+/**
+ * @Description 缁堢璁惧鐨勫睘鎬т俊鎭�
+ * @Author CZT
+ * @Date 2025/11/11 18:09
+ */
+@Data
+public class IoMessage {
+    private String orgId;
+    private String groupId;
+    private String iedId;
+    private String functionId;
+    private String deviceId;
+    private String result;
+    private String orderId;
+    private String time;
+    private String signHeader;
+    private String len;
+    private String content;
+    private String signBody;
+    private String file;//闄勪欢
+    private byte[] fileBytes;
+    private String sn;
+    private String type;
+    //2021骞�6鏈�11鏃� 12:13:00 娣诲姞
+    private String sessionId;
+}
diff --git a/fzzy-igdss-io/src/main/java/com/fzzy/igds/iot/server/IotMessageConsumer.java b/fzzy-igdss-io/src/main/java/com/fzzy/igds/iot/server/IotMessageConsumer.java
new file mode 100644
index 0000000..4c719b0
--- /dev/null
+++ b/fzzy-igdss-io/src/main/java/com/fzzy/igds/iot/server/IotMessageConsumer.java
@@ -0,0 +1,42 @@
+package com.fzzy.igds.iot.server;
+
+import com.fzzy.igds.iot.analysis.AnalysisService;
+import com.fzzy.igds.iot.analysis.builder.ReMessageBuilder;
+import com.ld.io.api.IoMsgConsumer;
+import com.ld.io.api.IoSession;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * @Description  FZZT-IOT 娑堟伅鎺ユ敹绫�
+ * @Author CZT
+ * @Date 2025/11/11 18:17
+ */
+@Service
+@Slf4j
+public class IotMessageConsumer implements IoMsgConsumer {
+
+    @Autowired
+    private AnalysisService analysisService;
+
+    /**
+     * 闃熷垪閲岄潰澶勭悊娑堟伅
+     * @param ioSession
+     * @param bytes
+     */
+    public void consume(IoSession ioSession, byte[] bytes) {
+        if (null == bytes) {
+            log.error("Reply bytes is null");
+            return;
+        }
+        try {
+            String message = new String(bytes, ReMessageBuilder.CHARSET);
+            message = message.substring(ReMessageBuilder.PREFIX.length());
+            log.info("鏀跺埌IOT缃戝叧娑堟伅锛�" + message);
+            analysisService.analysis(ioSession.getBusinessKey(),message);
+        }catch (Exception e){
+            log.error(e.getMessage(),e);
+        }
+    }
+}
\ No newline at end of file
diff --git a/fzzy-igdss-io/src/main/java/com/fzzy/igds/iot/server/IotServerEngine.java b/fzzy-igdss-io/src/main/java/com/fzzy/igds/iot/server/IotServerEngine.java
new file mode 100644
index 0000000..6fddbeb
--- /dev/null
+++ b/fzzy-igdss-io/src/main/java/com/fzzy/igds/iot/server/IotServerEngine.java
@@ -0,0 +1,69 @@
+package com.fzzy.igds.iot.server;
+
+import com.fzzy.igds.iot.analysis.builder.ReMessageBuilder;
+import com.ld.io.api.IoServerOption;
+import com.ld.io.api.IoSession;
+import com.ld.io.api.IoSessionQuery;
+import com.ld.io.netty.NettyServer;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * @Description  FZZT-IOT 鏈嶅姟鍚姩绫�
+ * @Author CZT
+ * @Date 2025/11/11 18:09
+ */
+@Slf4j
+@Service
+public class IotServerEngine {
+
+    public static final Integer PORT = 9302;
+
+    @Autowired
+    private IotMessageConsumer defaultMessageConsumer;
+    @Autowired
+    private IotSessionListener defaultSessionListener;
+
+    private IoSessionQuery sessionQuery;
+
+    public void start(Integer port) {
+        IoServerOption ioServerOption = new IoServerOption();
+
+        if (null != port) {
+            ioServerOption.setPort(port);
+        } else {
+            ioServerOption.setPort(PORT);
+        }
+
+        ioServerOption.setDelimiter(ReMessageBuilder.SUFFIX.getBytes());
+
+        NettyServer ioServer = new NettyServer(ioServerOption, defaultMessageConsumer, defaultSessionListener);
+        ioServer.startup();
+
+        sessionQuery = ioServer.getSessionQuery();
+        log.info("* ");
+        log.info("* ========================");
+        log.info("* ");
+        log.info("* [SERVER锛欶ZZY_IOT,PORT={}]", PORT);
+        log.info("* ");
+        log.info("* ========================");
+        log.info("* ");
+
+        System.out.println("* ========================");
+        System.out.println("* ");
+        System.out.println("* [SERVER锛欶ZZY_IOT,PORT={}]" + port);
+        System.out.println("* ");
+        System.out.println("* ========================");
+    }
+
+    public IoSessionQuery getSessionQuery() {
+        return sessionQuery;
+    }
+
+    public IoSession getSessionById(String sessionId) {
+        return this.getSessionQuery().getSession(sessionId);
+    }
+
+
+}
\ No newline at end of file
diff --git a/fzzy-igdss-io/src/main/java/com/fzzy/igds/iot/server/IotSessionListener.java b/fzzy-igdss-io/src/main/java/com/fzzy/igds/iot/server/IotSessionListener.java
new file mode 100644
index 0000000..49e5da6
--- /dev/null
+++ b/fzzy-igdss-io/src/main/java/com/fzzy/igds/iot/server/IotSessionListener.java
@@ -0,0 +1,40 @@
+package com.fzzy.igds.iot.server;
+
+
+import com.fzzy.igds.io.notify.ServerNotifyInvoker;
+import com.fzzy.igds.utils.SpringUtil;
+import com.ld.io.api.IoSession;
+import com.ld.io.api.IoSessionListener;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+/**
+ * @Description
+ * @Author CZT
+ * @Date 2025/11/11 18:09
+ */
+@Slf4j
+@Service
+public class IotSessionListener implements IoSessionListener {
+    private ServerNotifyInvoker serverNotifyInvoker;
+
+    @Override
+    public void onCreate(IoSession session) {
+
+        log.info("++++鏂板缓杩炴帴++++-IP={}锛孭ORT={}", session.getAddress(), session.getPort());
+
+        // 娣诲姞鑷畾涔変笟鍔D
+        session.setBusinessKey(ServerUtils.getServerKey(session.getAddress(), session.getPort()));
+    }
+
+    @Override
+    public void onDestroy(IoSession session) {
+        log.info("----杩炴帴鏂紑-----IP={}锛孭ORT={}", session.getAddress(), session.getPort());
+
+        if (null == serverNotifyInvoker) {
+            serverNotifyInvoker = SpringUtil.getBean(ServerNotifyInvoker.class);
+        }
+        serverNotifyInvoker.connectDestory(session.getBusinessKey(),
+                session.getAddress(), session.getPort());
+    }
+}
diff --git a/fzzy-igdss-io/src/main/java/com/fzzy/igds/iot/server/ServerUtils.java b/fzzy-igdss-io/src/main/java/com/fzzy/igds/iot/server/ServerUtils.java
new file mode 100644
index 0000000..4fbf3fb
--- /dev/null
+++ b/fzzy-igdss-io/src/main/java/com/fzzy/igds/iot/server/ServerUtils.java
@@ -0,0 +1,23 @@
+package com.fzzy.igds.iot.server;
+
+/**
+ * @Description 宸ュ叿绫�
+ * @Author CZT
+ * @Date 2025/11/11 18:07
+ */
+public class ServerUtils {
+
+
+    /**
+     * 鐢熸垚TCP杩炴帴鐨凨EY
+     *
+     * @param ip
+     * @param port
+     * @return
+     */
+    public static String getServerKey(String ip, Integer port) {
+        return ip + ":" + port;
+    }
+
+
+}
diff --git a/fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/analysis/AnalysisService.java b/fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/analysis/AnalysisService.java
index 347cd7b..dc6d81b 100644
--- a/fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/analysis/AnalysisService.java
+++ b/fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/analysis/AnalysisService.java
@@ -7,7 +7,7 @@
 import com.fzzy.igds.domain.FileInfo;
 import com.fzzy.igds.domain.Quantity;
 import com.fzzy.igds.domain.QuantityConf;
-import com.fzzy.igds.notify.NotifyWebInvoker;
+import com.fzzy.igds.io.notify.NotifyWebInvoker;
 import com.fzzy.igds.quantity.command.BhznRemoteQuantityImpl;
 import com.fzzy.igds.quantity.command.CommandBuilder;
 import com.fzzy.igds.quantity.dto.IoMessage;
@@ -224,6 +224,7 @@
         quantityData.setDeptId(depot.getDeptId());
         quantityData.setCompanyId(depot.getCompanyId());
         quantityData.setPoints("");
+        quantityData.setCheckUser(request.getExeUser());
         quantityService.saveData(quantityData);
         //鐩存帴杩斿洖
         remoteQuantity.sendMsg(ip, port, CommandBuilder.getInstance().build2004Message(message));
diff --git a/fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/command/BhznRemoteQuantityImpl.java b/fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/command/BhznRemoteQuantityImpl.java
index 96145ab..5d9e9ee 100644
--- a/fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/command/BhznRemoteQuantityImpl.java
+++ b/fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/command/BhznRemoteQuantityImpl.java
@@ -3,7 +3,7 @@
 import com.fzzy.igds.constant.OrderRespEnum;
 import com.fzzy.igds.constant.ProtocolEnum;
 import com.fzzy.igds.io.service.RemoteQuantityService;
-import com.fzzy.igds.notify.NotifyWebInvoker;
+import com.fzzy.igds.io.notify.NotifyWebInvoker;
 import com.fzzy.igds.quantity.dto.IoMessage;
 import com.fzzy.igds.quantity.server.BhznQuantityServerEngine;
 import com.fzzy.igds.quantity.util.ServerUtils;
diff --git a/fzzy-igdss-view/src/main/java/com/fzzy/igds/Depot.view.xml b/fzzy-igdss-view/src/main/java/com/fzzy/igds/Depot.view.xml
index 291836b..542db0f 100644
--- a/fzzy-igdss-view/src/main/java/com/fzzy/igds/Depot.view.xml
+++ b/fzzy-igdss-view/src/main/java/com/fzzy/igds/Depot.view.xml
@@ -348,7 +348,7 @@
           </Children>
         </FieldSet>
         <FieldSet layout="padding:5">
-          <Property name="caption">璐ㄦ淇℃伅</Property>
+          <Property name="caption">鍏朵粬淇℃伅</Property>
           <Buttons/>
           <Children>
             <AutoForm>
@@ -357,7 +357,27 @@
               <Property name="labelSeparator"> : </Property>
               <Property name="labelAlign">right</Property>
               <Property name="cols">*,*,*,*,*,*,*,*</Property>
-              <Property name="labelWidth">80</Property>
+              <Property name="labelWidth">100</Property>
+              <AutoFormElement layoutConstraint="colSpan:2">
+                <Property name="name">length</Property>
+                <Property name="property">length</Property>
+                <Editor/>
+              </AutoFormElement>
+              <AutoFormElement layoutConstraint="colSpan:2">
+                <Property name="name">width</Property>
+                <Property name="property">width</Property>
+                <Editor/>
+              </AutoFormElement>
+              <AutoFormElement layoutConstraint="colSpan:2">
+                <Property name="name">height</Property>
+                <Property name="property">height</Property>
+                <Editor/>
+              </AutoFormElement>
+              <AutoFormElement layoutConstraint="colSpan:2">
+                <Property name="name">bulkWeight</Property>
+                <Property name="property">bulkWeight</Property>
+                <Editor/>
+              </AutoFormElement>
               <AutoFormElement layoutConstraint="colSpan:2">
                 <Property name="name">perWet</Property>
                 <Property name="property">perWet</Property>
@@ -366,11 +386,6 @@
               <AutoFormElement layoutConstraint="colSpan:2">
                 <Property name="name">perImpurity</Property>
                 <Property name="property">perImpurity</Property>
-                <Editor/>
-              </AutoFormElement>
-              <AutoFormElement layoutConstraint="colSpan:2">
-                <Property name="name">bulkWeight</Property>
-                <Property name="property">bulkWeight</Property>
                 <Editor/>
               </AutoFormElement>
               <AutoFormElement layoutConstraint="colSpan:2">
diff --git a/fzzy-igdss-view/src/main/java/com/fzzy/igds/DepotConf.view.xml b/fzzy-igdss-view/src/main/java/com/fzzy/igds/DepotConf.view.xml
index 1c7ecdf..c8fc624 100644
--- a/fzzy-igdss-view/src/main/java/com/fzzy/igds/DepotConf.view.xml
+++ b/fzzy-igdss-view/src/main/java/com/fzzy/igds/DepotConf.view.xml
@@ -262,21 +262,6 @@
                 <Editor/>
               </AutoFormElement>
               <AutoFormElement>
-                <Property name="property">diameter</Property>
-                <Property name="name">diameter</Property>
-                <Editor/>
-              </AutoFormElement>
-              <AutoFormElement>
-                <Property name="property">height</Property>
-                <Property name="name">height</Property>
-                <Editor/>
-              </AutoFormElement>
-              <AutoFormElement>
-                <Property name="name">updateBy</Property>
-                <Property name="property">updateBy</Property>
-                <Editor/>
-              </AutoFormElement>
-              <AutoFormElement>
                 <Property name="name">grainFreq</Property>
                 <Property name="property">grainFreq</Property>
                 <Editor/>
diff --git a/fzzy-igdss-view/src/main/java/com/fzzy/igds/DeviceIot.view.xml b/fzzy-igdss-view/src/main/java/com/fzzy/igds/DeviceIot.view.xml
index 1bbb631..0e2a6b3 100644
--- a/fzzy-igdss-view/src/main/java/com/fzzy/igds/DeviceIot.view.xml
+++ b/fzzy-igdss-view/src/main/java/com/fzzy/igds/DeviceIot.view.xml
@@ -170,7 +170,7 @@
       <ClientEvent name="onHide">view.id(&quot;dsDeviceIot&quot;).getData().cancel();</ClientEvent>
       <Property name="iconClass">fa fa-tasks</Property>
       <Property name="caption">璁惧淇℃伅</Property>
-      <Property name="width">35%</Property>
+      <Property name="width">60%</Property>
       <Buttons>
         <Button>
           <Property name="action">actionDeviceIotSave</Property>
diff --git a/fzzy-igdss-view/src/main/java/models/core.model.xml b/fzzy-igdss-view/src/main/java/models/core.model.xml
index bf31da5..798bdbb 100644
--- a/fzzy-igdss-view/src/main/java/models/core.model.xml
+++ b/fzzy-igdss-view/src/main/java/models/core.model.xml
@@ -302,7 +302,22 @@
     <PropertyDef name="bulkWeight">
       <Property name="dataType">Double</Property>
       <Property name="label">瀹归噸</Property>
-      <Property name="displayFormat">0.0 g/L</Property>
+      <Property name="displayFormat">#0.00 g/L</Property>
+    </PropertyDef>
+    <PropertyDef name="length">
+      <Property name="dataType">Double</Property>
+      <Property name="label">闀垮害/鐩村緞</Property>
+      <Property name="displayFormat">#0.00 绫�</Property>
+    </PropertyDef>
+    <PropertyDef name="width">
+      <Property name="dataType">Double</Property>
+      <Property name="label">瀹藉害</Property>
+      <Property name="displayFormat">#0.00 绫�</Property>
+    </PropertyDef>
+    <PropertyDef name="height">
+      <Property name="dataType">Double</Property>
+      <Property name="label">楂樺害</Property>
+      <Property name="displayFormat">#0.00 绫�</Property>
     </PropertyDef>
     <PropertyDef name="storeKeeper">
       <Property></Property>
@@ -878,16 +893,6 @@
     <PropertyDef name="startRow">
       <Property name="dataType">Integer</Property>
       <Property name="label">璧峰鏍瑰彿</Property>
-    </PropertyDef>
-    <PropertyDef name="diameter">
-      <Property name="dataType">Double</Property>
-      <Property name="label">绛掍粨鐩村緞</Property>
-      <Property name="displayFormat">#0.00 绫�</Property>
-    </PropertyDef>
-    <PropertyDef name="height">
-      <Property name="dataType">Double</Property>
-      <Property name="label">绛掍粨楂樺害</Property>
-      <Property name="displayFormat">#0.00 绫�</Property>
     </PropertyDef>
     <PropertyDef name="grainAuto">
       <Property></Property>

--
Gitblit v1.9.3