learshaw 4 днів тому
батько
коміт
d19638eb55
19 змінених файлів з 1900 додано та 1 видалено
  1. 20 0
      ems/ems-cloud/ems-dev-adapter/pom.xml
  2. 37 0
      ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/config/AcrelConfig.java
  3. 399 0
      ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/core/Acrel3000Template.java
  4. 53 0
      ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/core/BaseApiTemplate.java
  5. 170 0
      ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/model/acrel/AlarmEventLog.java
  6. 103 0
      ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/model/acrel/Circuit.java
  7. 31 0
      ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/model/acrel/ConsumeReport.java
  8. 38 0
      ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/model/acrel/EnergyValue.java
  9. 68 0
      ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/model/acrel/MeterKeyValue.java
  10. 136 0
      ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/model/acrel/MeterUse.java
  11. 40 0
      ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/model/acrel/ReportNode.java
  12. 424 0
      ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/model/acrel/Station.java
  13. 35 0
      ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/model/acrel/StationEpiTime.java
  14. 45 0
      ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/model/acrel/StationType.java
  15. 35 0
      ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/model/acrel/Token.java
  16. 127 0
      ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/retrofit/Acrel3000Api.java
  17. 8 1
      ems/ems-cloud/ems-dev-adapter/src/main/resources/application-local.yml
  18. 7 0
      ems/ems-cloud/ems-dev-adapter/src/main/resources/application-prod-ct.yml
  19. 124 0
      ems/ems-cloud/ems-dev-adapter/src/test/java/com/huashe/test/Acrel3000Test.java

+ 20 - 0
ems/ems-cloud/ems-dev-adapter/pom.xml

@@ -49,6 +49,11 @@
             <artifactId>spring-boot-starter-actuator</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+        </dependency>
+
         <!-- Swagger UI -->
         <dependency>
             <groupId>io.springfox</groupId>
@@ -87,6 +92,13 @@
             <version>5.1.2.RELEASE</version>
         </dependency>
 
+        <!-- retrofit -->
+        <dependency>
+            <groupId>com.squareup.retrofit2</groupId>
+            <artifactId>retrofit</artifactId>
+            <version>2.5.0</version>
+        </dependency>
+
         <dependency>
             <groupId>com.huashe.ems</groupId>
             <artifactId>ems-core</artifactId>
@@ -98,6 +110,14 @@
                 </exclusion>
             </exclusions>
         </dependency>
+
+        <!-- 添加JUnit 4依赖 -->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.13.2</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>

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

