BjkjDevicePullService.java 15.5 KB
package com.iot.scheduler.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.iot.scheduler.model.DeviceToken;
import com.iot.scheduler.model.QxDeviceInfo;
import com.iot.scheduler.model.QxDeviceInfoDetail;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
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.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.util.UriComponentsBuilder;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 博晶科技(滁州)有限公司应用数据同步
 */
@Slf4j
@Service
public class BjkjDevicePullService {

    @Value("${bjkj.iot.organizeId:}")
    private String iotOrganizeId;
    @Value("${bjkj.iot.profileId}")
    private String iotProfileId;
    @Value("${bjkj.iot.deviceProfileId}")
    private String iotDeviceProfileId;
    @Value("${bjkj.iot.userName:}")
    private String iotUserName;
    @Value("${bjkj.iot.password:}")
    private String iotPassword;
    @Value("${bjkj.iot.tokenUrl}")
    private String iotTokenUrl;
    @Value("${bjkj.iot.infoUrl}")
    private String iotDeviceInfoUrl;
    @Value("${bjkj.iot.detailUrl}")
    private String iotDeviceDetailUrl;

    @Value("${device.token.url}")
    private String deviceTokenUrl;
    @Value("${bjkj.device.token.userName}")
    private String deviceUserName;
    @Value("${bjkj.device.token.password}")
    private String devicePassword;
    @Value("${device.info.url}")
    private String deviceInfoUrl;
    @Value("${device.detail.url}")
    private String deviceDetailUrl;

