Commit 24851b70ec13d68a2d1ef04f25e1a71cb91e2a49

Authored by 杨鸣坤
1 parent 7220147f

feat: 添加设备拉取服务和相关配置

... ... @@ -35,6 +35,60 @@
35 35 <artifactId>spring-boot-starter-test</artifactId>
36 36 <scope>test</scope>
37 37 </dependency>
  38 + <dependency>
  39 + <groupId>com.zaxxer</groupId>
  40 + <artifactId>HikariCP</artifactId>
  41 + <version>4.0.3</version>
  42 + </dependency>
  43 + <dependency>
  44 + <groupId>com.zaxxer</groupId>
  45 + <artifactId>HikariCP-java7</artifactId>
  46 + <version>2.4.13</version>
  47 + </dependency>
  48 + <dependency>
  49 + <groupId>org.postgresql</groupId>
  50 + <artifactId>postgresql</artifactId>
  51 + <version>42.7.3</version>
  52 + </dependency>
  53 + <dependency>
  54 + <groupId>org.apache.httpcomponents</groupId>
  55 + <artifactId>httpclient</artifactId>
  56 + <version>4.5.8</version>
  57 + </dependency>
  58 + <!--工具类-->
  59 + <dependency>
  60 + <groupId>org.apache.commons</groupId>
  61 + <artifactId>commons-lang3</artifactId>
  62 + <version>3.6</version>
  63 + </dependency>
  64 +
  65 + <!--工具类-->
  66 + <dependency>
  67 + <groupId>org.apache.commons</groupId>
  68 + <artifactId>commons-collections4</artifactId>
  69 + <version>4.2</version>
  70 + </dependency>
  71 +
  72 + <dependency>
  73 + <groupId>com.alibaba</groupId>
  74 + <artifactId>fastjson</artifactId>
  75 + <version>1.2.60</version>
  76 + </dependency>
  77 + <dependency>
  78 + <groupId>org.springframework.boot</groupId>
  79 + <artifactId>spring-boot-starter-data-redis</artifactId>
  80 + <version>2.0.9.RELEASE</version>
  81 + </dependency>
  82 + <dependency>
  83 + <groupId>redis.clients</groupId>
  84 + <artifactId>jedis</artifactId>
  85 + <version>2.9.0</version>
  86 + </dependency>
  87 + <dependency>
  88 + <groupId>org.eclipse.paho</groupId>
  89 + <artifactId>org.eclipse.paho.client.mqttv3</artifactId>
  90 + <version>1.2.5</version>
  91 + </dependency>
38 92 </dependencies>
39 93
40 94 <build>
... ...
1 1 package com.iot.scheduler.controller;
2 2
  3 +import com.iot.scheduler.service.DevicePullService;
  4 +import jakarta.annotation.Resource;