@@ -0,0 +1,37 @@
+/*
+ * 文 件 名:  AcrelConfig
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/7/21
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.config;
+
+import lombok.Data;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 安科瑞参数
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/7/21]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+@Data
+@Configuration
+public class AcrelConfig {
+    @Value("${adapter.acrel.url}")
+    private String url;
+
+    @Value("${adapter.acrel.auth.loginName}")
+    private String authLoginName;
+
+    @Value("${adapter.acrel.auth.password}")
+    private String authPassword;
+}

+ 399 - 0
ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/core/Acrel3000Template.java

@@ -0,0 +1,399 @@
+/*
+ * 文 件 名:  Acrel3000Template
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/7/19
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+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.huashe.common.utils.DateUtils;
+import com.ruoyi.common.core.utils.SpringUtils;
+import com.ruoyi.common.redis.service.RedisService;
+import com.ruoyi.ems.config.AcrelConfig;
+import com.ruoyi.ems.model.acrel.AlarmEventLog;
+import com.ruoyi.ems.model.acrel.Circuit;
+import com.ruoyi.ems.model.acrel.ConsumeReport;
+import com.ruoyi.ems.model.acrel.MeterKeyValue;
+import com.ruoyi.ems.model.acrel.MeterUse;
+import com.ruoyi.ems.model.acrel.Station;
+import com.ruoyi.ems.model.acrel.Token;
+import com.ruoyi.ems.retrofit.Acrel3000Api;
+import lombok.extern.slf4j.Slf4j;
+import okhttp3.MediaType;
+import okhttp3.OkHttpClient;
+import okhttp3.RequestBody;
+import org.apache.commons.lang3.StringUtils;
+import retrofit2.Call;
+import retrofit2.Response;
+import retrofit2.Retrofit;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 安科瑞3000系列模板类
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/7/19]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+@Slf4j
+public class Acrel3000Template extends BaseApiTemplate {
+    /**
+     * 访问地址
+     */
+    protected String url;
+
+    /**
+     * 调用代理
+     */
+    protected final Acrel3000Api api;
+
+    public Acrel3000Template(String restUrl) {
+        this.url = restUrl;
+
+        OkHttpClient httpClient = getClient();
+        Retrofit retrofit = new Retrofit.Builder().baseUrl(restUrl)
+            .addConverterFactory(Retrofit2ConverterFactory.create()).client(httpClient).build();
+        this.api = retrofit.create(Acrel3000Api.class);
+    }
+
+    /**
+     * 构造调用模板
+     *
+     * @param restUrl        服务地址 (http://ip:port)
+     * @param connectTimeout 连接超时
+     * @param readTimeout    读取超时
+     * @param writeTimeout   写超时
+     */
+    public Acrel3000Template(String restUrl, int connectTimeout, int readTimeout, int writeTimeout) {
+        super.connectTimeout = connectTimeout;
+        super.readTimeout = readTimeout;
+        super.writeTimeout = writeTimeout;
+        this.url = restUrl;
+
+        OkHttpClient httpClient = getClient();
+        Retrofit retrofit = new Retrofit.Builder().baseUrl(restUrl)
+            .addConverterFactory(Retrofit2ConverterFactory.create()).client(httpClient).build();
+        api = retrofit.create(Acrel3000Api.class);
+    }
+
+    public synchronized String getAuthToken() {
+        RedisService redisService = SpringUtils.getBean(RedisService.class);
+        String tokenStr = redisService.getCacheObject("ACREL_AUTH_TOKEN");
+
+        if (StringUtils.isEmpty(tokenStr)) {
+            AcrelConfig config = SpringUtils.getBean(AcrelConfig.class);
+            Token token = getAuthToken(config.getAuthLoginName(), config.getAuthPassword());
+            Assert.notNull(token, -1, "获取权限失败");
+
+            Date expireDate = DateUtils.stringToDate(token.getExpireDate(), "yyyy-MM-dd HH:mm:ss");
+            Date currentDate = new Date();
+            long expireSeconds = (expireDate.getTime() - currentDate.getTime()) / 1000;
+            Assert.isTrue(expireSeconds > 0, -1, "Token已过期或过期时间无效");
+            redisService.setCacheObject("ACREL_AUTH_TOKEN", token.getToken(), expireSeconds, TimeUnit.SECONDS);
+            tokenStr = token.getToken();
+        }
+
+        return tokenStr;
+    }
+
+    /**
+     * 获取权限
+     *
+     * @param loginName 用户名
+     * @param password  密码
+     * @return 响应
+     */
+    public Token getAuthToken(String loginName, String password) {
+        Token token = null;
+
+        try {
+            // 创建请求体
+            RequestBody loginnameBody = RequestBody.create(MediaType.parse("text/plain"), loginName);
+            RequestBody passwordBody = RequestBody.create(MediaType.parse("text/plain"), password);
+
+            // 执行调用
+            Call<String> call = api.getAuthToken(loginnameBody, passwordBody);
+            Response<String> response = call.execute();
+            log.debug("getAuthToken response:{}", response);
+
+            JSONObject resJson = JSONObject.parseObject(response.body());
+            Assert.isTrue(StringUtils.equals(resJson.getString("code"), "200"), resJson.getInteger("code"),
+                resJson.getString("msg"));
+
+            String dataStr = resJson.getString("data");
+            token = JSONObject.parseObject(dataStr, Token.class);
+        }
+        catch (Exception e) {
+            log.error("getAuthToken fail!", e);
+        }
+
+        return token;
+    }
+
+    /**
+     * 获取站点列表
+     *
+     * @param coacCountNo 企业编号(和站点区域分组id不能同时存在)
+     * @param subGroupId  站点区域分组编号(和企业编号不能同时存在)
+     * @return 响应
+     */
+    public List<Station> getStationTreeList(String coacCountNo, String subGroupId) {
+        List<Station> stations = null;
+
+        try {
+            // 动态构建参数字段
+            Map<String, RequestBody> fields = new HashMap<>();
+            fields.put("type", RequestBody.create(MediaType.parse("text/plain"), "0"));
+
+            if (StringUtils.isNotBlank(coacCountNo)) {
+                fields.put("fCoaccountno", RequestBody.create(MediaType.parse("text/plain"), coacCountNo));
+            }
+
+            if (StringUtils.isNotBlank(subGroupId)) {
+                fields.put("fSubgroupid", RequestBody.create(MediaType.parse("text/plain"), subGroupId));
+            }
+
+            // 执行调用
+            Call<String> call = api.getStationTreeList(getAuthToken(), fields);
+            Response<String> response = call.execute();
+            log.debug("getStationTreeList response:{}", response);
+
+            JSONObject resJson = JSONObject.parseObject(response.body());
+            Assert.isTrue(StringUtils.equals(resJson.getString("code"), "200"), resJson.getInteger("code"),
+                resJson.getString("msg"));
+
+            JSONObject dataJson = resJson.getJSONObject("data");
+            int num = dataJson.getInteger("num");
+
+            if (num > 0) {
+                String list = dataJson.getString("list");
+                stations = JSONObject.parseArray(list, Station.class);
+            }
+            else {
+                stations = new ArrayList<>();
+            }
+        }
+        catch (Exception e) {
+            log.error("getStationTreeList fail!", e);
+        }
+
+        return stations;
+    }
+
+    /**
+     * 获取仪表列表
+     *
+     * @param subId 站点ID
+     * @return 响应
+     */
+    public List<MeterUse> getMeterUseInfoList(String subId) {
+        List<MeterUse> list = new ArrayList<>();
+
+        try {
+            int pageNo = 1;
+            int pageSize = 20;
+            int english = 0;
+            boolean isLastPage;
+
+            do {
+                // 执行调用
+                Call<String> call = api.getMeterUseInfoList(getAuthToken(), subId, pageNo, pageSize, english);
+                Response<String> response = call.execute();
+                log.debug("getMeterUseInfoList response:{}", response);
+
+                JSONObject resJson = JSONObject.parseObject(response.body());
+                Assert.isTrue(StringUtils.equals(resJson.getString("code"), "200"), resJson.getInteger("code"),
+                    resJson.getString("msg"));
+
+                JSONObject dataJson = resJson.getJSONObject("data");
+                isLastPage = dataJson.getBoolean("isLastPage");
+                String listStr = dataJson.getString("list");
+                list.addAll(JSONObject.parseArray(listStr, MeterUse.class));
+
+                pageNo++;
+            }
+            while (!isLastPage);
+        }
+        catch (Exception e) {
+            log.error("getMeterUseInfoList fail!", e);
+        }
+
+        return list;
+    }
+
+    /**
+     * 获取回路列表
+     *
+     * @param subId 站点ID
+     * @return 响应
+     */
+    public List<Circuit> getCircuitInfoTree(String subId) {
+        List<Circuit> circuitList = null;
+
+        try {
+            // 执行调用
+            Call<String> call = api.getCircuitInfoTree(getAuthToken(), subId);
+            Response<String> response = call.execute();
+            log.debug("getCircuitInfoTree response:{}", response);
+
+            JSONObject resJson = JSONObject.parseObject(response.body());
+            Assert.isTrue(StringUtils.equals(resJson.getString("code"), "200"), resJson.getInteger("code"),
+                resJson.getString("msg"));
+
+            String dataStr = resJson.getString("data");
+            circuitList = JSONObject.parseArray(dataStr, Circuit.class);
+        }
+        catch (Exception e) {
+            log.error("getCircuitInfoTree fail!", e);
+        }
+
+        return circuitList;
+    }
+
+    /**
+     * 获取实时数据
+     *
+     * @param subId     站点ID
+     * @param meterCode 设备ID
+     * @return 响应
+     */
+    public List<MeterKeyValue> getMeterParamValueByKey(String subId, String meterCode) {
+        List<MeterKeyValue> meterKvList = null;
+
+        try {
+            // 执行调用
+            Call<String> call = api.getMeterParamValueByKey(getAuthToken(), subId, meterCode);
+            Response<String> response = call.execute();
+            log.debug("getMeterParamValueByKey response:{}", response);
+
+            JSONObject resJson = JSONObject.parseObject(response.body());
+            Assert.isTrue(StringUtils.equals(resJson.getString("code"), "200"), resJson.getInteger("code"),
+                resJson.getString("msg"));
+
+            JSONObject dataJson = resJson.getJSONObject("data");
+            Assert.notNull(dataJson, -1, "data is null!");
+
+            String resultStr = dataJson.getString("result");
+            meterKvList = JSONObject.parseArray(resultStr, MeterKeyValue.class);
+        }
+        catch (Exception e) {
+            log.error("getMeterParamValueByKey fail!", e);
+        }
+
+        return meterKvList;
+    }
+
+    /**
+     * 用能集抄
+     *
+     * @param circuitIds 回路ID集合
+     * @param type       类型 min:分, hour: 时, day: 日, mon: 月
+     * @return 响应
+     */
+    public ConsumeReport getNewConsumeReport(String circuitIds, String type, String startTime, String endTime,
+        String interval, String paramCode) {
+        ConsumeReport consumeReport = null;
+
+        try {
+            // 动态构建参数字段
+            Map<String, RequestBody> fields = new HashMap<>();
+            fields.put("fCircuitids", RequestBody.create(MediaType.parse("text/plain"), circuitIds));
+            fields.put("type", RequestBody.create(MediaType.parse("text/plain"), type));
+            fields.put("startTime", RequestBody.create(MediaType.parse("text/plain"), startTime));
+            fields.put("endTime", RequestBody.create(MediaType.parse("text/plain"), endTime));
+            fields.put("interval", RequestBody.create(MediaType.parse("text/plain"), interval));
+            fields.put("paramCode", RequestBody.create(MediaType.parse("text/plain"), paramCode));
+
+            // 执行调用
+            Call<String> call = api.getNewConsumeReport(getAuthToken(), fields);
+            Response<String> response = call.execute();
+            log.debug("getNewConsumeReport response:{}", response);
+
+            JSONObject resJson = JSONObject.parseObject(response.body());
+            Assert.isTrue(StringUtils.equals(resJson.getString("code"), "200"), resJson.getInteger("code"),
+                resJson.getString("msg"));
+
+            String dataStr = resJson.getString("data");
+            consumeReport = JSONObject.parseObject(dataStr, ConsumeReport.class);
+        }
+        catch (Exception e) {
+            log.error("getNewConsumeReport fail!", e);
+        }
+
+        return consumeReport;
+    }
+
+    /**
+     * 获取报警事件列表
+     * @param subId 站点ID
+     * @param startTime 开始时间
+     * @param endTime 结束时间
+     * @return 响应
+     */
+    public List<AlarmEventLog> getAlarmEventLogList(String subId, String startTime, String endTime) {
+        List<AlarmEventLog> list = new ArrayList<>();
+
+        try {
+            int pageNo = 1;
+            int pageSize = 20;
+            boolean isLastPage;
+
+            do {
+                // 动态构建参数字段
+                Map<String, RequestBody> fields = new HashMap<>();
+
+                if (null != subId) {
+                    fields.put("subId", RequestBody.create(MediaType.parse("text/plain"), subId));
+                }
+
+                fields.put("startTime", RequestBody.create(MediaType.parse("text/plain"), startTime));
+                fields.put("endTime", RequestBody.create(MediaType.parse("text/plain"), endTime));
+                fields.put("pageNo", RequestBody.create(MediaType.parse("text/plain"), String.valueOf(pageNo)));
+                fields.put("pageSize", RequestBody.create(MediaType.parse("text/plain"), String.valueOf(pageSize)));
+
+                // 执行调用
+                Call<String> call = api.getAlarmEventLogList(getAuthToken(), fields);
+                Response<String> response = call.execute();
+                log.debug("getAlarmEventLogList response:{}", response);
+
+                JSONObject resJson = JSONObject.parseObject(response.body());
+                Assert.isTrue(StringUtils.equals(resJson.getString("code"), "200"), resJson.getInteger("code"),
+                    resJson.getString("msg"));
+
+                JSONObject dataJson = resJson.getJSONObject("data");
+                Assert.notNull(dataJson, -1, "data is null!");
+                JSONObject alarmJson = dataJson.getJSONObject("alarmEventLogList");
+
+                isLastPage = alarmJson.getBoolean("isLastPage");
+                String listStr = alarmJson.getString("list");
+                List<AlarmEventLog> tmp = JSONObject.parseArray(listStr, AlarmEventLog.class);
+
+                list.addAll(tmp);
+
+                fields.clear();
+                pageNo++;
+            }
+            while (!isLastPage);
+        }
+        catch (Exception e) {
+            log.error("getAlarmEventLogList fail!", e);
+        }
+
+        return list;
+    }
+}

