Commit e1f88de450ad326edfef663312ec2afef4a1b1f7

Authored by 杨鸣坤
1 parent 33ef845b

金马

  1 +package com.iot.scheduler.service.wuwei;
  2 +
  3 +import com.alibaba.fastjson.JSON;
  4 +import com.alibaba.fastjson.JSONArray;
  5 +import com.alibaba.fastjson.JSONObject;
  6 +import com.alibaba.fastjson.TypeReference;
  7 +import com.iot.scheduler.model.DeviceToken;
  8 +import com.iot.scheduler.model.QxDeviceInfo;
  9 +import com.iot.scheduler.model.QxDeviceInfoDetail;
  10 +import jakarta.annotation.Resource;
  11 +import lombok.extern.slf4j.Slf4j;
  12 +import org.apache.commons.lang3.StringUtils;
  13 +import org.apache.http.Consts;
  14 +import org.apache.http.HttpEntity;
  15 +import org.apache.http.client.methods.CloseableHttpResponse;
  16 +import org.apache.http.client.methods.HttpGet;
  17 +import org.apache.http.client.methods.HttpPost;
  18 +import org.apache.http.entity.ContentType;
  19 +import org.apache.http.entity.StringEntity;
  20 +import org.apache.http.impl.client.CloseableHttpClient;
  21 +import org.apache.http.impl.client.HttpClients;
  22 +import org.apache.http.message.BasicHeader;
  23 +import org.apache.http.util.EntityUtils;
  24 +import org.springframework.beans.factory.annotation.Value;
  25 +import org.springframework.data.redis.core.RedisTemplate;
  26 +import org.springframework.stereotype.Service;
  27 +import org.springframework.util.CollectionUtils;
  28 +import org.springframework.util.LinkedMultiValueMap;
  29 +import org.springframework.util.MultiValueMap;
  30 +import org.springframework.web.util.UriComponentsBuilder;
  31 +
  32 +import java.io.ByteArrayOutputStream;
  33 +import java.io.IOException;
  34 +import java.io.InputStream;
  35 +import java.text.SimpleDateFormat;
  36 +import java.util.*;
  37 +import java.util.concurrent.TimeUnit;
  38 +
  39 +
  40 +/**
  41 + * 金马电气三色灯--->IOT平台
  42 + */
  43 +@Slf4j
  44 +@Service
  45 +public class JmDevicePullService {
  46 +
  47 + @Value("${jmdq.iot.organizeId:}")
  48 + private String iotOrganizeId;
  49 + @Value("${jmdq.iot.profileId}")
  50 + private String iotProfileId;
  51 + @Value("${jmdq.iot.deviceProfileId}")
  52 + private String iotDeviceProfileId;
  53 + @Value("${jmdq.iot.userName:}")
  54 + private String iotUserName;
  55 + @Value("${jmdq.iot.password:}")
  56 + private String iotPassword;
  57 + @Value("${jmdq.iot.tokenUrl}")
  58 + private String iotTokenUrl;
  59 + @Value("${jmdq.iot.infoUrl}")
  60 + private String iotDeviceInfoUrl;
  61 + @Value("${jmdq.iot.detailUrl}")
  62 + private String iotDeviceDetailUrl;
  63 +
  64 +
  65 + @Value("${device.token.url}")
  66 + private String deviceTokenUrl;
  67 + @Value("${device.token.userName}")
  68 + private String deviceUserName;
  69 + @Value("${device.token.password}")
  70 + private String devicePassword;
  71 + @Value("${device.info.url}")
  72 + private String deviceInfoUrl;
  73 + @Value("${device.detail.url}")
  74 + private String deviceDetailUrl;
  75 +
  76 + @Resource
  77 + private RedisTemplate<String, String> redisTemplate;
  78 +
  79 + final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  80 +
  81 + public void pullDeviceAndPushToIot() {
  82 + String deviceResult = getDeviceInfo();
  83 + Map<String, Object> deviceInfos = JSON.parseObject(deviceResult, new TypeReference<>() {
  84 + });
  85 +
  86 + JSONArray deviceInfoList = (JSONArray) deviceInfos.get("data");
  87 + List<QxDeviceInfo> qxDeviceInfos = new ArrayList<>();
  88 + List<QxDeviceInfoDetail> qxAddDeviceInfoDetails = new ArrayList<>();
  89 + Map<String, QxDeviceInfoDetail> qxDeviceInfoDetailMap = new HashMap<>();
  90 + for (Object o : deviceInfoList) {
  91 + JSONObject deviceInfoJson = (JSONObject) o;
  92 + QxDeviceInfo qxDeviceInfo = new QxDeviceInfo();
  93 + qxDeviceInfo.setDeviceType("DIRECT_CONNECTION");
  94 + qxDeviceInfo.setTransportType("DEFAULT");
  95 + qxDeviceInfo.setOrganizationId(iotOrganizeId);
  96 + qxDeviceInfo.setDeviceProfileId(iotDeviceProfileId);
  97 + qxDeviceInfo.setProfileId(iotProfileId);
  98 +// //项目状态(1:在线,2:离线,3:报警)
  99 +// Integer projectState = deviceInfoJson.getInteger("projectState");
  100 +// if (projectState != null) {
  101 +// qxDeviceInfo.setDescription(String.valueOf(projectState));
  102 +// }
  103 +
  104 + //项目类型
  105 + qxDeviceInfo.setLabel("生产设备");
  106 + //设备名称
  107 + String deviceName = deviceInfoJson.getString("deviceName");
  108 +
  109 + qxDeviceInfo.setName(deviceName);
  110 + qxDeviceInfo.setBrand(deviceName);
  111 + //序列号
  112 + String dtuSn = deviceInfoJson.getString("dtuSn");
  113 + qxDeviceInfo.setSn(dtuSn);
  114 + DeviceToken deviceToken = new DeviceToken();
  115 + deviceToken.setCredentialsType("ACCESS_TOKEN");
  116 + deviceToken.setCredentialsId(dtuSn);
  117 + deviceToken.setCredentialsValue(dtuSn);
  118 + qxDeviceInfo.setDeviceToken(deviceToken);
  119 + qxDeviceInfos.add(qxDeviceInfo);
  120 + //有序列号直接获取灯信息
  121 + if (StringUtils.isNotBlank(dtuSn)) {
  122 + String deviceInfoDetails = getDeviceInfoDetail(dtuSn);
  123 + if (StringUtils.isBlank(deviceInfoDetails)) {
  124 + continue;
  125 + }
  126 +
  127 + Map<String, Object> deviceInfoDetailMap = JSON.parseObject(deviceInfoDetails, new TypeReference<>() {
  128 + });
  129 +
  130 + JSONArray deviceInfoDetailList = (JSONArray) deviceInfoDetailMap.get("data");
  131 + if (CollectionUtils.isEmpty(deviceInfoDetailList)) {
  132 + continue;
  133 + }
  134 +
  135 + JSONObject deviceInfoDetailJson = (JSONObject) deviceInfoDetailList.get(0);
  136 + //灯详情数据
  137 + //序列号
  138 + String dtuSnDetail = deviceInfoDetailJson.getString("dtuSn");
  139 + //开始时间
  140 + String startTime = deviceInfoDetailJson.getString("startTime");
  141 + QxDeviceInfoDetail qxDeviceInfoDetail = new QxDeviceInfoDetail();
  142 + qxDeviceInfoDetail.setAlarm(false);
  143 + //灯状态(0:灭灯,1:红,2:黄,3:绿,4:蓝)
  144 + Integer lampState = deviceInfoDetailJson.getInteger("lampState");
  145 + switch (lampState) {
  146 + case 0:
  147 + qxDeviceInfoDetail.setStatus("OFF");
  148 + break;
  149 + case 1:
  150 + qxDeviceInfoDetail.setStatus("ERROR");
  151 + qxDeviceInfoDetail.setAlarm(true);
  152 + break;
  153 + case 2:
  154 + qxDeviceInfoDetail.setStatus("STAND");
  155 + break;
  156 + case 3:
  157 + qxDeviceInfoDetail.setStatus("RUN");
  158 + break;
  159 + default:
  160 + continue;
  161 + }
  162 +
  163 + if (StringUtils.isNotBlank(startTime)) {
  164 + try {
  165 + qxDeviceInfoDetail.setStartTime(dateFormat.parse(startTime));
  166 + } catch (Exception e) {
  167 + log.error("时间格式出错");
  168 + qxDeviceInfoDetail.setStartTime(new Date());
  169 + }
  170 + } else {
  171 + qxDeviceInfoDetail.setStartTime(new Date());
  172 + }
  173 +
  174 + qxDeviceInfoDetail.setDtuSn(dtuSn);
  175 + qxDeviceInfoDetailMap.put(dtuSn, qxDeviceInfoDetail);
  176 + qxAddDeviceInfoDetails.add(qxDeviceInfoDetail);
  177 + }
  178 + }
  179 +
  180 + //将数据同步到IOT平台
  181 + Map<String, String> qxParam = new HashMap<>(2);
  182 + qxParam.put("username", iotUserName);
  183 + qxParam.put("password", iotPassword);
  184 +
  185 + HttpPost qxHttpPost = new HttpPost(iotTokenUrl);
  186 + String qxResult = sendPost(qxHttpPost, JSON.toJSONString(qxParam));
  187 + if (StringUtils.isBlank(qxResult)) {
  188 + return;
  189 + }
  190 + Map<String, Object> qxRes = JSON.parseObject(qxResult, new TypeReference<Map<String, Object>>() {
  191 + });
  192 +
  193 + String qxAccessToken = (String) qxRes.get("token");
  194 + if (StringUtils.isBlank(qxAccessToken)) {
  195 + return;
  196 + }
  197 +
  198 + BasicHeader qxAuthorization = new BasicHeader("X-Authorization", "Bearer " + qxAccessToken);
  199 + if (!CollectionUtils.isEmpty(qxDeviceInfos)) {
  200 + HttpPost qxDeviceInfoPost = new HttpPost(iotDeviceInfoUrl);
  201 + qxDeviceInfoPost.addHeader(qxAuthorization);
  202 + for (QxDeviceInfo qxDeviceInfo : qxDeviceInfos) {
  203 + // todo
  204 + String syncDeviceInfo = sendPost(qxDeviceInfoPost, JSON.toJSONString(qxDeviceInfo));
  205 + //log.info("同步设备信息 syncDeviceInfo:{}", syncDeviceInfo);
  206 + }
  207 + }
  208 +
  209 + if (!CollectionUtils.isEmpty(qxAddDeviceInfoDetails)) {
  210 + for (QxDeviceInfoDetail qxDeviceInfoDetail : qxAddDeviceInfoDetails) {
  211 + String qxDeviceInfoDetailUrlStr = iotDeviceDetailUrl + qxDeviceInfoDetail.getDtuSn() + "/telemetry";
  212 + HttpPost qxDeviceInfoDetailPost = new HttpPost(qxDeviceInfoDetailUrlStr);
  213 + qxDeviceInfoDetailPost.addHeader(qxAuthorization);
  214 + String syncDeviceInfoDetail = sendPost(qxDeviceInfoDetailPost, JSON.toJSONString(qxDeviceInfoDetail));
  215 + }
  216 + }
  217 + }
  218 +
  219 + public String getDeviceInfoDetail(String dtuSn) {
  220 + String accessToken = getAccessToken();
  221 + Map<String, String> dtuSnOb = new HashMap<>(1);
  222 + dtuSnOb.put("dtuSn", dtuSn);
  223 + Map<String, String> headerMap = new HashMap<>(1);
  224 + headerMap.put("Authorization", "Bearer " + accessToken);
  225 + String deviceInfoDetail = sendRequestGet(deviceDetailUrl, dtuSnOb, headerMap);
  226 + if (StringUtils.isBlank(deviceInfoDetail)) {
  227 + return null;
  228 + }
  229 +
  230 + Map<String, Object> deviceInfoDetailMap = JSON.parseObject(deviceInfoDetail,
  231 + new TypeReference<>() {
  232 + });
  233 + Integer deviceInfoDetailCode = (Integer) deviceInfoDetailMap.get("code");
  234 + if (deviceInfoDetailCode != 200) {
  235 + return null;
  236 + }
  237 +
  238 + JSONArray deviceInfoDetailList = (JSONArray) deviceInfoDetailMap.get("data");
  239 + if (CollectionUtils.isEmpty(deviceInfoDetailList)) {
  240 + return null;
  241 + }
  242 +
  243 + JSONObject deviceInfoDetailJson = (JSONObject) deviceInfoDetailList.get(0);
  244 + //灯详情数据
  245 + //灯状态(0:灭灯,1:红,2:黄,3:绿,4:蓝)
  246 + Integer lampState = deviceInfoDetailJson.getInteger("lampState");
  247 + if (lampState == null) {
  248 + return null;
  249 + }
  250 +
  251 + return deviceInfoDetail;
  252 + }
  253 +
  254 + public String getDeviceInfo() {
  255 + String accessToken = getAccessToken();
  256 + // 初始化headerMap并设置Authorization
  257 + Map<String, String> headerMap = new HashMap<>(1);
  258 + headerMap.put("Authorization", "Bearer " + accessToken);
  259 +
  260 + Map<String, String> paramsMap = new HashMap<>();
  261 + paramsMap.put("groupName", "金马");
  262 +
  263 + // 第一次请求设备信息
  264 + String deviceResult = sendRequestGet(deviceInfoUrl, paramsMap, headerMap);
  265 +
  266 + // 检查设备信息是否为空
  267 + if (StringUtils.isBlank(deviceResult)) {
  268 + return null;
  269 + }
  270 +
  271 + // 解析设备信息
  272 + Map<String, Object> deviceInfos = JSON.parseObject(deviceResult, new TypeReference<>() {
  273 + });
  274 + Integer deviceInfoCode = (Integer) deviceInfos.get("code");
  275 +
  276 + // 如果code不为200,可能是accessToken失效,重新获取token并重试
  277 + if (deviceInfoCode != 200) {
  278 + accessToken = getAccessToken();
  279 + if (StringUtils.isEmpty(accessToken)) {
  280 + return null;
  281 + }
  282 +
  283 + // 更新headerMap中的Authorization
  284 + headerMap.put("Authorization", "Bearer " + accessToken);
  285 +
  286 + // 第二次请求设备信息
  287 + deviceResult = sendRequestGet(deviceInfoUrl, paramsMap, headerMap);
  288 + if (StringUtils.isBlank(deviceResult)) {
  289 + return null;
  290 + }
  291 +
  292 + // 重新解析设备信息
  293 + deviceInfos = JSON.parseObject(deviceResult, new TypeReference<>() {
  294 + });
  295 + deviceInfoCode = (Integer) deviceInfos.get("code");
  296 +
  297 + // 如果第二次请求仍然失败,返回错误信息
  298 + if (deviceInfoCode != 200) {
  299 + return null;
  300 + }
  301 + }
  302 +
  303 + // 返回成功的设备信息
  304 + return deviceResult;
  305 + }
  306 +
  307 + private String getAccessToken() {
  308 + String accessToken = "";
  309 + String redisKey = "device_token";
  310 + if (StringUtils.isNotBlank(redisTemplate.opsForValue().get(redisKey)) && redisTemplate.getExpire(redisKey) > 0) {
  311 + return redisTemplate.opsForValue().get(redisKey);
  312 + }
  313 +
  314 + Map<String, String> param = new HashMap<>(2);
  315 + param.put("username", deviceUserName);
  316 + param.put("password", devicePassword);
  317 + HttpPost httpPost = new HttpPost(deviceTokenUrl);
  318 + String result = sendPost(httpPost, JSON.toJSONString(param));
  319 + if (StringUtils.isBlank(result)) {
  320 + return accessToken;
  321 + }
  322 +
  323 + Map<String, Object> res = JSON.parseObject(result, new TypeReference<>() {
  324 + });
  325 +
  326 + Integer code = (Integer) res.get("code");
  327 + if (code == 200) {
  328 + JSONObject data = (JSONObject) res.get("data");
  329 + accessToken = (String) data.get("token");
  330 + redisTemplate.opsForValue().set(redisKey, accessToken, 3600, TimeUnit.SECONDS); // 一小时过期
  331 + }
  332 +
  333 + return accessToken;
  334 + }
  335 +
  336 + public static String sendRequestGet(String url, Map<String, String> params, Map<String, String> header) {
  337 + //实例化httpclient
  338 + CloseableHttpClient httpclient = HttpClients.createDefault();
  339 + url = builderUrl(url, params);
  340 + //请求结果
  341 + String content = "";
  342 + //实例化get方法
  343 + HttpGet httpget = new HttpGet(url);
  344 + if (!CollectionUtils.isEmpty(header)) {
  345 + for (Map.Entry<String, String> entry : header.entrySet()) {
  346 + httpget.setHeader(entry.getKey(), entry.getValue());
  347 + }
  348 + }
  349 +
  350 + try (CloseableHttpResponse response = httpclient.execute(httpget)) {
  351 +
  352 + //执行get方法
  353 + if (response.getStatusLine().getStatusCode() == 200) {
  354 + content = EntityUtils.toString(response.getEntity(), "UTF-8");
  355 + }
  356 + } catch (IOException e) {
  357 + log.error("sendRequest---GET Error!", e);
  358 + }
  359 + return content;
  360 + }
  361 +
  362 + private static String builderUrl(String url, Map<String, String> params) {
  363 + UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(url);
  364 + if (!CollectionUtils.isEmpty(params)) {
  365 + MultiValueMap<String, String> paramsValue = new LinkedMultiValueMap<>();
  366 + for (Map.Entry<String, String> entry : params.entrySet()) {
  367 + paramsValue.add(entry.getKey(), entry.getValue());
  368 + }
  369 +
  370 + uriBuilder = uriBuilder.queryParams(paramsValue);
  371 + }
  372 +
  373 + return uriBuilder.toUriString();
  374 + }
  375 +
  376 + private String sendPost(HttpPost httpPost, String jsonData) {
  377 + CloseableHttpClient httpClient = HttpClients.createDefault();
  378 + StringEntity entity = new StringEntity(jsonData, ContentType.create("application/json", Consts.UTF_8));
  379 + httpPost.setEntity(entity);
  380 + String result = null;
  381 + try {
  382 + CloseableHttpResponse execute = httpClient.execute(httpPost);
  383 + HttpEntity res = execute.getEntity();
  384 + InputStream is = res.getContent();
  385 + int len;
  386 + byte[] buf = new byte[128];
  387 + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
  388 + while ((len = is.read(buf)) != -1) {
  389 + byteArrayOutputStream.write(buf, 0, len);
  390 + }
  391 + result = byteArrayOutputStream.toString();
  392 + } catch (IOException e) {
  393 + e.printStackTrace();
  394 + }
  395 + return result;
  396 + }
  397 +}
  1 +package com.iot.scheduler.zone;
  2 +
  3 +import com.iot.scheduler.service.PjDeviceReportService;
  4 +import com.iot.scheduler.service.wuwei.JmDevicePullService;
  5 +import com.iot.scheduler.task.AbstractZoneScheduler;
  6 +import jakarta.annotation.Resource;
  7 +import lombok.extern.slf4j.Slf4j;
  8 +import org.springframework.scheduling.annotation.Scheduled;
  9 +import org.springframework.stereotype.Component;
  10 +
  11 +/**
  12 + * 无为金马设备同步
  13 + */
  14 +@Slf4j
  15 +@Component
  16 +public class WuweiZoneScheduler extends AbstractZoneScheduler {
  17 +
  18 + @Resource
  19 + private JmDevicePullService jmDevicePullService;
  20 +
  21 + @Override
  22 + protected String getZoneName() {
  23 + return "WuWei (无为园区)";
  24 + }
  25 +
  26 + @Scheduled(cron = "${scheduler.jmdq.pull:0 0/1 * * * ?}")
  27 + public void pullDevicesFromThirdParty() {
  28 + String taskName = "Pull Devices (3rd Party -> IoT)";
  29 + logStart(taskName);
  30 + try {
  31 + // TODO: Implement actual logic
  32 + log.info("[{}] Simulating pulling devices...", getZoneName());
  33 + jmDevicePullService.pullDeviceAndPushToIot();
  34 + Thread.sleep(1000);
  35 + } catch (Exception e) {
  36 + logError(taskName, e);
  37 + } finally {
  38 + logEnd(taskName);
  39 + }
  40 + }
  41 +
  42 + @Scheduled(cron = "${scheduler.jmdq.push:0 0/10 * * * ?}")
  43 + public void pushJmDevicesToThirdParty() {
  44 + String taskName = "PJ Devices (IoT -> 3rd Party)";
  45 + logStart(taskName);
  46 + try {
  47 + log.info("[{}] PJ pushing devices...", getZoneName());
  48 +// pjDeviceReportService.batchReportEnterprise();
  49 + Thread.sleep(1000);
  50 + } catch (Exception e) {
  51 + logError(taskName, e);
  52 + } finally {
  53 + logEnd(taskName);
  54 + }
  55 + }
  56 +}
