learshaw 4 месяцев назад
Родитель
Сommit
c21d4e5dc3

+ 37 - 0
ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/config/GrowattConfig.java

@@ -0,0 +1,37 @@
+/*
+ * 文 件 名:  GrowattConfig
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/12/15
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.List;
+
+/**
+ * 古瑞瓦特配置
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/12/15]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+@Data
+@Configuration
+@ConfigurationProperties(prefix = "adapter.growatt")
+public class GrowattConfig {
+    private String url;
+
+    private String token;
+
+    private List<String> plantList;
+}

+ 218 - 0
ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/core/GrowattTemplate.java

@@ -0,0 +1,218 @@
+/*
+ * 文 件 名:  GrowattTemplate
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/12/16
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.core;
+
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.support.retrofit.Retrofit2ConverterFactory;
+import com.huashe.common.exception.Assert;
+import com.ruoyi.ems.model.growatt.DataLogger;
+import com.ruoyi.ems.model.growatt.DeviceInfo;
+import com.ruoyi.ems.retrofit.GrowattApi;
+import lombok.extern.slf4j.Slf4j;
+import okhttp3.OkHttpClient;
+import org.apache.commons.lang3.StringUtils;
+import retrofit2.Call;
+import retrofit2.Response;
+import retrofit2.Retrofit;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Growatt - 古瑞瓦特 操作模板
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/12/16]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+@Slf4j
+public class GrowattTemplate extends BaseApiTemplate {
+    /**
+     * 访问地址
+     */
+    protected String url;
+
+    /**
+     * 调用令牌
+     */
+    protected String token;
+
+    /**
+     * 调用代理
+     */
+    protected final GrowattApi api;
+
+    public GrowattTemplate(String restUrl, String token) {
+        this.url = restUrl;
+        this.token = token;
+
+        OkHttpClient httpClient = getClient();
+        Retrofit retrofit = new Retrofit.Builder().baseUrl(restUrl)
+            .addConverterFactory(Retrofit2ConverterFactory.create()).client(httpClient).build();
+        this.api = retrofit.create(GrowattApi.class);
+    }
+
+    /**
+     * 构造调用模板
+     *
+     * @param restUrl        服务地址 (http://ip:port)
+     * @param connectTimeout 连接超时
+     * @param readTimeout    读取超时
+     * @param writeTimeout   写超时
+     */
+    public GrowattTemplate(String restUrl, String token, int connectTimeout, int readTimeout, int writeTimeout) {
+        super.connectTimeout = connectTimeout;
+        super.readTimeout = readTimeout;
+        super.writeTimeout = writeTimeout;
+        this.url = restUrl;
+        this.token = token;
+
+        OkHttpClient httpClient = getClient();
+        Retrofit retrofit = new Retrofit.Builder().baseUrl(restUrl)
+            .addConverterFactory(Retrofit2ConverterFactory.create()).client(httpClient).build();
+        api = retrofit.create(GrowattApi.class);
+    }
+
+    /**
+     * 获取采集器列表
+     *
+     * @param plantId 电站ID
+     * @return 采集器列表
+     */
+    public List<DataLogger> getDatalogList(String plantId) {
+        List<DataLogger> list = new ArrayList<>();
+
+        try {
+            int pageNo = 1;
+            int pageSize = 100;
+            boolean isLastPage = true;
+
+            do {
+                // 执行调用
+                Call<String> call = api.getDatalogList(token, plantId, pageNo, pageSize);
+                Response<String> response = call.execute();
+                log.debug("getDatalogList response:{}", response);
+
+                Assert.isTrue(response.isSuccessful(), response.code(), response.message());
+                JSONObject resJson = JSONObject.parseObject(response.body());
+                Assert.isTrue(resJson.getIntValue("error_code") == 0, resJson.getIntValue("error_code"),
+                    resJson.getString("error_msg"));
+
+                JSONObject data = resJson.getJSONObject("data");
+
+                if (null != data) {
+                    String dataStr = data.getString("dataloggers");
+                    list.addAll(JSONObject.parseArray(dataStr, DataLogger.class));
+
+                    int count = data.getIntValue("count");
+                    isLastPage = list.size() >= count;
+
+                    if (!isLastPage) {
+                        pageNo++;
+                    }
+                }
+            }
+            while (!isLastPage);
+        }
+        catch (Exception e) {
+            log.error("getDatalogList fail!", e);
+        }
+
+        return list;
+    }
+
+    /**
+     * 获取设备列表
+     *
+     * @param plantId 电站ID
+     * @return 设备列表
+     */
+    public List<DeviceInfo> getDeviceList(String plantId) {
+        List<DeviceInfo> list = new ArrayList<>();
+
+        try {
+            int pageNo = 1;
+            int pageSize = 100;
+            boolean isLastPage = true;
+
+            do {
+                // 执行调用
+                Call<String> call = api.getDeviceList(token, plantId, pageNo, pageSize);
+                Response<String> response = call.execute();
+                log.debug("getDeviceList response:{}", response);
+
+                Assert.isTrue(response.isSuccessful(), response.code(), response.message());
+                JSONObject resJson = JSONObject.parseObject(response.body());
+                Assert.isTrue(resJson.getIntValue("error_code") == 0, resJson.getIntValue("error_code"),
+                    resJson.getString("error_msg"));
+
+                JSONObject data = resJson.getJSONObject("data");
+
+                if (null != data) {
+                    String dataStr = data.getString("devices");
+                    list.addAll(JSONObject.parseArray(dataStr, DeviceInfo.class));
+
+                    int count = data.getIntValue("count");
+                    isLastPage = list.size() >= count;
+
+                    if (!isLastPage) {
+                        pageNo++;
+                    }
+                }
+            }
+            while (!isLastPage);
+        }
+        catch (Exception e) {
+            log.error("getDeviceList fail!", e);
+        }
+
+        return list;
+    }
+
+    /**
+     * 获取设备列表
+     *
+     * @param type 类型 16:inverter, 17:SPH, 18:MAX, 19:SPA, 22:MIN
+     * @param snList 设备SN集合
+     * @return 设备列表
+     */
+    public Map<String, Object> getDeviceData(int type, List<String> snList) {
+        Map<String, Object> retMap = new HashMap<>();
+
+        try {
+            // 执行调用
+            String devSnStr = StringUtils.join(snList, ",");
+            Call<String> call = api.getDeviceData(token, type, devSnStr);
+            Response<String> response = call.execute();
+            log.debug("getDeviceData response:{}", response);
+
+            Assert.isTrue(response.isSuccessful(), response.code(), response.message());
+            JSONObject resJson = JSONObject.parseObject(response.body());
+            Assert.isTrue(resJson.getIntValue("error_code") == 0, resJson.getIntValue("error_code"),
+                resJson.getString("error_msg"));
+
+            JSONObject data = resJson.getJSONObject("data");
+
+            if (null != data) {
+                retMap = data.getInnerMap();
+            }
+        }
+        catch (Exception e) {
+            log.error("getDeviceData fail!", e);
+        }
+
+        return retMap;
+    }
+}