+ 53 - 0
ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/core/BaseApiTemplate.java

@@ -0,0 +1,53 @@
+/*
+ * 文 件 名:  BaseApiTemplate
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/7/19
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.core;
+
+import okhttp3.OkHttpClient;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Api 操作模版基类
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/7/19]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+public class BaseApiTemplate {
+    /**
+     * 连接超时(毫秒)
+     */
+    protected int connectTimeout = 60000;
+
+    /**
+     * 读取超时(毫秒)
+     */
+    protected int readTimeout = 60000;
+
+    /**
+     * 写超时(毫秒)
+     */
+    protected int writeTimeout = 60000;
+
+    /**
+     * 创建连接
+     *
+     * @return 连接
+     */
+    protected OkHttpClient getClient() {
+        OkHttpClient.Builder builder = new OkHttpClient().newBuilder()
+            .connectTimeout(connectTimeout, TimeUnit.MILLISECONDS).readTimeout(readTimeout, TimeUnit.MILLISECONDS)
+            .writeTimeout(writeTimeout, TimeUnit.MILLISECONDS);
+        return builder.build();
+    }
+}

+ 170 - 0
ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/model/acrel/AlarmEventLog.java

@@ -0,0 +1,170 @@
+/*
+ * 文 件 名:  AlarmEventLog
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/7/25
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.model.acrel;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import lombok.Data;
+
+/**
+ * 告警事件日志
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/7/25]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+@Data
+public class AlarmEventLog {
+    /**
+     * 事件id
+     */
+    @JSONField(name = "fAlarmeventlogid")
+    private String alarmEventLogId;
+
+    /**
+     * 站点id
+     */
+    @JSONField(name = "fSubid")
+    private Integer subId;
+
+    /**
+     * 站点名称
+     */
+    @JSONField(name = "fSubname")
+    private String subName;
+
+    /**
+     * 回路id
+     */
+    @JSONField(name = "fCircuitid")
+    private String circuitId;
+
+    /**
+     * fType
+     */
+    @JSONField(name = "fType")
+    private Integer fType;
+
+    /**
+     * 报警类型编码
+     */
+    @JSONField(name = "fMessinfocode")
+    private String messInfoCode;
+
+    /**
+     * 报警类型  2:通讯状态, 3:现场报警 4:设备故障 33:一级报警 35:二级报警 36:三级报警
+     */
+    @JSONField(name = "fMessinfotypeid")
+    private Integer messInfoTypeId;
+
+    /**
+     * 事件类型
+     */
+    @JSONField(name = "fMessInfoExplain")
+    private String messInfoExplain;
+
+    /**
+     * 报警类型详情
+     */
+    @JSONField(name = "fMessInfoTypeExplain")
+    private String messInfoTypeExplain;
+
+    /**
+     * 报警等级详情
+     */
+    @JSONField(name = "fMessinfolevelexplain")
+    private String messInfoLevelExplain;
+
+    /**
+     * 报警等级
+     */
+    @JSONField(name = "fMessinfolevel")
+    private Integer messInfoLevel;
+
+    /**
+     * 设备编号
+     */
+    @JSONField(name = "fDevicecode")
+    private String deviceCode;
+
+    /**
+     * 设备名称
+     */
+    @JSONField(name = "fDevicename")
+    private String deviceName;
+
+    /**
+     * 参数编码(仪表报警有,网关没有)
+     */
+    @JSONField(name = "fParamcode")
+    private String paramCode;
+
+    /**
+     * 参数名称
+     */
+    @JSONField(name = "fParamname")
+    private String paramName;
+
+    /**
+     * 参数对应值说明
+     */
+    @JSONField(name = "fValueType")
+    private String valueType;
+
+    /**
+     * 参数对应值(仪表报警有,网关没有)
+     */
+    @JSONField(name = "fValue")
+    private String value;
+
+    /**
+     * 限制值
+     */
+    @JSONField(name = "fLimitvalue")
+    private String limitValue;
+
+    /**
+     * 报警类型
+     */
+    @JSONField(name = "fAlarmtype")
+    private String alarmType;
+
+    /**
+     * 报警详情
+     */
+    @JSONField(name = "fAlarmdesc")
+    private String alarmDesc;
+
+    /**
+     * 报警时间
+     */
+    @JSONField(name = "fAlarmtime")
+    private String alarmTime;
+
+    /**
+     * 确认状态
+     */
+    @JSONField(name = "fConfirmstatus")
+    private Boolean confirmStatus;
+
+    @JSONField(name = "fCoaccountno")
+    private String coacCountNo;
+
+    @JSONField(name = "fConame")
+    private String coName;
+
+    @JSONField(name = "fContact")
+    private String contacts;
+
+    @JSONField(name = "fContactsPhone")
+    private String contactsPhone;
+}