@@ -37,6 +37,9 @@ scheduler: @@ -37,6 +37,9 @@ scheduler:
37 push: "0 0 0/1 * * ?" 37 push: "0 0 0/1 * * ?"
38 pj: 38 pj:
39 push: "0 0/10 * * * ?" 39 push: "0 0/10 * * * ?"
  40 + jmdq:
  41 + pull: "0 0/1 * * * ?"
  42 + push: "0 0/10 * * * ?"
40 43
41 hn: 44 hn:
42 third: 45 third:
@@ -144,6 +147,17 @@ shzz: @@ -144,6 +147,17 @@ shzz:
144 infoUrl: "https://iot.hzzlyun.com/api/yt/device" 147 infoUrl: "https://iot.hzzlyun.com/api/yt/device"
145 detailUrl: "https://iot.hzzlyun.com/api/v1/" 148 detailUrl: "https://iot.hzzlyun.com/api/v1/"
146 149
  150 +jmdq:
  151 + iot:
  152 + organizeId: "80108826-48af-48ff-b120-41d1a5722e9a"
  153 + profileId: "e717b260-025d-11f1-9cb8-e3376d1e7978"
  154 + deviceProfileId: "e717b260-025d-11f1-9cb8-e3376d1e7978"
  155 + userName: "jmdq"
  156 + password: "123456"
  157 + tokenUrl: "https://iot.hzzlyun.com/api/auth/login"
  158 + infoUrl: "https://iot.hzzlyun.com/api/yt/device"
  159 + detailUrl: "https://iot.hzzlyun.com/api/v1/"
  160 +
147 device: 161 device:
148 token: 162 token:
149 url: "https://iotgc.cniot.vip/auth/token" 163 url: "https://iotgc.cniot.vip/auth/token"