+ 43 - 0
ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/model/growatt/DataLogger.java

@@ -0,0 +1,43 @@
+/*
+ * 文 件 名:  DataLogger
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/12/16
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.model.growatt;
+
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.annotation.JSONField;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 古瑞瓦特采集器
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/12/16]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+@Data
+public class DataLogger {
+    private String sn;
+    private String model;
+    private Integer type;
+    @JSONField(name = "netmode")
+    private String netMode;
+    private String manufacturer;
+    private boolean lost;
+    @JSONField(name = "last_update_time")
+    private JSONObject updateTime;
+
+    private Date getUpdateTime() {
+        return new Date(updateTime.getLongValue("time"));
+    }
+}

+ 51 - 0
ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/model/growatt/DeviceInfo.java

@@ -0,0 +1,51 @@
+/*
+ * 文 件 名:  DeviceInfo
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/12/16
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.model.growatt;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import lombok.Data;
+
+/**
+ * 设备(逆变器)
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/12/16]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+@Data
+public class DeviceInfo {
+    @JSONField(name = "device_sn")
+    private String deviceSn;
+
+    private String model;
+
+    /**
+     * 设备类型(1:逆变器(含MAX),2:储能机,3:其他设备,4:MAX(单MAX),5:SPH,6:SPA,7:MIN,8:PCS,9:HPS,10:PBD)
+     */
+    private int type;
+
+    @JSONField(name = "datalogger_sn")
+    private String dataLoggerSn;
+
+    /**
+     * 	设备状态
+     */
+    private int status;
+
+    private String manufacturer;
+
+    private boolean lost;
+
+    @JSONField(name = "last_update_time")
+    private String lastUpdateTime;
+}

+ 66 - 0
ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/retrofit/GrowattApi.java

@@ -0,0 +1,66 @@
+/*
+ * 文 件 名:  GrowattApi
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/12/15
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.retrofit;
+
+import retrofit2.Call;
+import retrofit2.http.GET;
+import retrofit2.http.Header;
+import retrofit2.http.Headers;
+import retrofit2.http.POST;
+import retrofit2.http.Query;
+
+/**
+ * Growatt - 古瑞瓦特(逆变器、光伏监测API)
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/12/15]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+public interface GrowattApi {
+    /**
+     * 获取采集器列表
+     *
+     * @param token   认证令牌
+     * @param plantId 电站ID
+     * @return 采集器列表
+     */
+    @Headers({ "Content-Type: application/json" })
+    @GET("/v1/device/datalogger/list")
+    Call<String> getDatalogList(@Header("token") String token, @Query("plant_id") String plantId,
+        @Query("page") Integer pageNo, @Query("perpage") Integer pageSize);
+
+    /**
+     * 获取电站设备列表
+     *
+     * @param token   认证令牌
+     * @param plantId 电站ID
+     * @return 设备列表
+     */
+    @Headers({ "Content-Type: application/json" })
+    @GET("/v1/device/list")
+    Call<String> getDeviceList(@Header("token") String token, @Query("plant_id") String plantId,
+        @Query("page") Integer pageNo, @Query("perpage") Integer pageSize);
+
+    /**
+     * 获取设备实时数据
+     *
+     * @param token   认证令牌
+     * @param type 类型 16:inverter, 17:SPH, 18:MAX, 19:SPA, 22:MIN
+     * @param devices 设备ID
+     * @return 设备列表
+     */
+    @Headers({ "Content-Type: application/json" })
+    @POST("/v1/device/last/datas")
+    Call<String> getDeviceData(@Header("token") String token, @Query("type") int type,
+        @Query("devices") String devices);
+}