+ 103 - 0
ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/model/acrel/Circuit.java

@@ -0,0 +1,103 @@
+/*
+ * 文 件 名:  Circuit
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/7/21
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.model.acrel;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 回路信息
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/7/21]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+@Data
+public class Circuit {
+    /**
+     * 站点id
+     */
+    @JSONField(name = "fSubid")
+    private Integer subId;
+
+    /**
+     * 站点名称
+     */
+    @JSONField(name = "fSubname")
+    private String subName;
+
+    /**
+     * 站点名称-英文
+     */
+    @JSONField(name = "fSubnameEn")
+    private String subNameEn;
+
+    /**
+     * 回路id
+     */
+    @JSONField(name = "fCircuitid")
+    private String circuitId;
+
+    /**
+     * 回路名称
+     */
+    @JSONField(name = "fCircuitname")
+    private String circuitName;
+
+    /**
+     * 父级回路id
+     */
+    @JSONField(name = "fParentid")
+    private String parentId;
+
+    /**
+     * 状态
+     */
+    @JSONField(name = "fState")
+    private Integer state;
+
+    /**
+     * 是否进线
+     */
+    @JSONField(name = "fIsincoming")
+    private Boolean inComIng;
+
+    /**
+     * 仪表编号
+     */
+    @JSONField(name = "fMetercode")
+    private String meterCode;
+
+    /**
+     * 排序号
+     */
+    @JSONField(name = "fSortNum")
+    private Integer sortNum;
+
+    /**
+     * 开关状态
+     */
+    @JSONField(name = "fSwitchstatus")
+    private Boolean switchStatus;
+
+    /**
+     * 告警
+     */
+    @JSONField(name = "isAlarm")
+    private Integer alarm;
+
+    @JSONField(name = "children")
+    private List<Circuit> children;
+}

+ 31 - 0
ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/model/acrel/ConsumeReport.java

@@ -0,0 +1,31 @@
+/*
+ * 文 件 名:  ConsumeReport
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/7/23
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.model.acrel;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 自定义集抄对象
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/7/23]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+@Data
+public class ConsumeReport {
+    private List<String> datetimeList;
+
+    private List<ReportNode> energyReport;
+}

+ 38 - 0
ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/model/acrel/EnergyValue.java

@@ -0,0 +1,38 @@
+/*
+ * 文 件 名:  EnergyValue
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/7/23
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.model.acrel;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import lombok.Data;
+
+/**
+ * 抄报读数
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/7/23]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+@Data
+public class EnergyValue {
+    @JSONField(name = "fCollecttime")
+    private String collecttime;
+
+    @JSONField(name = "fOrigValue")
+    private String origValue;
+
+    @JSONField(name = "fConsumeValue")
+    private Double consumeValue;
+
+    @JSONField(name = "fConsumeFee")
+    private Double consumeFee;
+}

+ 68 - 0
ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/model/acrel/MeterKeyValue.java

@@ -0,0 +1,68 @@
+/*
+ * 文 件 名:  MeterKeyValue
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/7/23
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.model.acrel;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import lombok.Data;
+
+/**
+ * 计量返回键值对
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/7/23]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+@Data
+public class MeterKeyValue {
+    /**
+     * 站点ID
+     */
+    @JSONField(name = "fSubid")
+    private Integer subId;
+
+    /**
+     * 仪表编码
+     */
+    @JSONField(name = "fMetercode")
+    private String meterCode;
+
+    /**
+     * 仪表名称
+     */
+    @JSONField(name = "fMetername")
+    private String meterName;
+
+    /**
+     * 参数
+     */
+    @JSONField(name = "fParamcode")
+    private String paramCode;
+
+    /**
+     * 参数名称
+     */
+    @JSONField(name = "fParamname")
+    private String paramName;
+
+    /**
+     * 值
+     */
+    @JSONField(name = "fValue")
+    private String value;
+
+    /**
+     * 值单位
+     */
+    @JSONField(name = "fUnitCode")
+    private String unitCode;
+}