3 5 import org.springframework.web.bind.annotation.GetMapping;
4 6 import org.springframework.web.bind.annotation.RestController;
5 7
6 8 @RestController
7 9 public class HealthController {
8 10
  11 + @Resource
  12 + private DevicePullService devicePullService;
  13 +
9 14 @GetMapping("/health")
10 15 public String health() {
  16 + devicePullService.getEnergyInfo();
11 17 return "IoT Scheduler is running...";
12 18 }
13 19 }
... ...
  1 +package com.iot.scheduler.service;
  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 jakarta.annotation.Resource;
  8 +import lombok.extern.slf4j.Slf4j;
  9 +import org.apache.commons.lang3.StringUtils;
  10 +import org.apache.http.Consts;
  11 +import org.apache.http.HttpEntity;
  12 +import org.apache.http.client.methods.CloseableHttpResponse;
  13 +import org.apache.http.client.methods.HttpGet;
  14 +import org.apache.http.client.methods.HttpPost;
  15 +import org.apache.http.entity.ContentType;
  16 +import org.apache.http.entity.StringEntity;
  17 +import org.apache.http.impl.client.CloseableHttpClient;
  18 +import org.apache.http.impl.client.HttpClients;
  19 +import org.apache.http.util.EntityUtils;
  20 +import org.springframework.beans.factory.annotation.Value;
  21 +import org.springframework.data.redis.core.RedisTemplate;
  22 +import org.springframework.stereotype.Service;
  23 +import org.springframework.util.CollectionUtils;
  24 +import org.springframework.util.LinkedMultiValueMap;
  25 +import org.springframework.util.MultiValueMap;
  26 +import org.springframework.web.util.UriComponentsBuilder;
  27 +
  28 +import java.io.ByteArrayOutputStream;
  29 +import java.io.IOException;
  30 +import java.io.InputStream;
  31 +import java.text.SimpleDateFormat;
  32 +import java.util.*;
  33 +import java.util.concurrent.TimeUnit;
  34 +
  35 +@Slf4j
  36 +@Service
  37 +public class DevicePullService {
  38 +
  39 +
  40 + @Value("${device.token.url}")
  41 + private String deviceTokenUrl;
  42 + @Value("${device.token.userName}")
  43 + private String deviceUserName;
  44 + @Value("${device.token.password}")
  45 + private String devicePassword;
  46 + @Value("${device.info.url}")
  47 + private String deviceInfoUrl;
  48 + @Value("${device.detail.url}")
  49 + private String deviceDetailUrl;
  50 + @Value("${device.energyInfo.url}")
  51 + private String energyInfoUrl;
  52 +
  53 + @Resource
  54 + private RedisTemplate<String, String> redisTemplate;
  55 +
  56 + final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  57 +
  58 + public void pullDeviceAndPushToIot() {
  59 + String deviceResult = getDeviceInfo();
  60 + Map<String, Object> deviceInfos = JSON.parseObject(deviceResult, new TypeReference<>() {
  61 + });
  62 +
  63 + JSONArray deviceInfoList = (JSONArray) deviceInfos.get("data");
  64 +
  65 + }
  66 +
  67 + public String getDeviceInfoDetail(String dtuSn) {
  68 + String accessToken = getAccessToken();
  69 + Map<String, String> dtuSnOb = new HashMap<>(1);
  70 + dtuSnOb.put("dtuSn", dtuSn);
  71 + Map<String, String> headerMap = new HashMap<>(1);
  72 + headerMap.put("Authorization", "Bearer " + accessToken);
  73 + String deviceInfoDetail = sendRequestGet(deviceDetailUrl, dtuSnOb, headerMap);
  74 + if (StringUtils.isBlank(deviceInfoDetail)) {
  75 + return null;
  76 + }
  77 +
  78 + Map<String, Object> deviceInfoDetailMap = JSON.parseObject(deviceInfoDetail,
  79 + new TypeReference<>() {
  80 + });
  81 + Integer deviceInfoDetailCode = (Integer) deviceInfoDetailMap.get("code");
  82 + if (deviceInfoDetailCode != 200) {
  83 + return null;
  84 + }
  85 +
  86 + JSONArray deviceInfoDetailList = (JSONArray) deviceInfoDetailMap.get("data");
  87 + if (CollectionUtils.isEmpty(deviceInfoDetailList)) {
  88 + return null;
  89 + }
  90 +
  91 + JSONObject deviceInfoDetailJson = (JSONObject) deviceInfoDetailList.get(0);
  92 + //灯详情数据
  93 + //灯状态(0:灭灯,1:红,2:黄,3:绿,4:蓝)
  94 + Integer lampState = deviceInfoDetailJson.getInteger("lampState");
  95 + if (lampState == null) {
  96 + return null;
  97 + }
  98 +
  99 + return deviceInfoDetail;
  100 + }
  101 +
  102 + public String getEnergyInfo() {
  103 + String accessToken = getAccessToken();
  104 + Map<String, String> headerMap = new HashMap<>(1);
  105 + headerMap.put("Authorization", "Bearer " + accessToken);
  106 +
  107 + Map<String, String> paramsMap = new HashMap<>();
  108 + paramsMap.put("groupName", "一期工厂");
  109 +
  110 + String energyInfoResult = sendRequestGet(energyInfoUrl, paramsMap, headerMap);
  111 + if (StringUtils.isBlank(energyInfoResult)) {
  112 + return null;
  113 + }
  114 +
  115 + // 解析设备信息
  116 + Map<String, Object> energyInfos = JSON.parseObject(energyInfoResult, new TypeReference<>() {
  117 + });
  118 + Integer energyInfoCode = (Integer) energyInfos.get("code");
  119 +
  120 + // 如果code不为200,可能是accessToken失效,重新获取token并重试
  121 + if (energyInfoCode != 200) {
  122 + accessToken = getAccessToken();
  123 + if (StringUtils.isEmpty(accessToken)) {
  124 + return null;
  125 + }
  126 +
  127 + // 更新headerMap中的Authorization
  128 + headerMap.put("Authorization", "Bearer " + accessToken);
  129 +
  130 + // 第二次请求设备信息
  131 + energyInfoResult = sendRequestGet(energyInfoUrl, paramsMap, headerMap);
  132 + if (StringUtils.isBlank(energyInfoResult)) {
  133 + return null;
  134 + }
  135 +
  136 + // 重新解析设备信息
  137 + energyInfos = JSON.parseObject(energyInfoResult, new TypeReference<Map<String, Object>>() {
  138 + });
  139 + energyInfoCode = (Integer) energyInfos.get("code");
  140 +
  141 + // 如果第二次请求仍然失败,返回错误信息
  142 + if (energyInfoCode != 200) {
  143 + return null;
  144 + }
  145 + }
  146 +
  147 + // 返回成功的设备信息
  148 + return energyInfoResult;
  149 + }
  150 +
  151 + public String getDeviceInfo() {
  152 + String accessToken = getAccessToken();
  153 + // 初始化headerMap并设置Authorization
  154 + Map<String, String> headerMap = new HashMap<>(1);
  155 + headerMap.put("Authorization", "Bearer " + accessToken);
  156 +
  157 + Map<String, String> paramsMap = new HashMap<>();
  158 + paramsMap.put("groupName", "一期工厂");
  159 +
  160 + // 第一次请求设备信息
  161 + String deviceResult = sendRequestGet(deviceInfoUrl, paramsMap, headerMap);
  162 +
  163 + // 检查设备信息是否为空
  164 + if (StringUtils.isBlank(deviceResult)) {
  165 + return null;
  166 + }
  167 +
  168 + // 解析设备信息
  169 + Map<String, Object> deviceInfos = JSON.parseObject(deviceResult, new TypeReference<Map<String, Object>>() {
  170 + });
  171 + Integer deviceInfoCode = (Integer) deviceInfos.get("code");
  172 +
  173 + // 如果code不为200,可能是accessToken失效,重新获取token并重试
  174 + if (deviceInfoCode != 200) {
  175 + accessToken = getAccessToken();
  176 + if (StringUtils.isEmpty(accessToken)) {
  177 + return null;
  178 + }
  179 +
  180 + // 更新headerMap中的Authorization
  181 + headerMap.put("Authorization", "Bearer " + accessToken);
  182 +
  183 + // 第二次请求设备信息
  184 + deviceResult = sendRequestGet(deviceInfoUrl, paramsMap, headerMap);
  185 + if (StringUtils.isBlank(deviceResult)) {
  186 + return null;
  187 + }
  188 +
  189 + // 重新解析设备信息
  190 + deviceInfos = JSON.parseObject(deviceResult, new TypeReference<Map<String, Object>>() {
  191 + });
  192 + deviceInfoCode = (Integer) deviceInfos.get("code");
  193 +
  194 + // 如果第二次请求仍然失败,返回错误信息
  195 + if (deviceInfoCode != 200) {
  196 + return null;
  197 + }
  198 + }
  199 +
  200 + // 返回成功的设备信息
  201 + return deviceResult;
  202 + }
  203 +
  204 + private String getAccessToken() {
  205 + String accessToken = "";
  206 + String redisKey = "hnyssl_device_token";
  207 + if (StringUtils.isNotBlank(redisTemplate.opsForValue().get(redisKey)) && redisTemplate.getExpire(redisKey) > 0) {
  208 + return redisTemplate.opsForValue().get(redisKey);
  209 + }
  210 +
  211 + Map<String, String> param = new HashMap<>(2);
  212 + param.put("username", deviceUserName);
  213 + param.put("password", devicePassword);
  214 + HttpPost httpPost = new HttpPost(deviceTokenUrl);
  215 + String result = sendPost(httpPost, JSON.toJSONString(param));
  216 + if (StringUtils.isBlank(result)) {
  217 + return accessToken;
  218 + }
  219 +
  220 + Map<String, Object> res = JSON.parseObject(result, new TypeReference<>() {
  221 + });
  222 +
  223 + Integer code = (Integer) res.get("code");
  224 + if (code == 200) {
  225 + JSONObject data = (JSONObject) res.get("data");
  226 + accessToken = (String) data.get("token");
  227 + redisTemplate.opsForValue().set(redisKey, accessToken, 3600, TimeUnit.SECONDS); // 一小时过期
  228 + }
  229 +
  230 + return accessToken;
  231 + }
  232 +
  233 + public static String sendRequestGet(String url, Map<String, String> params, Map<String, String> header) {
  234 + //实例化httpclient
  235 + CloseableHttpClient httpclient = HttpClients.createDefault();
  236 + url = builderUrl(url, params);
  237 + //请求结果
  238 + String content = "";
  239 + //实例化get方法
  240 + HttpGet httpget = new HttpGet(url);
  241 + if (!CollectionUtils.isEmpty(header)) {
  242 + for (Map.Entry<String, String> entry : header.entrySet()) {
  243 + httpget.setHeader(entry.getKey(), entry.getValue());
  244 + }
  245 + }
  246 +
  247 + try (CloseableHttpResponse response = httpclient.execute(httpget)) {
  248 +
  249 + //执行get方法
  250 + if (response.getStatusLine().getStatusCode() == 200) {
  251 + content = EntityUtils.toString(response.getEntity(), "UTF-8");
  252 + }
  253 + } catch (IOException e) {
  254 + log.error("sendRequest---GET Error!", e);
  255 + }
  256 + return content;
  257 + }
  258 +
  259 + private static String builderUrl(String url, Map<String, String> params) {
  260 + UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(url);
  261 + if (!CollectionUtils.isEmpty(params)) {
  262 + MultiValueMap<String, String> paramsValue = new LinkedMultiValueMap<>();
  263 + for (Map.Entry<String, String> entry : params.entrySet()) {
  264 + paramsValue.add(entry.getKey(), entry.getValue());
  265 + }
  266 +
  267 + uriBuilder = uriBuilder.queryParams(paramsValue);
  268 + }
  269 +
  270 + return uriBuilder.toUriString();
  271 + }
  272 +
  273 + private String sendPost(HttpPost httpPost, String jsonData) {
  274 + CloseableHttpClient httpClient = HttpClients.createDefault();
  275 + StringEntity entity = new StringEntity(jsonData, ContentType.create("application/json", Consts.UTF_8));
  276 + httpPost.setEntity(entity);
  277 + String result = null;
  278 + try {
  279 + CloseableHttpResponse execute = httpClient.execute(httpPost);
  280 + HttpEntity res = execute.getEntity();
  281 + InputStream is = res.getContent();
  282 + int len;
  283 + byte[] buf = new byte[128];
  284 + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
  285 + while ((len = is.read(buf)) != -1) {
  286 + byteArrayOutputStream.write(buf, 0, len);
  287 + }
  288 + result = byteArrayOutputStream.toString();
  289 + } catch (IOException e) {
  290 + e.printStackTrace();
  291 + }
  292 + return result;
  293 + }
  294 +}