+ 9 - 3
ems/ems-cloud/ems-dev-adapter/src/main/resources/application-local.yml

@@ -57,9 +57,9 @@ mqtt:
 adapter:
   ems:
     url: http://127.0.0.1:9202
-    connectTimeout: 3
-    readTimeout: 5
-    writeTimeout: 5
+    connectTimeout: 300
+    readTimeout: 500
+    writeTimeout: 500
     notifyEnabled: true
   # 安科瑞
   acrel:
@@ -75,6 +75,12 @@ adapter:
     user-name: developer3
     password: dev@admin123
     tenant-id: 1
+  # 古瑞瓦特逆变器-光伏
+  growatt:
+    url: https://openapi-cn.growatt.com
+    token: 3g7gdk3264xfw94jn1f7oox76fln8o3q
+    plantList:
+      - '926492'
   # BA楼控
   ba-ctl:
     url: http://127.0.0.1:8093

+ 9 - 3
ems/ems-cloud/ems-dev-adapter/src/main/resources/application-prod-ct.yml

@@ -57,9 +57,9 @@ mqtt:
 adapter:
   ems:
     url: http://127.0.0.1:9202
-    connectTimeout: 3
-    readTimeout: 5
-    writeTimeout: 5
+    connectTimeout: 300
+    readTimeout: 500
+    writeTimeout: 500
     notifyEnabled: true
   # 安科瑞
   acrel:
@@ -75,6 +75,12 @@ adapter:
     user-name: developer3
     password: dev@admin123
     tenant-id: 1
+  # 古瑞瓦特逆变器-光伏
+  growatt:
+    url: https://openapi-cn.growatt.com
+    token: 3g7gdk3264xfw94jn1f7oox76fln8o3q
+    plantList:
+      - '926492'
   # BA楼控
   ba-ctl:
     url: http://172.17.50.186:80

+ 71 - 0
ems/ems-cloud/ems-dev-adapter/src/test/java/com/huashe/test/GrowattTest.java

@@ -0,0 +1,71 @@
+/*
+ * 文 件 名:  GrowattTest
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/12/16
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.huashe.test;
+
+import com.ruoyi.ems.EmsDevAdpApplication;
+import com.ruoyi.ems.config.GrowattConfig;
+import com.ruoyi.ems.core.GrowattTemplate;
+import com.ruoyi.ems.model.growatt.DataLogger;
+import com.ruoyi.ems.model.growatt.DeviceInfo;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import javax.annotation.Resource;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * GrowattTest
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/12/16]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+@Slf4j
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = EmsDevAdpApplication.class)
+public class GrowattTest {
+    @Resource
+    private GrowattConfig config;
+
+    @Test
+    public void testGetDatalogList() {
+        GrowattTemplate template = new GrowattTemplate(config.getUrl(), config.getToken());
+        List<DataLogger> dataLoggers = template.getDatalogList("926492");
+        log.info("dataLoggers: {}", dataLoggers);
+        Assert.assertNotNull(dataLoggers);
+    }
+
+    @Test
+    public void testGetDeviceList() {
+        GrowattTemplate template = new GrowattTemplate(config.getUrl(), config.getToken());
+        List<DeviceInfo> devices = template.getDeviceList("926492");
+        log.info("devices: {}", devices);
+        Assert.assertNotNull(devices);
+    }
+
+    @Test
+    public void testGetDeviceData() {
+        GrowattTemplate template = new GrowattTemplate(config.getUrl(), config.getToken());
+        String devSn = "GCN4E9503G,GCN4E9503H,THM9E6L00R,THM9E6L00J,GCN5EX9028,GCN5EX9024,GCN5EX900D,GCN5EX900E,GCN5EX902L,VUQ0E7L0BJ,GCN5EX9022,GCN5EX902H,GCN5EX902J,GCN5EX902M,GCN4E95032,GCN5EX900F,ZBK0E9L0QF,GCN5EX902G";
+        String[] devArr = devSn.split(",");
+        Map<String, Object> data = template.getDeviceData(18, Arrays.asList(devArr));
+        log.info("data: {}", data);
+        Assert.assertNotNull(data);
+    }
+}

Разница между файлами не показана из-за своего большого размера
+ 588 - 0
ems/sql/ems_init_data_ctfwq.sql


Некоторые файлы не были показаны из-за большого количества измененных файлов