package com.ruoyi.http.service.impl;
|
|
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSONArray;
|
import com.alibaba.fastjson2.JSONObject;
|
import com.ruoyi.common.utils.http.HttpUtils;
|
import com.ruoyi.http.service.RealTimeEnergyConsumptionService;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.data.redis.core.RedisTemplate;
|
import org.springframework.stereotype.Service;
|
|
import java.util.ArrayList;
|
import java.util.Collections;
|
import java.util.HashMap;
|
import java.util.HashSet;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.Set;
|
import java.util.concurrent.TimeUnit;
|
|
/**
|
* @author :yys
|
* @date : 2026/1/27 16:02
|
*/
|
@Service
|
@Slf4j
|
public class RealTimeEnergyConsumptionServiceImpl implements RealTimeEnergyConsumptionService {
|
|
private static final long REMOTE_CACHE_TTL_SECONDS_30 = 30L;
|
|
private static final String URL = "https://new.e-elitech.cn/api/data-api";
|
|
private static final String TOKEN_URL = "/elitechAccess/getToken";
|
|
private static final String REAL_TIME_URL = "/elitechAccess/v2/getRealTimeData";
|
|
private static final String REAL_HISTORY_URL = URL + "/elitechAccess/v2/getHistoryData";
|
|
private static final String KET_ID = "75804708";
|
|
private static final String KEY_SECRET = "xTUGToozKpYgUPqTsZzB";
|
|
private static final String USER_NAME = "\u7528\u623730773662";
|
|
private static final String PASS_WORD = "y17775163675";
|
|
private static final String REAL_TIME_CACHE_PREFIX = "JCLY:REAL_TIME:";
|
|
private static final String HISTORY_CACHE_PREFIX = "JCLY:HISTORY:";
|
|
private static final String STATUS_KEY = "status";
|
|
private static final String STATUS_MESSAGE_KEY = "statusMessage";
|
|
private static final String STATUS_OK = "ok";
|
|
private static final String STATUS_OFFLINE = "offline";
|
|
private static final String STATUS_ERROR = "error";
|
|
@Autowired
|
private RedisTemplate<String, String> redisTemplate;
|
|
private static JSONObject getProbeParam(JSONArray paramList, String targetCode) {
|
if (paramList == null) {
|
return new JSONObject();
|
}
|
for (int i = 0; i < paramList.size(); i++) {
|
JSONObject paramObj = paramList.getJSONObject(i);
|
if (targetCode.equals(paramObj.getString("paramCode"))) {
|
return paramObj;
|
}
|
}
|
return new JSONObject();
|
}
|
|
public List<Map<String, String>> getHistoryData(String guid, long startTime, long endTime) {
|
List<Map<String, String>> resultList = new ArrayList<>();
|
String token = getToken();
|
try {
|
String historyData = requestHistoryData(token, guid, startTime, endTime);
|
JSONObject resultObj = JSON.parseObject(historyData);
|
if (resultObj == null) {
|
resultList.add(buildStatusItem(guid, STATUS_ERROR, "history response is empty"));
|
return resultList;
|
}
|
|
Integer code = resultObj.getInteger("code");
|
if (!Integer.valueOf(0).equals(code)) {
|
resultList.add(buildStatusItem(guid, resolveStatusByCodeOrMessage(code, resultObj.getString("msg")), resultObj.getString("msg")));
|
return resultList;
|
}
|
|
JSONArray historyList = resultObj.getJSONArray("data");
|
if (historyList == null || historyList.isEmpty()) {
|
resultList.add(buildStatusItem(guid, STATUS_OFFLINE, "no history data"));
|
return resultList;
|
}
|
|
for (int i = 0; i < historyList.size(); i++) {
|
JSONObject historyObj = historyList.getJSONObject(i);
|
Map<String, String> historyItem = new HashMap<>();
|
historyItem.put("guid", firstNonBlank(
|
historyObj.getString("deviceGuid"),
|
historyObj.getString("guid"),
|
guid
|
));
|
historyItem.put("subUId", stringValue(historyObj.get("subUid")));
|
historyItem.put("monitorTimeStamp", stringValue(historyObj.get("monitorTimeStamp")));
|
historyItem.put("monitorTimeStr", historyObj.getString("monitorTimeStr"));
|
historyItem.put("position", historyObj.getString("position"));
|
historyItem.put("address", historyObj.getString("address"));
|
historyItem.put(STATUS_KEY, STATUS_OK);
|
|
JSONArray paramList = historyObj.getJSONArray("data");
|
if (paramList != null && !paramList.isEmpty()) {
|
for (int j = 0; j < paramList.size(); j++) {
|
JSONObject paramObj = paramList.getJSONObject(j);
|
String paramCode = paramObj.getString("paramCode");
|
String value = paramObj.getString("value");
|
String unitCode = paramObj.getString("unitCode");
|
String fullValue = concatValueWithUnit(value, unitCode);
|
if ("0100".equals(paramCode)) {
|
historyItem.put("light", fullValue);
|
} else if ("0110".equals(paramCode)) {
|
historyItem.put("temperature", fullValue);
|
} else if ("0120".equals(paramCode)) {
|
historyItem.put("humidity", fullValue);
|
} else if ("0130".equals(paramCode)) {
|
historyItem.put("co2", fullValue);
|
} else if (paramCode != null) {
|
historyItem.put(paramCode, fullValue);
|
}
|
}
|
}
|
resultList.add(historyItem);
|
}
|
return resultList;
|
} catch (Exception ex) {
|
log.error("history data parse/request failed, guid={}", guid, ex);
|
resultList.add(buildStatusItem(guid, STATUS_ERROR, ex.getMessage()));
|
return resultList;
|
}
|
}
|
|
public List<Map<String, String>> getRealData(List<String> guidList) {
|
log.info("start get real data");
|
List<Map<String, String>> listMaps = new ArrayList<>();
|
if (guidList == null || guidList.isEmpty()) {
|
return listMaps;
|
}
|
|
String token = getToken();
|
try {
|
String realTimeData = getRealTimeData(token, guidList);
|
JSONObject batchResp = JSON.parseObject(realTimeData);
|
Integer code = batchResp == null ? null : batchResp.getInteger("code");
|
if (Integer.valueOf(0).equals(code)) {
|
parseRealDataResponse(batchResp, guidList, listMaps);
|
return listMaps;
|
}
|
log.warn("batch getRealData failed, fallback one by one. code={}, msg={}", code, batchResp == null ? null : batchResp.getString("msg"));
|
} catch (Exception ex) {
|
log.error("batch getRealData exception, fallback one by one", ex);
|
}
|
|
for (String guid : guidList) {
|
listMaps.add(fetchSingleDeviceRealData(token, guid));
|
}
|
return listMaps;
|
}
|
|
public static void main(String[] args) {
|
System.out.println();
|
}
|
|
public String getToken() {
|
String cachedToken = sanitizeToken(redisTemplate.opsForValue().get("JCLY_TOKEN:"));
|
if (cachedToken != null) {
|
return cachedToken;
|
}
|
Map<String, String> param = new HashMap<>();
|
param.put("keyId", KET_ID);
|
param.put("keySecret", KEY_SECRET);
|
param.put("userName", USER_NAME);
|
param.put("password", PASS_WORD);
|
log.info("request token payload: {}", JSON.toJSONString(param));
|
String result = HttpUtils.sendPostJson(URL + TOKEN_URL, JSON.toJSONString(param));
|
log.info("request token response: {}", result);
|
Map<String, Object> map = JSON.parseObject(result, Map.class);
|
if (Integer.valueOf(0).equals(map.get("code"))) {
|
Object token = map.get("data");
|
log.info("token:{}", token);
|
redisTemplate.opsForValue().set("JCLY_TOKEN:", token.toString(), 60 * 60 * 24);
|
return token.toString();
|
}
|
return result;
|
}
|
|
private String sanitizeToken(String token) {
|
if (token == null) {
|
return null;
|
}
|
String cleanedToken = token.replace("\0", "").trim();
|
return cleanedToken.isEmpty() ? null : cleanedToken;
|
}
|
|
private String firstNonBlank(String... values) {
|
for (String value : values) {
|
if (value != null && !value.trim().isEmpty()) {
|
return value;
|
}
|
}
|
return null;
|
}
|
|
private String stringValue(Object value) {
|
return value == null ? null : String.valueOf(value);
|
}
|
|
private String concatValueWithUnit(String value, String unitCode) {
|
if (value == null) {
|
return null;
|
}
|
return value + (unitCode == null ? "" : unitCode);
|
}
|
|
private Map<String, String> buildStatusItem(String guid, String status, String statusMessage) {
|
Map<String, String> result = new HashMap<>();
|
result.put("guid", guid);
|
result.put(STATUS_KEY, status);
|
if (statusMessage != null && !statusMessage.trim().isEmpty()) {
|
result.put(STATUS_MESSAGE_KEY, statusMessage);
|
}
|
return result;
|
}
|
|
private String resolveStatusByCodeOrMessage(Integer code, String message) {
|
if (code != null && (code == 5 || code == 1003 || code == 1004)) {
|
return STATUS_OFFLINE;
|
}
|
if (message == null) {
|
return STATUS_ERROR;
|
}
|
String lowered = message.toLowerCase();
|
if (lowered.contains("offline") || message.contains("离线")) {
|
return STATUS_OFFLINE;
|
}
|
return STATUS_ERROR;
|
}
|
|
private void parseRealDataResponse(JSONObject responseObj, List<String> requestedGuids, List<Map<String, String>> output) {
|
JSONArray deviceList = responseObj.getJSONArray("data");
|
Set<String> returnedGuids = new HashSet<>();
|
if (deviceList != null) {
|
for (int deviceIndex = 0; deviceIndex < deviceList.size(); deviceIndex++) {
|
JSONObject deviceObj = deviceList.getJSONObject(deviceIndex);
|
Map<String, String> deviceData = parseSingleDevice(deviceObj, null);
|
String guid = deviceData.get("guid");
|
if (guid != null) {
|
returnedGuids.add(guid);
|
}
|
output.add(deviceData);
|
}
|
}
|
|
for (String requestGuid : requestedGuids) {
|
if (!returnedGuids.contains(requestGuid)) {
|
output.add(buildStatusItem(requestGuid, STATUS_OFFLINE, "device not returned by remote API"));
|
}
|
}
|
}
|
|
private Map<String, String> fetchSingleDeviceRealData(String token, String guid) {
|
try {
|
String singleResult = getRealTimeData(token, Collections.singletonList(guid));
|
JSONObject singleObj = JSON.parseObject(singleResult);
|
if (singleObj == null) {
|
return buildStatusItem(guid, STATUS_ERROR, "single device response is empty");
|
}
|
Integer code = singleObj.getInteger("code");
|
if (!Integer.valueOf(0).equals(code)) {
|
return buildStatusItem(guid, resolveStatusByCodeOrMessage(code, singleObj.getString("msg")), singleObj.getString("msg"));
|
}
|
|
JSONArray dataList = singleObj.getJSONArray("data");
|
if (dataList == null || dataList.isEmpty()) {
|
return buildStatusItem(guid, STATUS_OFFLINE, "single device response has no data");
|
}
|
return parseSingleDevice(dataList.getJSONObject(0), guid);
|
} catch (Exception ex) {
|
log.error("single getRealData failed, guid={}", guid, ex);
|
return buildStatusItem(guid, STATUS_ERROR, ex.getMessage());
|
}
|
}
|
|
private Map<String, String> parseSingleDevice(JSONObject deviceObj, String fallbackGuid) {
|
String[] targetCodes = {"0100", "0110", "0120", "0130"};
|
Map<String, String> deviceData = new HashMap<>();
|
String deviceGuid = firstNonBlank(
|
deviceObj.getString("deviceGuid"),
|
deviceObj.getString("guid"),
|
deviceObj.getString("devGuid"),
|
deviceObj.getString("sn"),
|
fallbackGuid
|
);
|
if (deviceGuid != null) {
|
deviceData.put("guid", deviceGuid);
|
}
|
|
JSONArray paramList = deviceObj.getJSONArray("data");
|
if (paramList == null || paramList.isEmpty()) {
|
deviceData.put(STATUS_KEY, STATUS_OFFLINE);
|
deviceData.put(STATUS_MESSAGE_KEY, "device data is empty");
|
return deviceData;
|
}
|
|
deviceData.put(STATUS_KEY, STATUS_OK);
|
for (String code : targetCodes) {
|
JSONObject paramObj = getProbeParam(paramList, code);
|
if (paramObj.isEmpty()) {
|
continue;
|
}
|
String value = paramObj.getString("value");
|
String unitCode = paramObj.getString("unitCode");
|
String fullValue = concatValueWithUnit(value, unitCode);
|
if ("0100".equals(code)) {
|
deviceData.put("light", fullValue);
|
} else if ("0110".equals(code)) {
|
deviceData.put("temperature", fullValue);
|
} else if ("0120".equals(code)) {
|
deviceData.put("humidity", fullValue);
|
} else if ("0130".equals(code)) {
|
deviceData.put("co2", fullValue);
|
}
|
}
|
return deviceData;
|
}
|
|
public String getRealTimeData(String token, List<String> guidList) {
|
Map<String, Object> param = new HashMap<>();
|
param.put("keyId", KET_ID);
|
param.put("keySecret", KEY_SECRET);
|
param.put("deviceGuids", guidList);
|
log.info("request realtime payload: {}", JSON.toJSONString(param));
|
String cacheKey = REAL_TIME_CACHE_PREFIX + JSON.toJSONString(param);
|
String cachedResult = sanitizeToken(redisTemplate.opsForValue().get(cacheKey));
|
if (cachedResult != null) {
|
log.info("hit realtime cache: {}", cacheKey);
|
return cachedResult;
|
}
|
String result = HttpUtils.sendPostJson(URL + REAL_TIME_URL, JSON.toJSONString(param), token);
|
log.info("request realtime response: {}", result);
|
cacheRemoteResponse(cacheKey, result);
|
return result;
|
}
|
|
public String requestHistoryData(String token, String guid, long startTime, long endTime) {
|
Map<String, Object> param = new HashMap<>();
|
param.put("keyId", KET_ID);
|
param.put("keySecret", KEY_SECRET);
|
param.put("deviceGuid", guid);
|
param.put("startTime", startTime);
|
param.put("endTime", endTime);
|
log.info("request history payload: {}", JSON.toJSONString(param));
|
String cacheKey = HISTORY_CACHE_PREFIX + JSON.toJSONString(param);
|
String cachedResult = sanitizeToken(redisTemplate.opsForValue().get(cacheKey));
|
if (cachedResult != null) {
|
log.info("hit history cache: {}", cacheKey);
|
return cachedResult;
|
}
|
String result = HttpUtils.sendPostJson(REAL_HISTORY_URL, JSON.toJSONString(param), token);
|
log.info("request history response: {}", result);
|
cacheRemoteResponse(cacheKey, result);
|
return result;
|
}
|
|
private void cacheRemoteResponse(String cacheKey, String result) {
|
if (result == null || result.trim().isEmpty()) {
|
return;
|
}
|
redisTemplate.opsForValue().set(cacheKey, result, REMOTE_CACHE_TTL_SECONDS_30, TimeUnit.SECONDS);
|
}
|
}
|