... ...
... ... @@ -3,6 +3,15 @@ spring:
3 3 name: iot-scheduler
4 4 main:
5 5 banner-mode: off
  6 + data:
  7 + redis:
  8 + cluster:
  9 + nodes: # 集群节点列表
  10 + - 10.9.1.252:16380
  11 + - 10.9.1.252:16381
  12 + - 10.9.1.252:16382
  13 + max-redirects: 3 # 最大重定向次数
  14 + password: "Qixiao@redis20240410.com" # 如果有密码
6 15
7 16 server:
8 17 port: 8080
... ... @@ -24,3 +33,17 @@ scheduler:
24 33 panji:
25 34 pull: "0 0/5 * * * ?"
26 35 push: "0 0/10 * * * ?"
  36 +
  37 +device:
  38 + token:
  39 + url: "https://iotgc.cniot.vip/auth/token"
  40 + userName: "guests"
  41 + password: "Lingzhi"
  42 + info:
  43 + url: "https://iotgc.cniot.vip/triColorLamp/userGroupDtuSns"
  44 + detail:
  45 + url: "https://iotgc.cniot.vip/triColorLamp/dtuSnState"
  46 + energyInfo:
  47 + url: "https://iotgc.cniot.vip/api/energy/userGroupDtuSns"
  48 + energyDetail:
  49 + url: "https://iotgc.cniot.vip/api/energy/dtuSnRateEnergy"
... ...