+ 136 - 0
ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/model/acrel/MeterUse.java

@@ -0,0 +1,136 @@
+/*
+ * 文 件 名:  MeterUse
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/7/21
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.model.acrel;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import lombok.Data;
+
+/**
+ * 计量装置
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/7/21]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+@Data
+public class MeterUse {
+    /**
+     * 仪表编号
+     */
+    @JSONField(name = "fMetercode")
+    private String meterCode;
+
+    /**
+     * 站点id
+     */
+    @JSONField(name = "fSubid")
+    private String subId;
+
+    /**
+     * 站点英文名称
+     */
+    @JSONField(name = "fSubnameEN")
+    private String subNameEn;
+
+    /**
+     * 站点名称
+     */
+    @JSONField(name = "fSubname")
+    private String subName;
+
+    /**
+     * 网关id
+     */
+    @JSONField(name = "fGatewayid")
+    private String gatewayId;
+
+    /**
+     * 仪表名称
+     */
+    @JSONField(name = "fMetername")
+    private String meterName;
+
+    /**
+     * 串口号
+     */
+    @JSONField(name = "fSerialport")
+    private String serialPort;
+
+    /**
+     * 仪表地址
+     */
+    @JSONField(name = "fMeteraddr")
+    private String meterAddr;
+
+    /**
+     * 是否离线
+     */
+    @JSONField(name = "fIsdisconnnect")
+    private Boolean disConnect;
+
+    /**
+     * 仪表类型编号
+     */
+    @JSONField(name = "fMetertypecode")
+    private String meterTypeCode;
+
+    /**
+     * 仪表状态编号
+     * </br>1:使用 0:不使用
+     */
+    @JSONField(name = "fState")
+    private Integer state;
+
+    /**
+     * 仪表状态
+     */
+    @JSONField(name = "fStateExplain")
+    private String stateExplain;
+
+    /**
+     * 能源类型
+     * 0:电 1:水 2:气
+     */
+    @JSONField(name = "fEnergyType")
+    private Integer energyType;
+
+    /**
+     * 仪表类型名称
+     */
+    @JSONField(name = "fMetertypename")
+    private String fMetertypename;
+
+    /**
+     * 第三方仪表是否存在
+     */
+    @JSONField(name = "thirdpartyState")
+    private Integer thirdPartyState;
+
+    /**
+     * IOT设备是否存在
+     */
+    @JSONField(name = "outfireState")
+    private Integer outFireState;
+
+    /**
+     * 是否虚拟表
+     */
+    @JSONField(name = "fIsreal")
+    private Boolean real;
+
+    /**
+     * 仪表型号
+     */
+    @JSONField(name = "fModelName")
+    private String fModelName;
+}

+ 40 - 0
ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/model/acrel/ReportNode.java

