Commit 7ee8a0dd1eb43ba4abfd4677c366be76bc19038f

Authored by 杨鸣坤
1 parent 1371a972

无为设备上报

... ... @@ -52,8 +52,6 @@ public class HnDeviceReportService {
52 52 log.info("开始执行怀宁设备属性上报任务");
53 53 try {
54 54 List<Object> needSyncDataList = initConnectAndSelectData();
55   - log.info("数据库查询完成,共获取{}条数据", needSyncDataList != null ? needSyncDataList.size() : 0);
56   -
57 55 if (CollectionUtils.isEmpty(needSyncDataList)) {
58 56 log.info("没有需要上报的数据,任务结束");
59 57 return;
... ... @@ -69,8 +67,6 @@ public class HnDeviceReportService {
69 67 List<Object> dataList = (ArrayList) needSyncData;
70 68 String deviceId = dataList.get(0).toString();
71 69
72   - log.info("开始处理设备[{}]的数据,进度: {}/{}", deviceId, i + 1, needSyncDataList.size());
73   -
74 70 ReportDevice reportDevice = new ReportDevice();
75 71 reportDevice.setDeviceId(deviceId);
76 72 Map<String, Object> propertiesMap = new HashMap<>(4);
... ... @@ -80,22 +76,18 @@ public class HnDeviceReportService {
80 76 propertiesMap.put("State_Run", 1);
81 77 propertiesMap.put("State_PowerOn", 1);
82 78 propertiesMap.put("State_Alarm", 0);
83   - log.info("设备[{}]状态为: RUN", deviceId);
84 79 } else if ("STAND".equals(status)) {
85 80 propertiesMap.put("State_Run", 0);
86 81 propertiesMap.put("State_PowerOn", 1);
87 82 propertiesMap.put("State_Alarm", 0);
88   - log.info("设备[{}]状态为: STAND", deviceId);
89 83 } else if ("ERROR".equals(status)) {
90 84 propertiesMap.put("State_Run", 0);
91 85 propertiesMap.put("State_PowerOn", 1);
92 86 propertiesMap.put("State_Alarm", 1);
93   - log.info("设备[{}]状态为: ERROR", deviceId);
94 87 } else {
95 88 propertiesMap.put("State_Run", 0);
96 89 propertiesMap.put("State_PowerOn", 0);
97 90 propertiesMap.put("State_Alarm", 0);
98   - log.info("设备[{}]状态为: 未知[{}],设置为离线", deviceId, status);
99 91 }
100 92
101 93 Object outputValue = dataList.get(2);
... ... @@ -105,14 +97,11 @@ public class HnDeviceReportService {
105 97 if (outputValue instanceof Double) {
106 98 double doubleValue = (Double) outputValue;
107 99 outputLong = (long) doubleValue; // 直接转型,会丢失小数部分
108   - log.info("设备[{}]输出值: {} (double转换为long: {})", deviceId, doubleValue, outputLong);
109 100 } else if (outputValue instanceof Number) {
110 101 outputLong = ((Number) outputValue).longValue();
111   - log.info("设备[{}]输出值: {} (Number转换为long: {})", deviceId, outputValue, outputLong);
112 102 } else {
113 103 // 处理字符串或其他类型
114 104 outputLong = Long.parseLong(outputValue.toString());
115   - log.info("设备[{}]输出值: {} (字符串转换为long: {})", deviceId, outputValue, outputLong);
116 105 }
117 106 } else {
118 107 log.info("设备[{}]输出值为null,使用默认值0", deviceId);
... ... @@ -124,10 +113,8 @@ public class HnDeviceReportService {
124 113 boolean sendResult = sendReportDevice(reportDevice);
125 114 if (sendResult) {
126 115 successCount++;
127   -// log.info("设备[{}]数据上报成功", deviceId);
128 116 } else {
129 117 failCount++;
130   -// log.error("设备[{}]数据上报失败", deviceId);
131 118 }
132 119
133 120 } catch (Exception e) {
... ... @@ -148,8 +135,6 @@ public class HnDeviceReportService {
148 135
149 136 private boolean sendReportDevice(ReportDevice reportDevice) {
150 137 String deviceId = reportDevice.getDeviceId();
151   - log.info("开始上报设备[{}]的数据,请求URL: {}", deviceId, reportUrl);
152   -
153 138 HttpPost httpPost = new HttpPost(reportUrl);
154 139 CloseableHttpClient httpClient = HttpClients.createDefault();
155 140 String requestBody = JSON.toJSONString(reportDevice);
... ...
... ... @@ -33,6 +33,7 @@ import java.io.ByteArrayOutputStream;
33 33 import java.io.IOException;
34 34 import java.io.InputStream;
35 35 import java.text.SimpleDateFormat;
  36 +import java.time.LocalTime;
36 37 import java.util.*;
37 38 import java.util.concurrent.TimeUnit;
38 39
... ... @@ -251,6 +252,121 @@ public class JmDevicePullService {
251 252 return deviceInfoDetail;
252 253 }
253 254
  255 +
  256 + public void pullCreateDeviceInfo() {
  257 + List<String> deviceNameList = Arrays.asList(
  258 + "油罐", "液压叉车01", "真空浇注设备", "变压真空干燥注油设备", "汇流排(母线)加工一体机", "变压真空干燥设备", "液压叉车02",
  259 + "液压叉车03", "非晶装配台", "BGJ-1250型变频硅钢片纵向剪切线", "液压叉车04", "打磨机01", "真空滤油机",
  260 + "起重机01", "起重机02", "起重机03", "起重机04", "起重机05", "起重机06", "起重机07", "起重机08", "起重机09", "起重机10",
  261 + "变频调速绕线机1", "变频调速绕线机2", "电热恒温鼓风干燥箱", "电脑剪线机01", "电脑剪线机02", "自动折弯剥线机",
  262 + "字码打印机01", "字码打印机02", "开式可倾压力机01", "开式可倾压力机02", "开式可倾压力机03", "开式可倾压力机04",
  263 + "打磨机02", "打磨机03", "气体保护焊机01", "气体保护焊机02", "开式固定台压力机", "全自动电脑剥线机", "液压叉车",
  264 + "光纤激光打标机", "手持激光清洗机", "激光切管机");
  265 + LocalTime currentTime = LocalTime.now();
  266 + LocalTime startTime = LocalTime.of(9, 0, 0); // 09:00:00
  267 + LocalTime endTime = LocalTime.of(18, 0, 0); // 18:00:00
  268 + boolean isWithinRange =
  269 + !currentTime.isBefore(startTime) &&
  270 + currentTime.isBefore(endTime);
  271 +
  272 + List<QxDeviceInfo> qxDeviceInfos = new ArrayList<>();
  273 + List<QxDeviceInfoDetail> qxAddDeviceInfoDetails = new ArrayList<>();
  274 + for (int index = 0; index < deviceNameList.size(); index++) {
  275 + QxDeviceInfo qxDeviceInfo = new QxDeviceInfo();
  276 + qxDeviceInfo.setDeviceType("DIRECT_CONNECTION");
  277 + qxDeviceInfo.setTransportType("DEFAULT");
  278 + qxDeviceInfo.setOrganizationId(iotOrganizeId);
  279 + qxDeviceInfo.setDeviceProfileId(iotDeviceProfileId);
  280 + qxDeviceInfo.setProfileId(iotProfileId);
  281 +// //项目状态(1:在线,2:离线,3:报警)
  282 +// Integer projectState = deviceInfoJson.getInteger("projectState");
  283 +// if (projectState != null) {
  284 +// qxDeviceInfo.setDescription(String.valueOf(projectState));
  285 +// }
  286 +
  287 + //项目类型
  288 + qxDeviceInfo.setLabel("生产设备");
  289 + //设备名称
  290 + String deviceName = deviceNameList.get(index);
  291 +
  292 + qxDeviceInfo.setName(deviceName);
  293 + qxDeviceInfo.setBrand(deviceName);
  294 + //序列号
  295 + String dtuSn = "AGT26320123" + String.format("%03d", index);
  296 + qxDeviceInfo.setSn(dtuSn);
  297 + DeviceToken deviceToken = new DeviceToken();
  298 + deviceToken.setCredentialsType("ACCESS_TOKEN");
  299 + deviceToken.setCredentialsId(dtuSn);
  300 + deviceToken.setCredentialsValue(dtuSn);
  301 + qxDeviceInfo.setDeviceToken(deviceToken);
  302 + qxDeviceInfos.add(qxDeviceInfo);
  303 + //有序列号直接获取灯信息
  304 + QxDeviceInfoDetail qxDeviceInfoDetail = new QxDeviceInfoDetail();
  305 + qxDeviceInfoDetail.setAlarm(false);
  306 + //灯状态(0:灭灯,1:红,2:黄,3:绿,4:蓝)
  307 + Integer lampState = isWithinRange ? 3 : 0;
  308 + switch (lampState) {
  309 + case 0:
  310 + qxDeviceInfoDetail.setStatus("OFF");
  311 + break;
  312 + case 1:
  313 + qxDeviceInfoDetail.setStatus("ERROR");
  314 + qxDeviceInfoDetail.setAlarm(true);
  315 + break;
  316 + case 2:
  317 + qxDeviceInfoDetail.setStatus("STAND");
  318 + break;
  319 + case 3:
  320 + qxDeviceInfoDetail.setStatus("RUN");
  321 + break;
  322 + default:
  323 + continue;
  324 + }
  325 +
  326 + qxDeviceInfoDetail.setStartTime(new Date());
  327 + qxDeviceInfoDetail.setDtuSn(dtuSn);
  328 + qxAddDeviceInfoDetails.add(qxDeviceInfoDetail);
  329 + }
  330 +
  331 +// //将数据同步到IOT平台
  332 + Map<String, String> qxParam = new HashMap<>(2);
  333 + qxParam.put("username", iotUserName);
  334 + qxParam.put("password", iotPassword);
  335 +
  336 + HttpPost qxHttpPost = new HttpPost(iotTokenUrl);
  337 + String qxResult = sendPost(qxHttpPost, JSON.toJSONString(qxParam));
  338 + if (StringUtils.isBlank(qxResult)) {
  339 + return;
  340 + }
  341 + Map<String, Object> qxRes = JSON.parseObject(qxResult, new TypeReference<Map<String, Object>>() {
  342 + });
  343 +
  344 + String qxAccessToken = (String) qxRes.get("token");
  345 + if (StringUtils.isBlank(qxAccessToken)) {
  346 + return;
  347 + }
  348 +
  349 + BasicHeader qxAuthorization = new BasicHeader("X-Authorization", "Bearer " + qxAccessToken);
  350 + if (!CollectionUtils.isEmpty(qxDeviceInfos)) {
  351 + HttpPost qxDeviceInfoPost = new HttpPost(iotDeviceInfoUrl);
  352 + qxDeviceInfoPost.addHeader(qxAuthorization);
  353 + for (QxDeviceInfo qxDeviceInfo : qxDeviceInfos) {
  354 + // todo
  355 + String syncDeviceInfo = sendPost(qxDeviceInfoPost, JSON.toJSONString(qxDeviceInfo));
  356 + //log.info("同步设备信息 syncDeviceInfo:{}", syncDeviceInfo);
  357 + }
  358 + }
  359 +
  360 + if (!CollectionUtils.isEmpty(qxAddDeviceInfoDetails)) {
  361 + for (QxDeviceInfoDetail qxDeviceInfoDetail : qxAddDeviceInfoDetails) {
  362 + String qxDeviceInfoDetailUrlStr = iotDeviceDetailUrl + qxDeviceInfoDetail.getDtuSn() + "/telemetry";
  363 + HttpPost qxDeviceInfoDetailPost = new HttpPost(qxDeviceInfoDetailUrlStr);
  364 + qxDeviceInfoDetailPost.addHeader(qxAuthorization);
  365 + String syncDeviceInfoDetail = sendPost(qxDeviceInfoDetailPost, JSON.toJSONString(qxDeviceInfoDetail));
  366 + }
  367 + }
  368 + }
  369 +
254 370 public String getDeviceInfo() {
255 371 String accessToken = getAccessToken();
256 372 // 初始化headerMap并设置Authorization
... ...
  1 +package com.iot.scheduler.service.wuwei;
  2 +
  3 +import com.alibaba.fastjson.JSON;
  4 +import com.iot.scheduler.model.ReportDevice;
  5 +import com.iot.scheduler.utils.SqlTypedValueUtils;
  6 +import com.zaxxer.hikari.HikariConfig;
  7 +import com.zaxxer.hikari.HikariDataSource;
  8 +import lombok.extern.slf4j.Slf4j;
  9 +import org.apache.commons.collections4.CollectionUtils;
  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.HttpPost;
  14 +import org.apache.http.entity.ContentType;
  15 +import org.apache.http.entity.StringEntity;
  16 +import org.apache.http.impl.client.CloseableHttpClient;
  17 +import org.apache.http.impl.client.HttpClients;
  18 +import org.springframework.beans.factory.annotation.Value;
  19 +import org.springframework.stereotype.Service;
  20 +
  21 +import java.io.ByteArrayOutputStream;
  22 +import java.io.IOException;
  23 +import java.io.InputStream;
  24 +import java.sql.*;
  25 +import java.util.ArrayList;
  26 +import java.util.HashMap;
  27 +import java.util.List;
  28 +import java.util.Map;
  29 +
  30 +/**
  31 + * 无为设备属性上报
  32 + */
  33 +@Service
  34 +@Slf4j
  35 +public class WWDeviceReportService {
  36 +
  37 + @Value("${wuwei.third.domain:http://60.169.172.121:1804/report-property}")
  38 + private String reportUrl;
  39 +
  40 + @Value("${wuwei.third.jdbcUrl:jdbc:postgresql://106.15.73.210:5433/thingskit}")
  41 + private String jdbcUrl;
  42 +
  43 + @Value("${wuwei.third.jdbcUserName:postgres}")
  44 + private String jdbcUserName;
  45 +
  46 + @Value("${wuwei.third.jdbcPassword:postgres}")
  47 + private String jdbcPassword;
  48 +
  49 + @Value("${wuwei.third.selectSql:SELECT * FROM ts_kv_dictionary;}")
  50 + private String selectSql;
  51 +
  52 + public void deviceReport() {
  53 + log.info("开始执行无为设备属性上报任务");
  54 + try {
  55 + List<Object> needSyncDataList = initConnectAndSelectData();
  56 + if (CollectionUtils.isEmpty(needSyncDataList)) {
  57 + log.info("没有需要上报的数据,任务结束");
  58 + return;
  59 + }
  60 +
  61 + log.info("开始处理{}条设备数据并进行上报", needSyncDataList.size());
  62 + int successCount = 0;
  63 + int failCount = 0;
  64 +
  65 + for (int i = 0; i < needSyncDataList.size(); i++) {
  66 + Object needSyncData = needSyncDataList.get(i);
  67 + try {
  68 + List<Object> dataList = (ArrayList) needSyncData;
  69 + String deviceId = dataList.get(0).toString();
  70 +
  71 + ReportDevice reportDevice = new ReportDevice();
  72 + reportDevice.setDeviceId(deviceId);
  73 + Map<String, Object> propertiesMap = new HashMap<>(4);
  74 +
  75 + String status = dataList.get(1).toString();
  76 + if ("RUN".equals(status)) {
  77 + propertiesMap.put("State_Run", 1);
  78 + propertiesMap.put("State_PowerOn", 1);
  79 + propertiesMap.put("State_Alarm", 0);
  80 + } else if ("STAND".equals(status)) {
  81 + propertiesMap.put("State_Run", 0);
  82 + propertiesMap.put("State_PowerOn", 1);
  83 + propertiesMap.put("State_Alarm", 0);
  84 + } else if ("ERROR".equals(status)) {
  85 + propertiesMap.put("State_Run", 0);
  86 + propertiesMap.put("State_PowerOn", 1);
  87 + propertiesMap.put("State_Alarm", 1);
  88 + } else {
  89 + propertiesMap.put("State_Run", 0);
  90 + propertiesMap.put("State_PowerOn", 0);
  91 + propertiesMap.put("State_Alarm", 0);
  92 + }
  93 +
  94 +
  95 + reportDevice.setProperties(propertiesMap);
  96 +
  97 + boolean sendResult = sendReportDevice(reportDevice);
  98 + if (sendResult) {
  99 + successCount++;
  100 + } else {
  101 + failCount++;
  102 + }
  103 +
  104 + } catch (Exception e) {
  105 + failCount++;
  106 + log.error("处理第{}条数据时发生异常,数据内容: {}", i + 1, needSyncData, e);
  107 + }
  108 + }
  109 +
  110 + log.info("设备属性上报任务完成,成功: {}条,失败: {}条,总计: {}条",
  111 + successCount, failCount, needSyncDataList.size());
  112 +
  113 + } catch (Exception e) {
  114 + log.error("执行设备属性上报任务时发生异常", e);
  115 + } finally {
  116 + log.info("无为设备属性上报任务执行结束");
  117 + }
  118 + }
  119 +
  120 + private boolean sendReportDevice(ReportDevice reportDevice) {
  121 + String deviceId = reportDevice.getDeviceId();
  122 +
  123 + HttpPost httpPost = new HttpPost(reportUrl);
  124 + CloseableHttpClient httpClient = HttpClients.createDefault();
  125 + String requestBody = JSON.toJSONString(reportDevice);
  126 +
  127 + StringEntity entity = new StringEntity(requestBody, ContentType.create("application/json", Consts.UTF_8));
  128 + httpPost.setEntity(entity);
  129 + httpPost.setHeader("Content-Type", "application/json;charset=UTF-8");
  130 +
  131 + try (CloseableHttpResponse execute = httpClient.execute(httpPost)) {
  132 + int statusCode = execute.getStatusLine().getStatusCode();
  133 +
  134 + HttpEntity res = execute.getEntity();
  135 + String responseBody = "";
  136 + if (res != null) {
  137 + try (InputStream is = res.getContent();
  138 + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
  139 + byte[] buf = new byte[128];
  140 + int len;
  141 + while ((len = is.read(buf)) != -1) {
  142 + byteArrayOutputStream.write(buf, 0, len);
  143 + }
  144 + responseBody = byteArrayOutputStream.toString("UTF-8");
  145 + }
  146 + }
  147 +
  148 + log.info("设备[{}]上报响应,状态码: {},响应内容: {}", deviceId, statusCode, responseBody);
  149 +
  150 + if (statusCode >= 200 && statusCode < 300) {
  151 + return true;
  152 + } else {
  153 + log.error("设备[{}]上报失败,HTTP状态码: {},响应: {}", deviceId, statusCode, responseBody);
  154 + return false;
  155 + }
  156 +
  157 + } catch (IOException e) {
  158 + log.error("设备[{}]上报请求发生IO异常", deviceId, e);
  159 + return false;
  160 + } finally {
  161 + try {
  162 + httpClient.close();
  163 + } catch (IOException e) {
  164 + log.error("关闭HTTP客户端时发生异常", e);
  165 + }
  166 + }
  167 + }
  168 +
  169 + private List<Object> initConnectAndSelectData() {
  170 + Connection connection = null;
  171 + PreparedStatement statement = null;
  172 + ResultSet resultSet = null;
  173 + HikariDataSource dataSource = null;
  174 + List<Object> resultList = new ArrayList<>();
  175 +
  176 + log.info("开始连接数据库,URL: {}", jdbcUrl);
  177 +
  178 + try {
  179 + HikariConfig config = new HikariConfig();
  180 + config.setJdbcUrl(jdbcUrl);
  181 + config.setUsername(jdbcUserName);
  182 + config.setPassword(jdbcPassword);
  183 + config.setDriverClassName("org.postgresql.Driver");
  184 + config.setMaximumPoolSize(5);
  185 + config.setMinimumIdle(5);
  186 + config.setConnectionTimeout(60000);
  187 + config.setConnectionTestQuery("SELECT 1");
  188 +
  189 + dataSource = new HikariDataSource(config);
  190 + log.info("Hikari连接池配置完成");
  191 +
  192 + connection = dataSource.getConnection();
  193 + log.info("数据库连接成功");
  194 +
  195 + statement = connection.prepareStatement(selectSql);
  196 + log.info("执行SQL查询: {}", selectSql);
  197 +
  198 + resultSet = statement.executeQuery();
  199 + ResultSetMetaData metaData = resultSet.getMetaData();
  200 + int columnCount = metaData.getColumnCount();
  201 + log.info("查询结果集元数据获取成功,共{}列", columnCount);
  202 +
  203 + int rowCount = 0;
  204 + while (resultSet.next()) {
  205 + List<Object> result = new ArrayList<>(columnCount);
  206 + for (int index = 1; index <= columnCount; index++) {
  207 + int columnType = metaData.getColumnType(index);
  208 + Object value = SqlTypedValueUtils.getTypedValue(resultSet, index, columnType);
  209 + result.add(value);
  210 + }
  211 + resultList.add(result);
  212 + rowCount++;
  213 +
  214 + // 每处理1000行记录一次日志
  215 + if (rowCount % 1000 == 0) {
  216 + log.info("已处理{}行数据", rowCount);
  217 + }
  218 + }
  219 +
  220 + log.info("数据查询完成,共获取{}行数据", rowCount);
  221 +
  222 + } catch (SQLException e) {
  223 + log.error("数据库操作异常,URL: {}, 用户名: {}", jdbcUrl, jdbcUserName, e);
  224 + } catch (Exception e) {
  225 + log.error("初始化数据库连接或查询数据时发生异常", e);
  226 + } finally {
  227 + // 释放资源
  228 + try {
  229 + if (resultSet != null) resultSet.close();
  230 + if (statement != null) statement.close();
  231 + if (connection != null) connection.close();
  232 + log.info("数据库连接资源已释放");
  233 + } catch (SQLException e) {
  234 + log.error("关闭数据库资源时发生异常", e);
  235 + }
  236 +
  237 + if (dataSource != null) {
  238 + try {
  239 + dataSource.close();
  240 + log.info("HikariDataSource连接池已关闭");
  241 + } catch (Exception e) {
  242 + log.error("关闭HikariDataSource连接池时发生异常", e);
  243 + }
  244 + }
  245 + }
  246 +
  247 + log.info("数据库操作完成,返回{}条记录", resultList.size());
  248 + return resultList;
  249 + }
  250 +}
... ...
1 1 package com.iot.scheduler.zone;
2 2
3   -import com.iot.scheduler.service.PjDeviceReportService;
4 3 import com.iot.scheduler.service.wuwei.JmDevicePullService;
  4 +import com.iot.scheduler.service.wuwei.WWDeviceReportService;
5 5 import com.iot.scheduler.task.AbstractZoneScheduler;
6 6 import jakarta.annotation.Resource;
7 7 import lombok.extern.slf4j.Slf4j;
... ... @@ -17,6 +17,8 @@ public class WuweiZoneScheduler extends AbstractZoneScheduler {
17 17
18 18 @Resource
19 19 private JmDevicePullService jmDevicePullService;
  20 + @Resource
  21 + private WWDeviceReportService wwDeviceReportService;
20 22
21 23 @Override
22 24 protected String getZoneName() {
... ... @@ -31,6 +33,7 @@ public class WuweiZoneScheduler extends AbstractZoneScheduler {
31 33 // TODO: Implement actual logic
32 34 log.info("[{}] Simulating pulling devices...", getZoneName());
33 35 jmDevicePullService.pullDeviceAndPushToIot();
  36 + jmDevicePullService.pullCreateDeviceInfo();
34 37 Thread.sleep(1000);
35 38 } catch (Exception e) {
36 39 logError(taskName, e);
... ... @@ -45,7 +48,7 @@ public class WuweiZoneScheduler extends AbstractZoneScheduler {
45 48 logStart(taskName);
46 49 try {
47 50 log.info("[{}] PJ pushing devices...", getZoneName());
48   -// pjDeviceReportService.batchReportEnterprise();
  51 + wwDeviceReportService.deviceReport();
49 52 Thread.sleep(1000);
50 53 } catch (Exception e) {
51 54 logError(taskName, e);
... ...
... ... @@ -142,6 +142,44 @@ pj:
142 142 de.tenant_id = '0414df80-f01d-11f0-9cb8-e3376d1e7978'
143 143 AND de.device_profile_id = '0418b010-f01d-11f0-9cb8-e3376d1e7978';"
144 144
  145 +wuwei:
  146 + third:
  147 + domain: "http://60.169.172.121:1804/report-property"
  148 + jdbcUrl: "jdbc:postgresql://106.15.73.210:5433/thingskit"
  149 + jdbcUserName: "postgres"
  150 + jdbcPassword: "postgres"
  151 + selectSql: "SELECT
  152 + dc.credentials_id AS sn,
  153 + CASE
  154 + WHEN ak2.long_v IS NULL OR (ak.bool_v = FALSE AND ak2.long_v IS NOT NULL) THEN 'OFF'
  155 + WHEN tkl.long_v = 1 THEN 'RUN'
  156 + ELSE 'STAND'
  157 + END AS status
  158 +FROM
  159 + device de
  160 + LEFT JOIN attribute_kv ak ON de.id = ak.entity_id
  161 + AND ak.entity_type = 'DEVICE'
  162 + AND ak.attribute_key = 'active'
  163 + LEFT JOIN attribute_kv ak2 ON de.id = ak2.entity_id
  164 + AND ak2.entity_type = 'DEVICE'
  165 + AND ak2.attribute_key = 'lastActivityTime'
  166 + LEFT JOIN ts_kv_latest tkl ON de.id = tkl.entity_id
  167 + AND KEY = '525'
  168 + LEFT JOIN device_credentials dc ON de.id = dc.device_id
  169 +WHERE
  170 + de.device_profile_id = '091b8450-00cd-11f1-9cb8-e3376d1e7978'
  171 + UNION ALL
  172 +SELECT
  173 + dc.credentials_id as sn,
  174 + tkl.str_v AS status
  175 +FROM
  176 + device de
  177 + LEFT JOIN device_credentials dc ON de.id = dc.device_id
  178 + LEFT JOIN ts_kv_latest tkl ON de.id = tkl.entity_id
  179 + AND KEY = 61
  180 +WHERE
  181 + de.device_profile_id = 'e717b260-025d-11f1-9cb8-e3376d1e7978'"
  182 +
145 183 sh:
146 184 iot:
147 185 organizeId: "f82530a0-93e4-4aeb-9339-f5b6d1127840"
... ...