package com.doumee.core.device; import cn.emay.sdk.util.StringUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.TypeReference; import com.doumee.core.device.model.*; import com.doumee.core.device.model.request.*; import com.doumee.core.device.model.response.*; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.HttpClient; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClients; import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.EntityUtils; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.util.*; @Slf4j public class ElectronicToolUtil { /** * 电表添加采集器 */ public static ElectronicBaseResponse collectorAdd(List param){ if(param ==null || param.size()==0){ return null; } String url = ElectronicConstant.api2_url+"/Api_v2/collector/add"; try { String request_content = JSON.toJSONString(param); String r = request(url, request_content); TypeReference typeReference = new TypeReference< ElectronicBaseResponse> >(){}; ElectronicBaseResponse result = JSONObject.parseObject(r, typeReference.getType()); return result; }catch (Exception e){ log.error("电表==============添加采集器",e); } return null; } /** * 删除采集器 */ public static ElectronicBaseResponse collectorDelete(List param){ if(param ==null || param.size()==0){ return null; } String url = ElectronicConstant.api2_url+"/Api_v2/collector/delete"; try { String request_content = JSON.toJSONString(param); String r = request(url, request_content); TypeReference typeReference = new TypeReference< ElectronicBaseResponse> >(){}; ElectronicBaseResponse result = JSONObject.parseObject(r, typeReference.getType()); return result; }catch (Exception e){ log.error("电表==============删除采集器",e); } return null; } /** * 更新采集器 */ public static ElectronicBaseResponse collectorUpdate(List param){ if(param ==null || param.size()==0){ return null; } String url = ElectronicConstant.api2_url+"/Api_v2/collector/renew"; try { String request_content = JSON.toJSONString(param); String r = request(url, request_content); TypeReference typeReference = new TypeReference< ElectronicBaseResponse> >(){}; ElectronicBaseResponse result = JSONObject.parseObject(r, typeReference.getType()); return result; }catch (Exception e){ log.error("电表==============更新采集器",e); } return null; } /** * 电能表添加 */ public static ElectronicBaseResponse eleMeterAdd(List param) { if(param ==null || param.size()==0){ return null; } String url = ElectronicConstant.api2_url+"/Api_v2/ele_meter/add"; try { String request_content = JSON.toJSONString(param); String r = request(url, request_content); TypeReference typeReference = new TypeReference< ElectronicBaseResponse> >(){}; ElectronicBaseResponse result = JSONObject.parseObject(r, typeReference.getType()); return result; }catch (Exception e){ log.error("电表==============新增电表",e); } return null; } /** * 电能表更新 */ public static ElectronicBaseResponse eleMeterUpdate(List param) { if(param ==null || param.size()==0){ return null; } String url = ElectronicConstant.api2_url+"/Api_v2/ele_meter/renew"; try { String request_content = JSON.toJSONString(param); String r = request(url, request_content); TypeReference typeReference = new TypeReference< ElectronicBaseResponse> >(){}; ElectronicBaseResponse result = JSONObject.parseObject(r, typeReference.getType()); return result; }catch (Exception e){ log.error("电表==============新增电表",e); } return null; } /** * 电能表删除 */ public static ElectronicBaseResponse eleMeterDelete(List param) { if(param ==null || param.size()==0){ return null; } String url = ElectronicConstant.api2_url+"/Api_v2/ele_meter/delete"; try { String request_content = JSON.toJSONString(param); String r = request(url, request_content); TypeReference typeReference = new TypeReference< ElectronicBaseResponse> >(){}; ElectronicBaseResponse result = JSONObject.parseObject(r, typeReference.getType()); return result; }catch (Exception e){ log.error("电表==============删除电表",e); } return null; } public static void main(String[] args) { QueryDataRequest param = new QueryDataRequest(); param.setStart_time("2026-05-25 10:00::00"); param.setEnd_time("2026-05-25 14:24:25"); param.setLimit(1); param.setFunctionids("253"); param.setOffset(0); queryDataRequest(param ); } /** * 电表开户_表清零 * 电表清零接口用于电表的清零操作,切换付费模式,通过该接口可以将电表的计量数据,余额清零,使得电表的计量数据重新从0开始。 * 注意 预付费电表 清零时会 拉闸 * 新预付费表开始启用时都要进行清零、开户、充值 */ public static ElectronicBaseResponse eleSecurityReset(List param) { if(param ==null || param.size()==0){ return null; } String url = ElectronicConstant.api2_url+"/Api_v2/ele_security/reset"; try { String request_content = JSON.toJSONString(param); String r = requestAsync(url, request_content); return parseAsyncMeterResponse(r); }catch (Exception e){ log.error("电表==============开户",e); } return null; } /** * 电表开户_同步模式m */ public static ElectronicBaseResponse openAcount(List param) { if(param ==null || param.size()==0){ return null; } String url = ElectronicConstant.api2_url+"/Api_v2/ele_security/open_acount"; try { String request_content = JSON.toJSONString(param); String r = requestAsync(url, request_content); return parseAsyncMeterResponse(r); }catch (Exception e){ log.error("电表==============开户",e); } return null; } /** * 电表_电表充值 */ public static ElectronicBaseResponse recharger(List param) { if(param ==null || param.size()==0){ return null; } String url = ElectronicConstant.api2_url+"/Api_v2/ele_security/recharge"; try { String request_content = JSON.toJSONString(param); String r = requestAsync(url, request_content); return parseAsyncMeterResponse(r); }catch (Exception e){ log.error("电表==============充值",e); } return null; } /** * 电表_拉合闸 */ public static ElectronicBaseResponse eleControl(List param) { if(param ==null || param.size()==0){ return null; } String url = ElectronicConstant.api2_url+"/Api_v2/ele_control"; try { String request_content = JSON.toJSONString(param); String r = requestAsync(url, request_content); return parseAsyncMeterResponse(r); }catch (Exception e){ log.error("电表==============拉合闸",e); } return null; } /** * 查询异步操作任务状态(/Api_v2/request/status)。 * request_content 为 JSON 数组,可合并传入多个 opr_id 一次查询。 * 调用成功后建议 30s 首次查询,后续间隔递增(1h、2h、4h…),禁止频繁调用。 * 响应 SUCCESS、FAIL、TIMEOUT、CANCELED、RESPONSE_FAIL 后无需再查询。 */ public static ElectronicBaseResponse requestStatus(List param) { if (param == null || param.isEmpty()) { return null; } String url = ElectronicConstant.api2_url + "/Api_v2/request/status"; try { String request_content = JSON.toJSONString(param); String r = request(url, request_content); return parseAsyncMeterResponse(r); } catch (Exception e) { log.error("电表==============查询异步任务状态", e); } return null; } /** * 按 opr_id 列表合并查询异步任务状态。 */ public static ElectronicBaseResponse requestStatusByOprIds(List oprIds) { if (oprIds == null || oprIds.isEmpty()) { return null; } List param = new ArrayList<>(); for (String oprId : oprIds) { if (StringUtils.isNotBlank(oprId)) { RequestStatusRequest req = new RequestStatusRequest(); req.setOpr_id(oprId.trim()); param.add(req); } } return param.isEmpty() ? null : requestStatus(param); } /** * 查询单个异步操作任务状态。 */ public static ElectronicBaseResponse requestStatus(String oprId) { if (StringUtils.isBlank(oprId)) { return null; } RequestStatusRequest req = new RequestStatusRequest(); req.setOpr_id(oprId.trim()); return requestStatus(Collections.singletonList(req)); } /** * 异步任务是否已到达终态,平台后续不再处理,无需再轮询。 */ public static boolean isAsyncStatusFinal(String status) { if (StringUtils.isBlank(status)) { return false; } String s = status.trim().toUpperCase(Locale.ROOT); return "SUCCESS".equals(s) || "FAIL".equals(s) || "TIMEOUT".equals(s) || "CANCELED".equals(s) || "RESPONSE_FAIL".equals(s); } /** * 电表_立即抄表 */ public static ElectronicBaseResponse eleRead(List param) { if(param ==null || param.size()==0){ return null; } String url = ElectronicConstant.api2_url+"/Api_v2/ele_read"; try { String request_content = JSON.toJSONString(param); String r = requestAsync(url, request_content); return parseAsyncMeterResponse(r); }catch (Exception e){ log.error("电表==============立即抄表",e); } return null; } /** * Api v1 数据类接口(/Api/Meter、/Api/Collector 等)成功标识:文档为 status=1,少数返回 SUCCESS */ public static boolean isDataApiSuccess(ElectronicDataResponse response) { if (response == null || StringUtils.isBlank(response.getStatus())) { return false; } String status = response.getStatus().trim(); return "1".equals(status) || "SUCCESS".equalsIgnoreCase(status); } public static String dataApiErrorMessage(ElectronicDataResponse response, String defaultMsg) { if (response != null && StringUtils.isNotBlank(response.getError_msg())) { return response.getError_msg(); } if (response != null && StringUtils.isNotBlank(response.getStatus())) { return defaultMsg + "(status=" + response.getStatus() + ")"; } return defaultMsg; } /** * 电表_查询设备列表和当前状态 */ public static ElectronicDataResponse meterList( ) { String url = ElectronicConstant.api_url+"/Api/Meter"; try { Map params = new HashMap<>(); params.put("auth",ElectronicConstant.auth_code); String urlParams = getUrlParams(params); url = url + "?" + urlParams; // String request_content = JSON.toJSONString(param); String r = HttpClientGet(url); log.info("meterList=========================:"+r); TypeReference typeReference = new TypeReference< ElectronicDataResponse> >(){}; ElectronicDataResponse result = JSONObject.parseObject(r, typeReference.getType()); return result; }catch (Exception e){ log.error("电表==============查询设备列表和当前状态",e); } return null; } /** * 电表_查询采集器列表和当前状态 */ public static ElectronicDataResponse collectorStatus( ) { String url = ElectronicConstant.api_url+"/Api/Collector"; try { Map params = new HashMap<>(); params.put("auth",ElectronicConstant.auth_code); String urlParams = getUrlParams(params); url = url + "?" + urlParams; // String request_content = JSON.toJSONString(param); String r = HttpClientGet(url); log.info("meterList=========================:"+r); TypeReference typeReference = new TypeReference< ElectronicDataResponse> >(){}; ElectronicDataResponse result = JSONObject.parseObject(r, typeReference.getType()); return result; }catch (Exception e){ log.error("电表==============查询设备列表和当前状态",e); } return null; } /** * 电表_查询参数档案 */ public static ElectronicDataResponse paramList() { String url = ElectronicConstant.api_url+"/Api/Param"; try { Map params = new HashMap<>(); params.put("auth",ElectronicConstant.auth_code); String urlParams = getUrlParams(params); url = url + "?" + urlParams; String r = HttpClientGet(url); log.error("paramList=========================:"+r); TypeReference typeReference = new TypeReference< ElectronicDataResponse> >(){}; ElectronicDataResponse result = JSONObject.parseObject(r, typeReference.getType()); return result; }catch (Exception e){ log.error("电表==============查询参数档案",e); } return null; } /** * 查询历史数据接口 */ public static ElectronicDataResponse queryDataRequest() { return queryDataRequest(null); } /** * 查询历史数据接口 */ public static ElectronicDataResponse queryDataRequest(QueryDataRequest param) { // 查询历史数据接口 try { String url =ElectronicConstant.api_url+"/Api/DataRequest"; Map params = new HashMap<>(); params.put("auth", ElectronicConstant.auth_code); if(param!=null){ params.put("type", param.getType()); params.put("functionids", param.getFunctionids()); params.put("start_time", param.getStart_time()); params.put("end_time", param.getEnd_time()); params.put("offset", param.getOffset()); params.put("limit", param.getLimit()); } String urlParams = getUrlParams(params); url = url + "?" + urlParams; String r = HttpClientGet(url); log.error("查询历史数据接口=============:"+r); TypeReference typeReference = new TypeReference< ElectronicDataResponse> >(){}; ElectronicDataResponse result = JSONObject.parseObject(r, typeReference.getType()); return result; }catch (Exception e){ log.error("电表==============查询历史数据接口",e); } return null; } /** * 报警信息查询接口 */ public static ElectronicDataResponse warningList(WarningListRequest param) { // 查询历史数据接口 try { String url =ElectronicConstant.api_url+"/Api/Warning"; Map params = new HashMap<>(); params.put("auth", ElectronicConstant.auth_code); if(param!=null){ params.put("device_type", param.getDevice_type()); params.put("warning_def_id", param.getWarning_def_id()); } String urlParams = getUrlParams(params); url = url + "?" + urlParams; String r = HttpClientGet(url); log.error("报警信息查询接口========:"+r); TypeReference typeReference = new TypeReference< ElectronicDataResponse> >(){}; ElectronicDataResponse result = JSONObject.parseObject(r, typeReference.getType()); return result; }catch (Exception e){ log.error("电表==============报警信息查询接口",e); } return null; } public static void simpleRequestPrint(String url, String resp) { String name=Thread.currentThread().getStackTrace()[2].getMethodName(); System.out.println(name); System.out.println("请求参数:" + url); System.out.println("返回数据:" + resp); } public static String HttpClientGet(String url) { try { CloseableHttpClient client = HttpClients.createDefault(); HttpGet httpGet = new HttpGet(url); CloseableHttpResponse Response = client.execute(httpGet); HttpEntity entity = Response.getEntity(); String resp = EntityUtils.toString(entity, "UTF-8"); Response.close(); return resp; } catch (Exception e) { System.out.println(e.getMessage()); return ""; } } public static String getUrlParams(Map map) { if (map == null || map.size() == 0) { return ""; } List list = new ArrayList<>(); map.forEach((key, value)->{ try { if(value!=null && StringUtils.isNotBlank(value.toString())){ list.add(key + "=" + URLEncoder.encode(value.toString(), "UTF-8")); } } catch (UnsupportedEncodingException e) { e.printStackTrace(); } }); return String.join("&", list); } public static void testApiAsync(String url, String request_content) { String name=Thread.currentThread().getStackTrace()[2].getMethodName(); System.out.println(name); String response = requestAsync(url, request_content); printResponse(response); } // 打印响应内容 /** * 解析 Api_v2 异步电表操作响应。 * 平台 response_content 可能是 JSON 数组,也可能是字符串形式的 JSON 数组。 */ public static ElectronicBaseResponse parseAsyncMeterResponse(String r) { if (StringUtils.isBlank(r)) { return null; } try { JSONObject jsonObject = JSON.parseObject(r); if (jsonObject == null) { return null; } ElectronicBaseResponse> result = new ElectronicBaseResponse<>(); result.setStatus(jsonObject.getString("status")); result.setTimestamp(jsonObject.getString("timestamp")); result.setError_msg(jsonObject.getString("error_msg")); result.setSign(jsonObject.getString("sign")); result.setResponse_content(parseResponseContentList(jsonObject.get("response_content"), MeterDealResponse.class)); return result; } catch (Exception e) { log.error("parse async meter response failed, raw={}", r, e); return null; } } private static List parseResponseContentList(Object content, Class clazz) { if (content == null) { return null; } if (content instanceof JSONArray) { return ((JSONArray) content).toJavaList(clazz); } if (content instanceof JSONObject) { T one = ((JSONObject) content).toJavaObject(clazz); return one != null ? Collections.singletonList(one) : null; } String text = String.valueOf(content); if (StringUtils.isBlank(text) || "null".equalsIgnoreCase(text.trim())) { return null; } text = text.trim(); if (text.startsWith("[")) { return JSON.parseArray(text, clazz); } if (text.startsWith("{")) { T one = JSON.parseObject(text, clazz); return one != null ? Collections.singletonList(one) : null; } return null; } public static void printResponse(String response) { JSONObject jsonObject = JSON.parseObject(response); String status = jsonObject.getString("status"); if(!"SUCCESS".equals(status)) { System.out.println(jsonObject.getString("error_msg")); } else { String response_content = jsonObject.getString("response_content"); System.out.println("response_content: " + response_content); JSONArray contentArray = JSON.parseArray(response_content); int index = 1; System.out.println("返回结果:"); for(int i = 0; i < contentArray.size(); ++i) { System.out.println("[" + index++ + "]"); JSONObject contentObject = contentArray.getJSONObject(i); Set keySet = contentObject.keySet(); for(String key: keySet) { System.out.println(key + ": " + contentObject.get(key)); } } } } // 请求接口 public static String request(String url, String request_content ){ // 时间戳 String timestamp = String.valueOf(new Date().getTime()/1000); // 用于签名的内容 Map data = new HashMap<>(); data.put("timestamp", timestamp); data.put("auth_code", ElectronicConstant.auth_code); data.put("request_content", request_content); // 获取签名 String sign = getSign(data); data.put("sign", sign); try { String r = sendHttpRequest(url, data); return r; } catch (Exception e) { e.printStackTrace(); } return ""; } // 请求接口 public static String requestAsync(String url, String request_content){ // 时间戳 String timestamp = String.valueOf(new Date().getTime()/1000); // 用于签名的内容 Map data = new HashMap<>(); data.put("timestamp", timestamp); data.put("auth_code", ElectronicConstant.auth_code); data.put("request_content", request_content); data.put("notify_url", ElectronicConstant.notify_url); // 获取签名 String sign = getSign(data); data.put("sign", sign); try { return sendHttpRequest(url, data); } catch (Exception e) { e.printStackTrace(); } return ""; } // 生成签名字符串 public static String getSign(Map data) { // 获取关键字列表 List keys = new ArrayList<>(data.keySet()); // 关键字列表排序 keys.sort(Comparator.naturalOrder()); StringBuilder sb = new StringBuilder(); for (String key : keys) { // 取各个字段内容拼接字符串 sb.append(data.get(key)); } // 加上双方约定随机字符串 String txt = sb.toString() + ElectronicConstant.nonce; // 计算哈希值 return getMD5(txt); } public static boolean verifyNotifySign(String responseContent, String timestamp, String sign) { if (StringUtils.isBlank(responseContent) || StringUtils.isBlank(timestamp) || StringUtils.isBlank(sign)) { return false; } Map withAuth = new HashMap<>(); withAuth.put("auth_code", ElectronicConstant.auth_code); withAuth.put("response_content", responseContent); withAuth.put("timestamp", timestamp); if (sign.equalsIgnoreCase(getSign(withAuth))) { return true; } Map withoutAuth = new HashMap<>(); withoutAuth.put("response_content", responseContent); withoutAuth.put("timestamp", timestamp); return sign.equalsIgnoreCase(getSign(withoutAuth)); } // md5加密 public static String getMD5(String password) { MessageDigest md5 = null; try { md5 = MessageDigest.getInstance("MD5"); } catch (Exception e) { throw new RuntimeException(e); } byte[] byteArray = password.getBytes(StandardCharsets.UTF_8); byte[] md5Bytes = md5.digest(byteArray); StringBuilder hexValue = new StringBuilder(); for (byte md5Byte : md5Bytes) { int val = ((int) md5Byte) & 0xff; if (val < 16) { hexValue.append("0"); } hexValue.append(Integer.toHexString(val)); } return hexValue.toString(); } // 发送http请求 public static String sendHttpRequest(String url, Map bodyMap) throws Exception { System.out.println("请求地址:" + url); System.out.println("发送参数:" + bodyMap.toString()); HttpClient client = HttpClientBuilder.create().build(); HttpPost postRequest = new HttpPost(url); List nvps = new ArrayList<>(); for(String key : bodyMap.keySet()) { nvps.add(new BasicNameValuePair(key,bodyMap.get(key))); } postRequest.setEntity(new UrlEncodedFormEntity(nvps,"utf-8")); int retry = 3; HttpResponse execute = null; while(retry-- > 0) { try { execute = client.execute(postRequest); break; } catch (Exception e) { Thread.sleep(5000); } } if(execute == null) { throw new Exception("接口请求失败"); } String resp = EntityUtils.toString(execute.getEntity(), "UTF-8"); System.out.println("接口返回:" + resp); return resp; } }