@@ -0,0 +1,40 @@
+/*
+ * 文 件 名:  ReportNode
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/7/23
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.model.acrel;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 抄报对象
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/7/23]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+@Data
+public class ReportNode {
+    @JSONField(name = "fCircuitid")
+    private String circuitId;
+
+    @JSONField(name = "fCircuitname")
+    private String circuitName;
+
+    @JSONField(name = "fIsincoming")
+    private Boolean fIsincoming;
+
+    @JSONField(name = "origEnergyValues")
+    private List<EnergyValue> origEnergyValues;
+}

+ 424 - 0
ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/model/acrel/Station.java

@@ -0,0 +1,424 @@
+/*
+ * 文 件 名:  Station
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/7/21
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.model.acrel;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 站点信息
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/7/21]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+@Data
+public class Station {
+    /**
+     * 站点编号
+     */
+    @JSONField(name = "fSubid")
+    private Long subId;
+
+    /**
+     * 站点区域分组编号
+     */
+    @JSONField(name = "fSubgroupid")
+    private Long subgroupId;
+
+    /**
+     * 站点区域分组名称
+     */
+    @JSONField(name = "fSubgroupName")
+    private String subGroupName;
+
+    /**
+     * 站点区域分组名称英文
+     */
+    @JSONField(name = "fSubgroupNameen")
+    private String subGroupNameEn;
+
+    /**
+     * 父站点编号
+     */
+    @JSONField(name = "fParentid")
+    private Long parentId;
+
+    /**
+     * 父级站点名称
+     */
+    @JSONField(name = "fParentname")
+    private String parentName;
+
+    /**
+     * 父级站点英文名称
+     */
+    @JSONField(name = "fParentnameen")
+    private String parentNameEn;
+
+    /**
+     * 站点名称
+     */
+    @JSONField(name = "fSubname")
+    private String subName;
+
+    /**
+     * 站点简称
+     */
+    @JSONField(name = "fSubshort")
+    private String subShort;
+
+    /**
+     * 站点图片地址
+     */
+    @JSONField(name = "substationImg")
+    private String substationImg;
+
+    /**
+     * 3d的url地址
+     */
+    @JSONField(name = "f3durl")
+    private String url3d;
+
+    /**
+     * 站点地址
+     */
+    @JSONField(name = "fAddress")
+    private String address;
+
+    /**
+     * 经度
+     */
+    @JSONField(name = "fLongitude")
+    private Double longitude;
+
+    /**
+     * 纬度
+     */
+    @JSONField(name = "fLatitude")
+    private Double latitude;
+
+    /**
+     * 企业编号
+     */
+    @JSONField(name = "fCoaccountno")
+    private String coAccountNo;
+
+    /**
+     * 企业名称
+     */
+    @JSONField(name = "fConame")
+    private String coName;
+
+    /**
+     * 企业名称英文
+     */
+    @JSONField(name = "fConameen")
+    private String coNameEn;
+
+    /**
+     * 价格类型
+     * 1:单电价,2:尖峰平谷电价
+     */
+    @JSONField(name = "priceType")
+    private String priceType;
+
+    /**
+     * 折扣
+     */
+    @JSONField(name = "rate")
+    private String rate;
+
+    /**
+     * 平时间段
+     */
+    @JSONField(name = "fEpiptime")
+    private String epiPTime;
+
+    /**
+     * 峰时间段
+     */
+    @JSONField(name = "fEpiftime")
+    private String epiFTime;
+
+    /**
+     * 谷时间段
+     */
+    @JSONField(name = "fEpigtime")
+    private String epiGTime;
+
+    /**
+     * 尖时间段
+     */
+    @JSONField(name = "fEpigtime")
+    private String epiJTime;
+
+    /**
+     * 平时段电价
+     */
+    @JSONField(name = "f_EpiPPrice")
+    private String epiPPrice;
+
+    /**
+     * 峰时段电价
+     */
+    @JSONField(name = "f_EpiFPrice")
+    private String epiFPrice;
+
+    /**
+     * 谷时段电价
+     */
+    @JSONField(name = "f_EpiGPrice")
+    private String epiGPrice;
+
+    /**
+     * 尖时段电价
+     */
+    @JSONField(name = "f_EpiJPrice")
+    private String epiJPrice;
+
+    /**
+     * 单一电价
+     */
+    @JSONField(name = "f_EpiSinglePrice")
+    private String epiSinglePrice;
+
+    /**
+     * 电价-5
+     */
+    @JSONField(name = "f_Epi5Price")
+    private String epi5Price;
+
+    /**
+     * 电价-6
+     */
+    @JSONField(name = "f_Epi6Price")
+    private String epi6Price;
+
+    /**
+     * 电价-8
+     */
+    @JSONField(name = "f_Epi8Price")
+    private String epi8Price;
+
+    /**
+     * 装机容量
+     */
+    @JSONField(name = "installEdcapacity")
+    private Integer installEdcApacity;
+
+    /**
+     * 电压等级
+     */
+    @JSONField(name = "fVoltagestep")
+    private Double voltageStep;
+
+    /**
+     * 变电电压
+     */
+    @JSONField(name = "fVoltageoftrans")
+    private String voltageOfTrans;
+
+    /**
+     * 站点类型
+     * <br/>0:变配电站,1:光伏电站,2:供水站,3:供气站,4:供冷站,5:供热站,6:储能站,7:风电站,8:瓦斯发电站
+     */
+    @JSONField(name = "fType")
+    private Integer fType;
+
+    /**
+     * 巡检配置
+     * <br/>2:启用自定义,3:启用停用配置
+     */
+    @JSONField(name = "fConfigtypeid")
+    private Integer configTypeId;
+
+    /**
+     * 视界直播
+     */
+    @JSONField(name = "fVisionlive")
+    private String visionLive;
+
+    /**
+     * 是否计量标志
+     */
+    @JSONField(name = "fIscount")
+    private Boolean count;
+
+    /**
+     * 变压器数量
+     */
+    @JSONField(name = "fTransformernum")
+    private Integer transformerNum;
+
+    /**
+     * 门禁
+     */
+    @JSONField(name = "fDoor")
+    private Boolean door;
+
+    /**
+     * 申报容量
+     */
+    @JSONField(name = "fApplycapacity")
+    private Integer applyCapacity;
+
+    /**
+     * 储能装机容量
+     */
+    @JSONField(name = "fStorageInstalledCapacity")
+    private String storageInstalledCapacity;
+
+    /**
+     * 电池类型
+     * <br/>0:锂电池,1:液流电池
+     */
+    @JSONField(name = "fBatteryType")
+    private String batteryType;
+
+    /**
+     * 补贴截止日期
+     */
+    @JSONField(name = "fSubsidyendtime")
+    private String subsidyEndTime;
+
+    /**
+     * 补贴电价
+     */
+    @JSONField(name = "fSubsidyprice")
+    private String subsidyPrice;
+
+    /**
+     * 二氧化碳
+     */
+    @JSONField(name = "fCo2")
+    private String co2;
+
+    /**
+     * 标准煤
+     */
+    @JSONField(name = "fFml")
+    private String ml;
+
+    /**
+     * STS开关检测功能
+     * <br/>0:关,1:开
+     */
+    @JSONField(name = "fSTS")
+    private Integer sts;
+
+    /**
+     * 报警手机号
+     */
+    @JSONField(name = "fPhoneofalarm")
+    private String phoneOfAlarm;
+
+    /**
+     * 联系人
+     */
+    @JSONField(name = "fContacts")
+    private String contacts;
+
+    /**
+     * 联系人电话
+     */
+    @JSONField(name = "fContactsPhone")
+    private String contactsPhone;
+
+    /**
+     * 默认负责人
+     */
+    @JSONField(name = "fDefaultcharger")
+    private String defaultCharger;
+
+    /**
+     * 默认执行人
+     */
+    @JSONField(name = "fDefaultexecutor")
+    private String defaultExecutor;
+
+    /**
+     * 运行状态手机号
+     */
+    @JSONField(name = "fPhoneofoperation")
+    private String phoneOfOperation;
+
+    /**
+     * 第三方用户平台
+     */
+    @JSONField(name = "f_PartnerSubNo")
+    private String partnerSubNo;
+
+    /**
+     * 水浸
+     */
+    @JSONField(name = "fWaterin")
+    private Boolean waterIn;
+
+    /**
+     * 烟雾
+     */
+    @JSONField(name = "fSmog")
+    private Boolean smog;
+
+    /**
+     * 温湿度表
+     */
+    @JSONField(name = "fTHMeter")
+    private String thMeter;
+
+    /**
+     * 投运时间
+     */
+    @JSONField(name = "fOperatetime")
+    private Long operateTime;
+
+    /**
+     * 光伏站点计算类型
+     * <br/>1:纯并网,2:余电上网
+     */
+    @JSONField(name = "energyType")
+    private String energyType;
+
+    /**
+     * 建造商
+     */
+    @JSONField(name = "fBuilder")
+    private String builder;
+
+    /**
+     * 并网电压
+     */
+    @JSONField(name = "fGridvoltage")
+    private String fGridvoltage;
+
+    /**
+     * 站点类型信息
+     */
+    @JSONField(name = "type")
+    private StationType type;
+
+    /**
+     * 时段电价信息
+     */
+    @JSONField(name = "fEpitimelist")
+    private List<StationEpiTime> epiTimeList;
+
+    /**
+     * 子站点信息
+     */
+    @JSONField(name = "children")
+    private List<Station> children;
+}