    final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    public void pullDeviceAndPushToIot() {
        String deviceResult = getDeviceInfo();
        Map<String, Object> deviceInfos = JSON.parseObject(deviceResult, new TypeReference<>() {
        });

        JSONArray deviceInfoList = (JSONArray) deviceInfos.get("data");
        List<QxDeviceInfo> qxDeviceInfos = new ArrayList<>();
        List<QxDeviceInfoDetail> qxAddDeviceInfoDetails = new ArrayList<>();
        Map<String, QxDeviceInfoDetail> qxDeviceInfoDetailMap = new HashMap<>();
        for (Object o : deviceInfoList) {
            JSONObject deviceInfoJson = (JSONObject) o;
            QxDeviceInfo qxDeviceInfo = new QxDeviceInfo();
            qxDeviceInfo.setDeviceType("DIRECT_CONNECTION");
            qxDeviceInfo.setTransportType("DEFAULT");
            qxDeviceInfo.setOrganizationId(iotOrganizeId);
            qxDeviceInfo.setDeviceProfileId(iotDeviceProfileId);
            qxDeviceInfo.setProfileId(iotProfileId);
//            //项目状态(1:在线,2:离线,3:报警)
//            Integer projectState = deviceInfoJson.getInteger("projectState");
//            if (projectState != null) {
//                qxDeviceInfo.setDescription(String.valueOf(projectState));
//            }

            //项目类型
            qxDeviceInfo.setLabel("生产设备");
            //设备名称
            String deviceName = deviceInfoJson.getString("deviceName");

            qxDeviceInfo.setName(deviceName);
            qxDeviceInfo.setBrand(deviceName);
            //序列号
            String dtuSn = deviceInfoJson.getString("dtuSn");
            qxDeviceInfo.setSn(dtuSn);

            DeviceToken deviceToken = new DeviceToken();
            deviceToken.setCredentialsType("ACCESS_TOKEN");
            deviceToken.setCredentialsId(dtuSn);
            deviceToken.setCredentialsValue(dtuSn);
            qxDeviceInfo.setDeviceToken(deviceToken);
            qxDeviceInfos.add(qxDeviceInfo);
            //有序列号直接获取灯信息
            if (StringUtils.isNotBlank(dtuSn)) {
                String deviceInfoDetails = getDeviceInfoDetail(dtuSn);
                if (StringUtils.isBlank(deviceInfoDetails)) {
                    continue;
                }

                Map<String, Object> deviceInfoDetailMap = JSON.parseObject(deviceInfoDetails, new TypeReference<>() {
                });

                JSONArray deviceInfoDetailList = (JSONArray) deviceInfoDetailMap.get("data");
                if (CollectionUtils.isEmpty(deviceInfoDetailList)) {
                    continue;
                }

                JSONObject deviceInfoDetailJson = (JSONObject) deviceInfoDetailList.get(0);
                //灯详情数据
                //序列号
                String dtuSnDetail = deviceInfoDetailJson.getString("dtuSn");
                //开始时间
                String startTime = deviceInfoDetailJson.getString("startTime");
                QxDeviceInfoDetail qxDeviceInfoDetail = new QxDeviceInfoDetail();
                qxDeviceInfoDetail.setAlarm(0);
                //灯状态(0:灭灯,1:红,2:黄,3:绿,4:蓝)
                Integer lampState = deviceInfoDetailJson.getInteger("lampState");
                switch (lampState) {
                    case 0:
                        qxDeviceInfoDetail.setStatus("OFF");
                        break;
                    case 1:
                        qxDeviceInfoDetail.setStatus("ERROR");
                        qxDeviceInfoDetail.setAlarm(1);
                        break;
                    case 2:
                        qxDeviceInfoDetail.setStatus("STAND");
                        break;
                    case 3:
                        qxDeviceInfoDetail.setStatus("RUN");
                        break;
                    default:
                        continue;
                }

                if (StringUtils.isNotBlank(startTime)) {
                    try {
                        qxDeviceInfoDetail.setStartTime(dateFormat.parse(startTime));
                    } catch (Exception e) {
                        log.error("时间格式出错");
                        qxDeviceInfoDetail.setStartTime(new Date());
                    }
                } else {
                    qxDeviceInfoDetail.setStartTime(new Date());
                }

                qxDeviceInfoDetail.setDtuSn(dtuSn);
                qxDeviceInfoDetailMap.put(dtuSn, qxDeviceInfoDetail);
                qxAddDeviceInfoDetails.add(qxDeviceInfoDetail);
            }
        }

        //将数据同步到IOT平台
        Map<String, String> qxParam = new HashMap<>(2);
        qxParam.put("username", iotUserName);
        qxParam.put("password", iotPassword);

        HttpPost qxHttpPost = new HttpPost(iotTokenUrl);
        String qxResult = sendPost(qxHttpPost, JSON.toJSONString(qxParam));
        if (StringUtils.isBlank(qxResult)) {
            return;
        }
        Map<String, Object> qxRes = JSON.parseObject(qxResult, new TypeReference<Map<String, Object>>() {
        });

        String qxAccessToken = (String) qxRes.get("token");
        if (StringUtils.isBlank(qxAccessToken)) {
            return;
        }

        BasicHeader qxAuthorization = new BasicHeader("X-Authorization", "Bearer " + qxAccessToken);
        if (!CollectionUtils.isEmpty(qxDeviceInfos)) {
            HttpPost qxDeviceInfoPost = new HttpPost(iotDeviceInfoUrl);
            qxDeviceInfoPost.addHeader(qxAuthorization);
            for (QxDeviceInfo qxDeviceInfo : qxDeviceInfos) {
                // todo
                String syncDeviceInfo = sendPost(qxDeviceInfoPost, JSON.toJSONString(qxDeviceInfo));
                //log.info("同步设备信息 syncDeviceInfo:{}", syncDeviceInfo);
            }
        }

        if (!CollectionUtils.isEmpty(qxAddDeviceInfoDetails)) {
            for (QxDeviceInfoDetail qxDeviceInfoDetail : qxAddDeviceInfoDetails) {
                String qxDeviceInfoDetailUrlStr = iotDeviceDetailUrl + qxDeviceInfoDetail.getDtuSn() + "/telemetry";
                HttpPost qxDeviceInfoDetailPost = new HttpPost(qxDeviceInfoDetailUrlStr);
                qxDeviceInfoDetailPost.addHeader(qxAuthorization);
                String syncDeviceInfoDetail = sendPost(qxDeviceInfoDetailPost, JSON.toJSONString(qxDeviceInfoDetail));
            }
        }
    }

    public String getDeviceInfoDetail(String dtuSn) {
        String accessToken = getAccessToken();
        Map<String, String> dtuSnOb = new HashMap<>(1);
        dtuSnOb.put("dtuSn", dtuSn);
        Map<String, String> headerMap = new HashMap<>(1);
        headerMap.put("Authorization", "Bearer " + accessToken);
        String deviceInfoDetail = sendRequestGet(deviceDetailUrl, dtuSnOb, headerMap);
        if (StringUtils.isBlank(deviceInfoDetail)) {
            return null;
        }

        Map<String, Object> deviceInfoDetailMap = JSON.parseObject(deviceInfoDetail,
                new TypeReference<>() {
                });
        Integer deviceInfoDetailCode = (Integer) deviceInfoDetailMap.get("code");
        if (deviceInfoDetailCode != 200) {
            return null;
        }

        JSONArray deviceInfoDetailList = (JSONArray) deviceInfoDetailMap.get("data");
        if (CollectionUtils.isEmpty(deviceInfoDetailList)) {
            return null;
        }

        JSONObject deviceInfoDetailJson = (JSONObject) deviceInfoDetailList.get(0);
        //灯详情数据
        //灯状态(0:灭灯,1:红,2:黄,3:绿,4:蓝)
        Integer lampState = deviceInfoDetailJson.getInteger("lampState");
        if (lampState == null) {
            return null;
        }

        return deviceInfoDetail;
    }