+ 35 - 0
ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/model/acrel/StationEpiTime.java

@@ -0,0 +1,35 @@
+/*
+ * 文 件 名:  StationEpitime
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/7/21
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.model.acrel;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import lombok.Data;
+
+/**
+ * 时段电价
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/7/21]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+@Data
+public class StationEpiTime {
+    @JSONField(name = "fSubid")
+    private Integer fSubId;
+
+    @JSONField(name = "fType")
+    private Integer fType;
+
+    @JSONField(name = "fEpitime")
+    private String fEpiTime;
+}

+ 45 - 0
ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/model/acrel/StationType.java

@@ -0,0 +1,45 @@
+/*
+ * 文 件 名:  StationType
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/7/21
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.model.acrel;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import lombok.Data;
+
+/**
+ * 站点类型信息
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/7/21]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+@Data
+public class StationType {
+    /**
+     * 站点类型英文名称
+     */
+    @JSONField(name = "fStationtypenameen")
+    private String fStationTypeNameEn;
+
+    /**
+     * 站点类型名称
+     */
+    @JSONField(name = "fStationtypename")
+    private String fStationTypeName;
+
+    /**
+     * 站点类型编码
+     * <br/>0:变配电站,1:光伏电站,2:供水站,3:供气站,4:供冷站,5:供热站,6:储能站,7:风电站,8:瓦斯发电站
+     */
+    @JSONField(name = "fStationtypecode")
+    private String fStationTypeCode;
+}

+ 35 - 0
ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/model/acrel/Token.java

@@ -0,0 +1,35 @@
+/*
+ * 文 件 名:  TokenRes
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/7/21
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.model.acrel;
+
+import lombok.Data;
+
+/**
+ * Token对象
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/7/21]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+@Data
+public class Token {
+    /**
+     * 过期时间
+     */
+    private String expireDate;
+
+    /**
+     * token
+     */
+    private String token;
+}

+ 127 - 0
ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/retrofit/Acrel3000Api.java

@@ -0,0 +1,127 @@
+/*
+ * 文 件 名:  Acrel3000WebApi
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/7/19
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.retrofit;
+
+import okhttp3.RequestBody;
+import retrofit2.Call;
+import retrofit2.http.GET;
+import retrofit2.http.Header;
+import retrofit2.http.Headers;
+import retrofit2.http.Multipart;
+import retrofit2.http.POST;
+import retrofit2.http.Part;
+import retrofit2.http.PartMap;
+import retrofit2.http.Query;
+
+import java.util.Map;
+
+/**
+ * 安科瑞 3000 系列 WEB API
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/7/19]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+public interface Acrel3000Api {
+    /**
+     * 获取权限
+     *
+     * @param loginName 用户名
+     * @param password  密码
+     * @return 权限信息
+     */
+    @Multipart
+    @Headers({ "Projecttype: 1", "Api-Version: 2.0.0" })
+    @POST("/SubstationWEBV2/user/getAuthToken")
+    Call<String> getAuthToken(@Part("fLoginname") RequestBody loginName, @Part("fPassword") RequestBody password);
+
+    /**
+     * 获取站点树结构
+     *
+     * @param authorization 用户名
+     * @param fields        参数
+     * @return 站点信息
+     */
+    @Multipart
+    @Headers({ "Projecttype: 1", "Api-Version: 2.0.0" })
+    @POST("/SubstationWEBV2/main/getStationTreeList")
+    Call<String> getStationTreeList(@Header("Authorization") String authorization,
+        @PartMap Map<String, RequestBody> fields);
+
+    /**
+     * 获取仪表
+     *
+     * @param authorization 用户名
+     * @param subId         站点ID
+     * @param pageNo        页码
+     * @param pageSize      每页数量
+     * @param english       是否英文
+     * @return 仪表信息
+     */
+    @Headers({ "Projecttype: 1", "Api-Version: 2.0.0" })
+    @GET("/SubstationWEBV2/sys/getMeterUseInfoList")
+    Call<String> getMeterUseInfoList(@Header("Authorization") String authorization, @Query("fSubId") String subId,
+        @Query("pageNo") int pageNo, @Query("pageSize") int pageSize, @Query("english") int english);
+
+    /**
+     * 获取回路
+     *
+     * @param authorization 用户名
+     * @param subId         站点ID
+     * @return 回路信息
+     */
+    @Headers({ "Projecttype: 1", "Api-Version: 2.0.0" })
+    @GET("/SubstationWEBV2/sys/getCircuitInfoTree")
+    Call<String> getCircuitInfoTree(@Header("Authorization") String authorization, @Query("fSubId") String subId);
+
+    /**
+     * 获取回路
+     *
+     * @param authorization 用户名
+     * @param subId         站点ID
+     * @param meterCode     表计编号
+     * @
+     * @return 回路信息
+     */
+    @Headers({ "Projecttype: 1", "Api-Version: 2.0.0" })
+    @GET("/SubstationWEBV2/main/getMeterParamValueByKey")
+    Call<String> getMeterParamValueByKey(@Header("Authorization") String authorization, @Query("fSubId") String subId,
+        @Query("fMetercode") String meterCode);
+
+
+    /**
+     * 用能集抄
+     *
+     * @param authorization 用户名
+     * @param fields        参数
+     * @return 站点信息
+     */
+    @Multipart
+    @Headers({ "Projecttype: 1", "Api-Version: 2.0.0" })
+    @POST("/SubstationWEBV2/main/getNewConsumeReport")
+    Call<String> getNewConsumeReport(@Header("Authorization") String authorization,
+        @PartMap Map<String, RequestBody> fields);
+
+    /**
+     * 报警信息
+     *
+     * @param authorization 用户名
+     * @param fields        参数
+     * @return 站点信息
+     */
+    @Multipart
+    @Headers({ "Projecttype: 1", "Api-Version: 2.0.0" })
+    @POST("/SubstationWEBV2/main/getAlarmEventLogList")
+    Call<String> getAlarmEventLogList(@Header("Authorization") String authorization,
+        @PartMap Map<String, RequestBody> fields);
+}

+ 8 - 1
ems/ems-cloud/ems-dev-adapter/src/main/resources/application-local.yml

@@ -46,7 +46,7 @@ spring:
 mqtt:
   server:
     host: tcp://xt.wenhq.top:8581
-    client_id: ems-dev-adapter
+    client_id: ems-dev-adapter1
   executor:
     msgHandle:
       corePoolSize: 20
@@ -54,6 +54,13 @@ mqtt:
       queueCapacity: 2000
       namePrefix: 'mqttHandle-'
 
+adapter:
+  acrel:
+    url: http://116.236.149.165:8092
+    auth:
+      loginName: guest
+      password: 123456
+
 # mybatis配置
 mybatis:
   # 搜索指定包别名

+ 7 - 0
ems/ems-cloud/ems-dev-adapter/src/main/resources/application-prod-ct.yml

@@ -54,6 +54,13 @@ mqtt:
       queueCapacity: 2000
       namePrefix: 'mqttHandle-'
 
+adapter:
+  acrel:
+    url: http://172.61.55.66:8092
+    auth:
+      loginName: guest
+      password: 123456
+
 # mybatis配置
 mybatis:
   # 搜索指定包别名

+ 124 - 0
ems/ems-cloud/ems-dev-adapter/src/test/java/com/huashe/test/Acrel3000Test.java

@@ -0,0 +1,124 @@
+/*
+ * 文 件 名:  AmapCongestTest
+ * 版    权:
+ * 描    述:  <描述>
+ * 修 改 人:  learshaw
+ * 修改时间:  2022/3/28
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.huashe.test;
+
+import com.huashe.common.utils.DateUtils;
+import com.ruoyi.common.redis.service.RedisService;
+import com.ruoyi.ems.EmsDevAdpApplication;
+import com.ruoyi.ems.config.AcrelConfig;
+import com.ruoyi.ems.core.Acrel3000Template;
+import com.ruoyi.ems.model.acrel.AlarmEventLog;
+import com.ruoyi.ems.model.acrel.Circuit;
+import com.ruoyi.ems.model.acrel.ConsumeReport;
+import com.ruoyi.ems.model.acrel.MeterKeyValue;
+import com.ruoyi.ems.model.acrel.MeterUse;
+import com.ruoyi.ems.model.acrel.Station;
+import com.ruoyi.ems.model.acrel.Token;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.Assert;
+import org.junit.Before;
+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.Date;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 高德 - 拥堵接口测试
+ * <功能详细描述>
+ *
+ * @author learshaw
+ * @version [版本号, 2022/3/28]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+@Slf4j
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = EmsDevAdpApplication.class)
+public class Acrel3000Test {
+
+    @Resource
+    private AcrelConfig config;
+
+    @Resource
+    private RedisService redisService;
+
+    /**
+     * 测试-获取权限
+     */
+    @Before
+    public void testGetAuthToken() {
+        Acrel3000Template template = new Acrel3000Template(config.getUrl());
+        Token token = template.getAuthToken(config.getAuthLoginName(), config.getAuthPassword());
+        Assert.assertNotNull(token);
+        log.info("Token: {}\nexpireDate: {}", token.getToken(), token.getExpireDate());
+
+        Date expireDate = DateUtils.stringToDate(token.getExpireDate(), "yyyy-MM-dd HH:mm:ss");
+        Date currentDate = new Date();
+        long expireSeconds = (expireDate.getTime() - currentDate.getTime()) / 1000;
+        com.huashe.common.exception.Assert.isTrue(expireSeconds > 0, -1, "Token已过期或过期时间无效");
+        redisService.setCacheObject("ACREL_AUTH_TOKEN", token.getToken(), expireSeconds, TimeUnit.SECONDS);
+    }
+
+    @Test
+    public void testGetStationTreeList() {
+        Acrel3000Template template = new Acrel3000Template(config.getUrl());
+        List<Station> stationList = template.getStationTreeList("1", null);
+        log.info("stationList: {}", stationList);
+        Assert.assertNotNull(stationList);
+    }
+
+    @Test
+    public void testGetMeterUseInfoList() {
+        Acrel3000Template template = new Acrel3000Template(config.getUrl());
+        List<MeterUse> meterUseList = template.getMeterUseInfoList("10100002");
+        log.info("meterUseList: {}", meterUseList);
+        Assert.assertNotNull(meterUseList);
+    }
+
+    @Test
+    public void testGetCircuitInfoTree() {
+        Acrel3000Template template = new Acrel3000Template(config.getUrl());
+        List<Circuit> circuitList = template.getCircuitInfoTree("10100002");
+        log.info("circuitList: {}", circuitList);
+        Assert.assertNotNull(circuitList);
+    }
+
+    @Test
+    public void testGetMeterParamValueByKey() {
+        Acrel3000Template template = new Acrel3000Template(config.getUrl());
+        List<MeterKeyValue> meterKeyValueList = template.getMeterParamValueByKey("10100001", "T201019");
+        log.info("MeterKeyValueList: {}", meterKeyValueList);
+        Assert.assertNotNull(meterKeyValueList);
+    }
+
+    @Test
+    public void testGetNewConsumeReport() {
+        Acrel3000Template template = new Acrel3000Template(config.getUrl());
+        ConsumeReport consumeReport = template.getNewConsumeReport("10100001001", "min", "2025-07-01 00:00:00",
+            "2025-07-20 00:00:00", "24", "EPI");
+        log.info("consumeReport: {}", consumeReport);
+        Assert.assertNotNull(consumeReport);
+    }
+
+    @Test
+    public void testGetAlarmEventLogList() {
+        Acrel3000Template template = new Acrel3000Template(config.getUrl());
+        List<AlarmEventLog> list = template.getAlarmEventLogList("10100001001", "2025-07-01 00:00:00",
+            "2025-07-20 00:00:00");
+        log.info("eventLogList: {}", list);
+        Assert.assertNotNull(list);
+    }
+}