    public String getDeviceInfo() {
        String accessToken = getAccessToken();
        // 初始化headerMap并设置Authorization
        Map<String, String> headerMap = new HashMap<>(1);
        headerMap.put("Authorization", "Bearer " + accessToken);

        Map<String, String> paramsMap = new HashMap<>();
        paramsMap.put("groupName", "默认组织");

        // 第一次请求设备信息
        String deviceResult = sendRequestGet(deviceInfoUrl, paramsMap, headerMap);

        // 检查设备信息是否为空
        if (StringUtils.isBlank(deviceResult)) {
            return null;
        }

        // 解析设备信息
        Map<String, Object> deviceInfos = JSON.parseObject(deviceResult, new TypeReference<>() {
        });
        Integer deviceInfoCode = (Integer) deviceInfos.get("code");

        // 如果code不为200,可能是accessToken失效,重新获取token并重试
        if (deviceInfoCode != 200) {
            accessToken = getAccessToken();
            if (StringUtils.isEmpty(accessToken)) {
                return null;
            }

            // 更新headerMap中的Authorization
            headerMap.put("Authorization", "Bearer " + accessToken);

            // 第二次请求设备信息
            deviceResult = sendRequestGet(deviceInfoUrl, paramsMap, headerMap);
            if (StringUtils.isBlank(deviceResult)) {
                return null;
            }

            // 重新解析设备信息
            deviceInfos = JSON.parseObject(deviceResult, new TypeReference<>() {
            });
            deviceInfoCode = (Integer) deviceInfos.get("code");

            // 如果第二次请求仍然失败,返回错误信息
            if (deviceInfoCode != 200) {
                return null;
            }
        }

        // 返回成功的设备信息
        return deviceResult;
    }

    private String getAccessToken() {
        String accessToken = "";
        String redisKey = "bjkj_device_token";
        if (StringUtils.isNotBlank(redisTemplate.opsForValue().get(redisKey)) && redisTemplate.getExpire(redisKey) > 0) {
            return redisTemplate.opsForValue().get(redisKey);
        }

        Map<String, String> param = new HashMap<>(2);
        param.put("username", deviceUserName);
        param.put("password", devicePassword);
        HttpPost httpPost = new HttpPost(deviceTokenUrl);
        String result = sendPost(httpPost, JSON.toJSONString(param));
        if (StringUtils.isBlank(result)) {
            return accessToken;
        }

        Map<String, Object> res = JSON.parseObject(result, new TypeReference<>() {
        });

        Integer code = (Integer) res.get("code");
        if (code == 200) {
            JSONObject data = (JSONObject) res.get("data");
            accessToken = (String) data.get("token");
            redisTemplate.opsForValue().set(redisKey, accessToken, 3600, TimeUnit.SECONDS); // 一小时过期
        }

        return accessToken;
    }

    public static String sendRequestGet(String url, Map<String, String> params, Map<String, String> header) {
        //实例化httpclient
        CloseableHttpClient httpclient = HttpClients.createDefault();
        url = builderUrl(url, params);
        //请求结果
        String content = "";
        //实例化get方法
        HttpGet httpget = new HttpGet(url);
        if (!CollectionUtils.isEmpty(header)) {
            for (Map.Entry<String, String> entry : header.entrySet()) {
                httpget.setHeader(entry.getKey(), entry.getValue());
            }
        }

        try (CloseableHttpResponse response = httpclient.execute(httpget)) {

            //执行get方法
            if (response.getStatusLine().getStatusCode() == 200) {
                content = EntityUtils.toString(response.getEntity(), "UTF-8");
            }
        } catch (IOException e) {
            log.error("sendRequest---GET Error!", e);
        }
        return content;
    }

    private static String builderUrl(String url, Map<String, String> params) {
        UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(url);
        if (!CollectionUtils.isEmpty(params)) {
            MultiValueMap<String, String> paramsValue = new LinkedMultiValueMap<>();
            for (Map.Entry<String, String> entry : params.entrySet()) {
                paramsValue.add(entry.getKey(), entry.getValue());
            }

            uriBuilder = uriBuilder.queryParams(paramsValue);
        }

        return uriBuilder.toUriString();
    }

    private String sendPost(HttpPost httpPost, String jsonData) {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        StringEntity entity = new StringEntity(jsonData, ContentType.create("application/json", Consts.UTF_8));
        httpPost.setEntity(entity);
        String result = null;
        try {
            CloseableHttpResponse execute = httpClient.execute(httpPost);
            HttpEntity res = execute.getEntity();
            InputStream is = res.getContent();
            int len;
            byte[] buf = new byte[128];
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            while ((len = is.read(buf)) != -1) {
                byteArrayOutputStream.write(buf, 0, len);
            }
            result = byteArrayOutputStream.toString();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }
}