Commit 91786743a0f713d3d82c95309f1b967be054acde

Authored by 杨鸣坤
1 parent e1f88de4

怀宁上传设备sql修改,盛华纸业和国宏数据同步修改

... ... @@ -7,37 +7,35 @@ import com.alibaba.fastjson.TypeReference;
7 7 import com.iot.scheduler.model.DeviceToken;
8 8 import com.iot.scheduler.model.QxDeviceInfo;
9 9 import com.iot.scheduler.model.QxDeviceInfoDetail;
  10 +import com.iot.scheduler.utils.SqlTypedValueUtils;
  11 +import com.zaxxer.hikari.HikariConfig;
  12 +import com.zaxxer.hikari.HikariDataSource;
10 13 import jakarta.annotation.Resource;
11 14 import lombok.extern.slf4j.Slf4j;
12 15 import org.apache.commons.lang3.StringUtils;
13 16 import org.apache.http.Consts;
14 17 import org.apache.http.HttpEntity;
15 18 import org.apache.http.client.methods.CloseableHttpResponse;
16   -import org.apache.http.client.methods.HttpGet;
17 19 import org.apache.http.client.methods.HttpPost;
18 20 import org.apache.http.entity.ContentType;
19 21 import org.apache.http.entity.StringEntity;
20 22 import org.apache.http.impl.client.CloseableHttpClient;
21 23 import org.apache.http.impl.client.HttpClients;
22 24 import org.apache.http.message.BasicHeader;
23   -import org.apache.http.util.EntityUtils;
24 25 import org.springframework.beans.factory.annotation.Value;
25 26 import org.springframework.data.redis.core.RedisTemplate;
26 27 import org.springframework.stereotype.Service;
27 28 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 29
32 30 import java.io.ByteArrayOutputStream;
33 31 import java.io.IOException;
34 32 import java.io.InputStream;
35   -import java.text.SimpleDateFormat;
  33 +import java.sql.*;
36 34 import java.util.*;
37   -import java.util.concurrent.TimeUnit;
  35 +import java.util.Date;
38 36
39 37 /**
40   - * 双龙应用数据同步
  38 + * 国宏应用数据同步
41 39 */
42 40 @Slf4j
43 41 @Service
... ... @@ -61,6 +59,16 @@ public class GhDevicePullService {
61 59 private String iotDeviceDetailUrl;
62 60
63 61
  62 + @Value("${hn.third.jdbcUrl:jdbc:postgresql://106.15.73.210:5433/thingskit}")
  63 + private String jdbcUrl;
  64 +
  65 + @Value("${hn.third.jdbcUserName:postgres}")
  66 + private String jdbcUserName;
  67 +
  68 + @Value("${hn.third.jdbcPassword:postgres}")
  69 + private String jdbcPassword;
  70 +
  71 +
64 72 @Resource
65 73 private RedisTemplate<String, String> redisTemplate;
66 74
... ... @@ -72,7 +80,7 @@ public class GhDevicePullService {
72 80 for (Object o : deviceInfoList) {
73 81 JSONObject deviceInfoJson = (JSONObject) o;
74 82 QxDeviceInfo qxDeviceInfo = new QxDeviceInfo();
75   - qxDeviceInfo.setDeviceType("DIRECT_CONNECTION");
  83 + qxDeviceInfo.setDeviceType("SENSOR");
76 84 qxDeviceInfo.setTransportType("DEFAULT");
77 85 qxDeviceInfo.setOrganizationId(iotOrganizeId);
78 86 qxDeviceInfo.setDeviceProfileId(iotDeviceProfileId);
... ... @@ -110,20 +118,30 @@ public class GhDevicePullService {
110 118 case 1:
111 119 qxDeviceInfoDetail.setStatus("ERROR");
112 120 qxDeviceInfoDetail.setAlarm(true);
  121 + //先从缓存里面拿token信息
  122 + String totalCapacity = getTotalCapacity("gh_total_capacity_" + dtuSn, 0D);
  123 + qxDeviceInfoDetail.setCumulativeOutput(Double.valueOf(totalCapacity));
113 124 break;
114 125 case 2:
115 126 qxDeviceInfoDetail.setStatus("STAND");
  127 + //先从缓存里面拿token信息
  128 + totalCapacity = getTotalCapacity("gh_total_capacity_" + dtuSn, 0D);
  129 + qxDeviceInfoDetail.setCumulativeOutput(Double.valueOf(totalCapacity));
116 130 break;
117 131 case 3:
118 132 qxDeviceInfoDetail.setStatus("RUN");
119 133 //先从缓存里面拿token信息
120   - String totalCapacity = getTotalCapacity("gh_total_capacity_" + dtuSn);
  134 + totalCapacity = getTotalCapacity("gh_total_capacity_" + dtuSn, 200D);
121 135 qxDeviceInfoDetail.setCumulativeOutput(Double.valueOf(totalCapacity));
  136 + qxDeviceInfoDetail.setCapacity(200D);
122 137 break;
123 138 default:
124 139 continue;
125 140 }
126 141
  142 + if (lampState == 0) {
  143 + continue;
  144 + }
127 145
128 146 qxDeviceInfoDetail.setStartTime(new Date());
129 147 qxDeviceInfoDetail.setDtuSn(dtuSn);
... ... @@ -171,13 +189,122 @@ public class GhDevicePullService {
171 189 }
172 190
173 191 private JSONArray getDeviceInfo() {
  192 + Connection connection = null;
  193 + PreparedStatement statement = null;
  194 + ResultSet resultSet = null;
  195 + HikariDataSource dataSource = null;
  196 + List<Object> resultList = new ArrayList<>();
  197 +
  198 + log.info("开始连接数据库,URL: {}", jdbcUrl);
  199 +
  200 + try {
  201 + HikariConfig config = new HikariConfig();
  202 + config.setJdbcUrl(jdbcUrl);
  203 + config.setUsername(jdbcUserName);
  204 + config.setPassword(jdbcPassword);
  205 + config.setDriverClassName("org.postgresql.Driver");
  206 + config.setMaximumPoolSize(5);
  207 + config.setMinimumIdle(5);
  208 + config.setConnectionTimeout(60000);
  209 + config.setConnectionTestQuery("SELECT 1");
  210 +
  211 + dataSource = new HikariDataSource(config);
  212 + log.info("Hikari连接池配置完成");
  213 +
  214 + connection = dataSource.getConnection();
  215 + log.info("数据库连接成功");
  216 +
  217 + String selectSql = "SELECT\n" +
  218 + "de.name,\n" +
  219 + "dc.credentials_id,\n" +
  220 + "CASE\n" +
  221 + " WHEN ak2.long_v IS NULL OR (ak.bool_v = FALSE AND ak2.long_v IS NOT NULL) THEN 'OFF'\n" +
  222 + " WHEN tkl.long_v = 1 THEN 'ERROR'\n" +
  223 + " WHEN tkl2.long_v = 1 THEN 'STAND'\n" +
  224 + " WHEN tkl3.long_v = 1 THEN 'RUN'\n" +
  225 + " ELSE 'OFF'\n" +
  226 + " END AS status \n" +
  227 + "FROM device de \n" +
  228 + "LEFT JOIN ts_kv_latest tkl on de.id = tkl.entity_id AND tkl.key = '64'\n" +
  229 + "LEFT JOIN ts_kv_latest tkl2 on de.id = tkl2.entity_id AND tkl2.key = '535'\n" +
  230 + "LEFT JOIN ts_kv_latest tkl3 on de.id = tkl3.entity_id AND tkl3.key = '534'\n" +
  231 + "LEFT JOIN attribute_kv ak ON de.id = ak.entity_id AND ak.entity_type = 'DEVICE' AND ak.attribute_key = 'active'\n" +
  232 + "LEFT JOIN attribute_kv ak2 ON de.id = ak2.entity_id AND ak2.entity_type = 'DEVICE' AND ak2.attribute_key = 'lastActivityTime'\n" +
  233 + "LEFT JOIN device_credentials dc ON de.id = dc.device_id\n" +
  234 + "WHERE de.organization_id = '875a4841-c7f2-4e2c-88a2-ea62d4642132'\n" +
  235 + "AND de.device_profile_id = '1f2183a0-0562-11f1-9cb8-e3376d1e7978'\n";
  236 +
  237 + statement = connection.prepareStatement(selectSql);
  238 + log.info("执行SQL查询: {}", selectSql);
  239 +
  240 + resultSet = statement.executeQuery();
  241 + ResultSetMetaData metaData = resultSet.getMetaData();
  242 + int columnCount = metaData.getColumnCount();
  243 + log.info("查询结果集元数据获取成功,共{}列", columnCount);
  244 +
  245 + int rowCount = 0;
  246 + while (resultSet.next()) {
  247 + List<Object> result = new ArrayList<>(columnCount);
  248 + for (int index = 1; index <= columnCount; index++) {
  249 + int columnType = metaData.getColumnType(index);
  250 + Object value = SqlTypedValueUtils.getTypedValue(resultSet, index, columnType);
  251 + result.add(value);
  252 + }
  253 + resultList.add(result);
  254 + rowCount++;
  255 +
  256 + // 每处理1000行记录一次日志
  257 + if (rowCount % 1000 == 0) {
  258 + log.info("已处理{}行数据", rowCount);
  259 + }
  260 + }
  261 +
  262 + log.info("数据查询完成,共获取{}行数据", rowCount);
  263 +
  264 + } catch (SQLException e) {
  265 + log.error("数据库操作异常,URL: {}, 用户名: {}", jdbcUrl, jdbcUserName, e);
  266 + } catch (Exception e) {
  267 + log.error("初始化数据库连接或查询数据时发生异常", e);
  268 + } finally {
  269 + // 释放资源
  270 + try {
  271 + if (resultSet != null) resultSet.close();
  272 + if (statement != null) statement.close();
  273 + if (connection != null) connection.close();
  274 + log.info("数据库连接资源已释放");
  275 + } catch (SQLException e) {
  276 + log.error("关闭数据库资源时发生异常", e);
  277 + }
  278 +
  279 + if (dataSource != null) {
  280 + try {
  281 + dataSource.close();
  282 + log.info("HikariDataSource连接池已关闭");
  283 + } catch (Exception e) {
  284 + log.error("关闭HikariDataSource连接池时发生异常", e);
  285 + }
  286 + }
  287 + }
  288 +
  289 + log.info("数据库操作完成,返回{}条记录", resultList.size());
174 290 JSONArray jsonArray = new JSONArray();
175   - List<JSONObject> jsonObjectList = new ArrayList<>(13);
176   - for (int index = 1; index < 14; index++) {
  291 + List<JSONObject> jsonObjectList = new ArrayList<>(resultList.size());
  292 + for (Object result : resultList) {
  293 + List<Object> dataList = (ArrayList) result;
177 294 Map<String, Object> map = new HashMap<>(3);
178   - map.put("deviceName", "无纺布机组" + index);
179   - map.put("dtuSn", "AGH20260123" + String.format("%03d", index));
180   - map.put("lampState", 3);
  295 + map.put("deviceName", dataList.get(0));
  296 + map.put("dtuSn", dataList.get(1));
  297 + String status = dataList.get(2).toString();
  298 + if ("OFF".equals(status)) {
  299 + map.put("lampState", 0);
  300 + } else if ("ERROR".equals(status)) {
  301 + map.put("lampState", 1);
  302 + } else if ("STAND".equals(status)) {
  303 + map.put("lampState", 2);
  304 + } else if ("RUN".equals(status)) {
  305 + map.put("lampState", 3);
  306 + }
  307 +
181 308 JSONObject jsonObject = new JSONObject();
182 309 jsonObject.putAll(map);
183 310 jsonObjectList.add(jsonObject);
... ... @@ -185,11 +312,26 @@ public class GhDevicePullService {
185 312
186 313 jsonArray.addAll(jsonObjectList);
187 314 return jsonArray;
  315 +
  316 +// JSONArray jsonArray = new JSONArray();
  317 +// List<JSONObject> jsonObjectList = new ArrayList<>(13);
  318 +// for (int index = 1; index < 14; index++) {
  319 +// Map<String, Object> map = new HashMap<>(3);
  320 +// map.put("deviceName", "无纺布机组" + index);
  321 +// map.put("dtuSn", "AGH20260123" + String.format("%03d", index));
  322 +// map.put("lampState", 3);
  323 +// JSONObject jsonObject = new JSONObject();
  324 +// jsonObject.putAll(map);
  325 +// jsonObjectList.add(jsonObject);
  326 +// }
  327 +//
  328 +// jsonArray.addAll(jsonObjectList);
  329 +// return jsonArray;
188 330 }
189 331
190   - private String getTotalCapacity(String key) {
  332 +
  333 + private String getTotalCapacity(String key, Double production) {
191 334 String totalCapacity = redisTemplate.opsForValue().get(key);
192   - Double production = 100D;
193 335 Double totalCapacityD = 0D;
194 336 if (StringUtils.isEmpty(totalCapacity)) {
195 337 totalCapacityD = production;
... ...
... ... @@ -124,10 +124,10 @@ public class HnDeviceReportService {
124 124 boolean sendResult = sendReportDevice(reportDevice);
125 125 if (sendResult) {
126 126 successCount++;
127   - log.info("设备[{}]数据上报成功", deviceId);
  127 +// log.info("设备[{}]数据上报成功", deviceId);
128 128 } else {
129 129 failCount++;
130   - log.error("设备[{}]数据上报失败", deviceId);
  130 +// log.error("设备[{}]数据上报失败", deviceId);
131 131 }
132 132
133 133 } catch (Exception e) {
... ...
... ... @@ -151,19 +151,26 @@ public class ShDevicePullService {
151 151 switch (lampState) {
152 152 case 0:
153 153 qxDeviceInfoDetail.setStatus("OFF");
  154 + String totalCapacity = getTotalCapacity("total_capacity_" + dtuSn, 0D);
  155 + qxDeviceInfoDetail.setCumulativeOutput(Double.valueOf(totalCapacity));
154 156 break;
155 157 case 1:
156 158 qxDeviceInfoDetail.setStatus("ERROR");
157 159 qxDeviceInfoDetail.setAlarm(true);
  160 + totalCapacity = getTotalCapacity("total_capacity_" + dtuSn, 0D);
  161 + qxDeviceInfoDetail.setCumulativeOutput(Double.valueOf(totalCapacity));
158 162 break;
159 163 case 2:
160 164 qxDeviceInfoDetail.setStatus("STAND");
  165 + totalCapacity = getTotalCapacity("total_capacity_" + dtuSn, 0D);
  166 + qxDeviceInfoDetail.setCumulativeOutput(Double.valueOf(totalCapacity));
161 167 break;
162 168 case 3:
163 169 qxDeviceInfoDetail.setStatus("RUN");
164 170 //先从缓存里面拿token信息
165   - String totalCapacity = getTotalCapacity("total_capacity_" + dtuSn, highSpeed);
  171 + totalCapacity = getTotalCapacity("total_capacity_" + dtuSn, highSpeed ? 120D : 90D);
166 172 qxDeviceInfoDetail.setCumulativeOutput(Double.valueOf(totalCapacity));
  173 + qxDeviceInfoDetail.setCapacity(highSpeed ? 120D : 90D);
167 174 break;
168 175 default:
169 176 continue;
... ... @@ -225,9 +232,8 @@ public class ShDevicePullService {
225 232 }
226 233 }
227 234
228   - private String getTotalCapacity(String key, boolean highSpeedDevice) {
  235 + private String getTotalCapacity(String key, Double production) {
229 236 String totalCapacity = redisTemplate.opsForValue().get(key);
230   - Double production = highSpeedDevice ? 120D : 90D;
231 237 Double totalCapacityD = 0D;
232 238 if (StringUtils.isEmpty(totalCapacity)) {
233 239 totalCapacityD = production;
... ...
... ... @@ -7,6 +7,9 @@ import com.alibaba.fastjson.TypeReference;
7 7 import com.iot.scheduler.model.DeviceToken;
8 8 import com.iot.scheduler.model.QxDeviceInfo;
9 9 import com.iot.scheduler.model.QxDeviceInfoDetail;
  10 +import com.iot.scheduler.utils.SqlTypedValueUtils;
  11 +import com.zaxxer.hikari.HikariConfig;
  12 +import com.zaxxer.hikari.HikariDataSource;
10 13 import jakarta.annotation.Resource;
11 14 import lombok.extern.slf4j.Slf4j;
12 15 import org.apache.commons.lang3.StringUtils;
... ... @@ -27,11 +30,12 @@ import org.springframework.util.CollectionUtils;
27 30 import java.io.ByteArrayOutputStream;
28 31 import java.io.IOException;
29 32 import java.io.InputStream;
30   -import java.time.LocalTime;
  33 +import java.sql.*;
31 34 import java.util.*;
  35 +import java.util.Date;
32 36
33 37 /**
34   - * 双龙应用数据同步
  38 + * 盛华纸业应用数据同步
35 39 */
36 40 @Slf4j
37 41 @Service
... ... @@ -54,19 +58,29 @@ public class ShzzDevicePullService {
54 58 @Value("${shzz.iot.detailUrl}")
55 59 private String iotDeviceDetailUrl;
56 60
  61 + @Value("${hn.third.jdbcUrl:jdbc:postgresql://106.15.73.210:5433/thingskit}")
  62 + private String jdbcUrl;
  63 +
  64 + @Value("${hn.third.jdbcUserName:postgres}")
  65 + private String jdbcUserName;
  66 +
  67 + @Value("${hn.third.jdbcPassword:postgres}")
  68 + private String jdbcPassword;
57 69
58 70 @Resource
59 71 private RedisTemplate<String, String> redisTemplate;
60 72
61 73 public void pullDeviceAndPushToIot() {
62 74 JSONArray deviceInfoList = getDeviceInfo();
  75 + JSONArray deviceInfoList2 = getDeviceInfo2();
  76 + deviceInfoList.addAll(deviceInfoList2);
63 77 List<QxDeviceInfo> qxDeviceInfos = new ArrayList<>();
64 78 List<QxDeviceInfoDetail> qxAddDeviceInfoDetails = new ArrayList<>();
65 79 Map<String, QxDeviceInfoDetail> qxDeviceInfoDetailMap = new HashMap<>();
66 80 for (Object o : deviceInfoList) {
67 81 JSONObject deviceInfoJson = (JSONObject) o;
68 82 QxDeviceInfo qxDeviceInfo = new QxDeviceInfo();
69   - qxDeviceInfo.setDeviceType("DIRECT_CONNECTION");
  83 + qxDeviceInfo.setDeviceType("SENSOR");
70 84 qxDeviceInfo.setTransportType("DEFAULT");
71 85 qxDeviceInfo.setOrganizationId(iotOrganizeId);
72 86 qxDeviceInfo.setDeviceProfileId(iotDeviceProfileId);
... ... @@ -104,20 +118,28 @@ public class ShzzDevicePullService {
104 118 case 1:
105 119 qxDeviceInfoDetail.setStatus("ERROR");
106 120 qxDeviceInfoDetail.setAlarm(true);
  121 + String totalCapacity = getTotalCapacity("gh_total_capacity_" + dtuSn, 0D);
  122 + qxDeviceInfoDetail.setCumulativeOutput(Double.valueOf(totalCapacity));
107 123 break;
108 124 case 2:
109 125 qxDeviceInfoDetail.setStatus("STAND");
  126 + totalCapacity = getTotalCapacity("gh_total_capacity_" + dtuSn, 0D);
  127 + qxDeviceInfoDetail.setCumulativeOutput(Double.valueOf(totalCapacity));
110 128 break;
111 129 case 3:
112 130 qxDeviceInfoDetail.setStatus("RUN");
113 131 //先从缓存里面拿token信息
114   - String totalCapacity = getTotalCapacity("gh_total_capacity_" + dtuSn, deviceInfoJson.getDouble("production"));
  132 + totalCapacity = getTotalCapacity("gh_total_capacity_" + dtuSn, deviceInfoJson.getDouble("production"));
115 133 qxDeviceInfoDetail.setCumulativeOutput(Double.valueOf(totalCapacity));
  134 + qxDeviceInfoDetail.setCapacity(deviceInfoJson.getDouble("production"));
116 135 break;
117 136 default:
118 137 continue;
119 138 }
120 139
  140 + if (lampState == 0) {
  141 + continue;
  142 + }
121 143
122 144 qxDeviceInfoDetail.setStartTime(new Date());
123 145 qxDeviceInfoDetail.setDtuSn(dtuSn);
... ... @@ -164,7 +186,304 @@ public class ShzzDevicePullService {
164 186 }
165 187 }
166 188
  189 + private JSONArray getDeviceInfo2() {
  190 + Connection connection = null;
  191 + PreparedStatement statement = null;
  192 + PreparedStatement tsKvStatement = null;
  193 + ResultSet resultSet = null;
  194 + ResultSet tsKvResultSet = null;
  195 + HikariDataSource dataSource = null;
  196 + List<Object> resultList = new ArrayList<>();
  197 +
  198 + log.info("开始连接数据库2,URL: {}", jdbcUrl);
  199 +
  200 + try {
  201 + HikariConfig config = new HikariConfig();
  202 + config.setJdbcUrl(jdbcUrl);
  203 + config.setUsername(jdbcUserName);
  204 + config.setPassword(jdbcPassword);
  205 + config.setDriverClassName("org.postgresql.Driver");
  206 + config.setMaximumPoolSize(5);
  207 + config.setMinimumIdle(5);
  208 + config.setConnectionTimeout(60000);
  209 + config.setConnectionTestQuery("SELECT 1");
  210 +
  211 + dataSource = new HikariDataSource(config);
  212 + log.info("Hikari连接池配置完成2");
  213 +
  214 + connection = dataSource.getConnection();
  215 + log.info("数据库连接成功2");
  216 +
  217 + String selectSql = "SELECT\n" +
  218 + "de.id,\n" +
  219 + "de.name,\n" +
  220 + "dc.credentials_id,\n" +
  221 + "CASE\n" +
  222 + " WHEN ak2.long_v IS NULL OR (ak.bool_v = FALSE AND ak2.long_v IS NOT NULL) THEN 'OFF'\n" +
  223 + " WHEN tkl.long_v = 1 THEN 'ERROR'\n" +
  224 + " ELSE 'RUN'\n" +
  225 + " END AS status \n" +
  226 + "FROM device de \n" +
  227 + "LEFT JOIN ts_kv_latest tkl on de.id = tkl.entity_id AND tkl.key = '528'\n" +
  228 + "LEFT JOIN attribute_kv ak ON de.id = ak.entity_id AND ak.entity_type = 'DEVICE' AND ak.attribute_key = 'active'\n" +
  229 + "LEFT JOIN attribute_kv ak2 ON de.id = ak2.entity_id AND ak2.entity_type = 'DEVICE' AND ak2.attribute_key = 'lastActivityTime'\n" +
  230 + "LEFT JOIN device_credentials dc ON de.id = dc.device_id\n" +
  231 + "WHERE de.organization_id = '3304ebd5-71ae-448a-91a2-e3b4d6ae258a'\n" +
  232 + "AND de.device_profile_id = '63042200-02fe-11f1-9cb8-e3376d1e7978'\n";
  233 +
  234 + statement = connection.prepareStatement(selectSql);
  235 + log.info("执行SQL查询2: {}", selectSql);
  236 +
  237 + resultSet = statement.executeQuery();
  238 + ResultSetMetaData metaData = resultSet.getMetaData();
  239 + int columnCount = metaData.getColumnCount();
  240 + log.info("查询结果集元数据获取成功2,共{}列", columnCount);
  241 +
  242 + int rowCount = 0;
  243 + while (resultSet.next()) {
  244 + List<Object> result = new ArrayList<>(columnCount);
  245 + for (int index = 1; index <= columnCount; index++) {
  246 + int columnType = metaData.getColumnType(index);
  247 + Object value = SqlTypedValueUtils.getTypedValue(resultSet, index, columnType);
  248 + result.add(value);
  249 + }
  250 +
  251 + // 处理状态为RUN的设备,进行二次验证
  252 + if (result.size() >= 4 && "RUN".equals(result.get(3))) {
  253 + String deviceId = result.get(0).toString();
  254 + String deviceName = result.get(1).toString();
  255 +
  256 + // 查询该设备最近两条key='531'的数据
  257 + String tsKvSql = "SELECT str_v FROM ts_kv " +
  258 + "WHERE entity_id = ? AND key = '531' " +
  259 + "ORDER BY ts DESC LIMIT 2";
  260 +
  261 + tsKvStatement = connection.prepareStatement(tsKvSql);
  262 + tsKvStatement.setString(1, deviceId);
  263 + tsKvResultSet = tsKvStatement.executeQuery();
  264 +
  265 + List<String> strVValues = new ArrayList<>(2);
  266 + while (tsKvResultSet.next()) {
  267 + strVValues.add(tsKvResultSet.getString("long_v"));
  268 + }
  269 +
  270 + // 如果查询到两条数据且值不同,才认为是真正的RUN状态
  271 + // 否则改为STAND状态
  272 + if (strVValues.size() < 2 ||
  273 + (strVValues.size() == 2 && strVValues.get(0).equals(strVValues.get(1)))) {
  274 + result.set(3, "STAND");
  275 + log.debug("设备{}状态由RUN修正为STAND,long_v值: {}", deviceName, strVValues);
  276 + } else {
  277 + log.debug("设备{}确认为RUN状态,最近两个long_v值不同: {} 和 {}",
  278 + deviceName, strVValues.get(0), strVValues.get(1));
  279 + }
  280 +
  281 + // 关闭ts_kv查询的相关资源
  282 + if (tsKvResultSet != null) {
  283 + tsKvResultSet.close();
  284 + tsKvResultSet = null;
  285 + }
  286 + if (tsKvStatement != null) {
  287 + tsKvStatement.close();
  288 + tsKvStatement = null;
  289 + }
  290 + }
  291 +
  292 + resultList.add(result);
  293 + rowCount++;
  294 +
  295 + // 每处理100行记录一次日志
  296 + if (rowCount % 100 == 0) {
  297 + log.info("已处理{}行数据", rowCount);
  298 + }
  299 + }
  300 +
  301 + log.info("数据查询完成,共获取{}行数据", rowCount);
  302 +
  303 + } catch (SQLException e) {
  304 + log.error("数据库操作异常,URL: {}, 用户名: {}", jdbcUrl, jdbcUserName, e);
  305 + } catch (Exception e) {
  306 + log.error("初始化数据库连接或查询数据时发生异常", e);
  307 + } finally {
  308 + // 释放资源
  309 + try {
  310 + if (tsKvResultSet != null) tsKvResultSet.close();
  311 + if (tsKvStatement != null) tsKvStatement.close();
  312 + if (resultSet != null) resultSet.close();
  313 + if (statement != null) statement.close();
  314 + if (connection != null) connection.close();
  315 + log.info("数据库连接资源已释放");
  316 + } catch (SQLException e) {
  317 + log.error("关闭数据库资源时发生异常", e);
  318 + }
  319 +
  320 + if (dataSource != null) {
  321 + try {
  322 + dataSource.close();
  323 + log.info("HikariDataSource连接池已关闭");
  324 + } catch (Exception e) {
  325 + log.error("关闭HikariDataSource连接池时发生异常", e);
  326 + }
  327 + }
  328 + }
  329 +
  330 + log.info("数据库操作完成,返回{}条记录", resultList.size());
  331 + List<String> deviceNameList = Arrays.asList(
  332 + "新发现KSJ-160智能纸杯机7oz-1", "新发现KSJ-160智能纸杯机7oz-2", "新发现KSJ-160智能纸杯机6.5oz", "新发现KSJ-160智能纸杯机8oz-1",
  333 + "新发现KSJ-160智能纸杯机8oz-2", "新发现PJJ-III型纸容器品检机6.5oz/7oz", "新发现PJJ-III型纸容器品检机7.5oz/8oz",
  334 + "新发现PJJ-I-02型纸容器品检机7.5oz/8oz", "新发现PJJ-I-02型纸容器品检机7.5oz/12oz", "新发现KSJ-160智能快速纸杯机7.5oz-1",
  335 + "新发现KSJ-160智能快速纸杯机7.5oz-2", "新发现KSJ-160智能快速纸杯机12oz", "智能中速纸杯机JBZ-22D-1",
  336 + "智能中速纸杯机JBZ-22D-2", "智能中速纸杯机JBZ-22D-3", "智能中速纸杯机JBZ-22D-4", "智能中速纸杯机JBZ-22D-5", "智能中速纸杯机JBZ-22D-6",
  337 + "智能中速纸杯机JBZ-22D-7", "智能中速纸杯机JBZ-22D-8", "智能中速纸杯机JBZ-22D-9", "智能中速纸杯机JBZ-22S-1", "智能中速纸杯机JBZ-22S-2",
  338 + "高速智能纸杯机DEBAO-100S", "纸机杯XC-L12齿轮340-B型-1", "纸机杯XC-L12齿轮340-B型-2", "中速外贴机SM100-KT490(12oz)",
  339 + "中速外贴机SM100-KT491(4oz)", "中速外贴机SM100-KY373", "中速外贴机SM100-KT489(16oz)", "外贴机8oz", "外贴机12oz", "模切机1",
  340 + "模切机2", "模切机3", "模切机4", "模切机5");
  341 +
  342 + JSONArray jsonArray = new JSONArray();
  343 + List<JSONObject> jsonObjectList = new ArrayList<>(resultList.size());
  344 + for (Object result : resultList) {
  345 + List<Object> dataList = (ArrayList) result;
  346 + int index = deviceNameList.indexOf(dataList.get(1)); // 注意:现在name在索引1位置
  347 +
  348 + Map<String, Object> map = new HashMap<>(3);
  349 + map.put("deviceName", dataList.get(1));
  350 + map.put("dtuSn", dataList.get(2));
  351 +
  352 + String status = dataList.get(3).toString();
  353 + if ("OFF".equals(status)) {
  354 + map.put("lampState", 0);
  355 + } else if ("ERROR".equals(status)) {
  356 + map.put("lampState", 1);
  357 + } else if ("STAND".equals(status)) {
  358 + map.put("lampState", 2);
  359 + } else if ("RUN".equals(status)) {
  360 + map.put("lampState", 3);
  361 + }
  362 +
  363 + if (index < 11) {
  364 + map.put("production", 130D);
  365 + } else if (index == 11) {
  366 + map.put("production", 120D);
  367 + } else if (index < 23) {
  368 + map.put("production", 80D);
  369 + } else if (index == 23) {
  370 + map.put("production", 110D);
  371 + } else if (index < 26) {
  372 + map.put("production", 50D);
  373 + } else if (index < 30) {
  374 + map.put("production", 120D);
  375 + } else {
  376 + map.put("production", 80D);
  377 + }
  378 +
  379 + JSONObject jsonObject = new JSONObject();
  380 + jsonObject.putAll(map);
  381 + jsonObjectList.add(jsonObject);
  382 + }
  383 +
  384 + jsonArray.addAll(jsonObjectList);
  385 + return jsonArray;
  386 + }
  387 +
167 388 private JSONArray getDeviceInfo() {
  389 + Connection connection = null;
  390 + PreparedStatement statement = null;
  391 + ResultSet resultSet = null;
  392 + HikariDataSource dataSource = null;
  393 + List<Object> resultList = new ArrayList<>();
  394 +
  395 + log.info("开始连接数据库,URL: {}", jdbcUrl);
  396 +
  397 + try {
  398 + HikariConfig config = new HikariConfig();
  399 + config.setJdbcUrl(jdbcUrl);
  400 + config.setUsername(jdbcUserName);
  401 + config.setPassword(jdbcPassword);
  402 + config.setDriverClassName("org.postgresql.Driver");
  403 + config.setMaximumPoolSize(5);
  404 + config.setMinimumIdle(5);
  405 + config.setConnectionTimeout(60000);
  406 + config.setConnectionTestQuery("SELECT 1");
  407 +
  408 + dataSource = new HikariDataSource(config);
  409 + log.info("Hikari连接池配置完成");
  410 +
  411 + connection = dataSource.getConnection();
  412 + log.info("数据库连接成功");
  413 +
  414 + String selectSql = "SELECT\n" +
  415 + "de.name,\n" +
  416 + "dc.credentials_id,\n" +
  417 + "CASE\n" +
  418 + " WHEN ak2.long_v IS NULL OR (ak.bool_v = FALSE AND ak2.long_v IS NOT NULL) THEN 'OFF'\n" +
  419 + " WHEN tkl.long_v = 1 THEN 'ERROR'\n" +
  420 + " WHEN tkl2.long_v = 1 THEN 'STAND'\n" +
  421 + " WHEN tkl3.long_v = 1 THEN 'RUN'\n" +
  422 + " ELSE 'OFF'\n" +
  423 + " END AS status \n" +
  424 + "FROM device de \n" +
  425 + "LEFT JOIN ts_kv_latest tkl on de.id = tkl.entity_id AND tkl.key = '64'\n" +
  426 + "LEFT JOIN ts_kv_latest tkl2 on de.id = tkl2.entity_id AND tkl2.key = '535'\n" +
  427 + "LEFT JOIN ts_kv_latest tkl3 on de.id = tkl3.entity_id AND tkl3.key = '534'\n" +
  428 + "LEFT JOIN attribute_kv ak ON de.id = ak.entity_id AND ak.entity_type = 'DEVICE' AND ak.attribute_key = 'active'\n" +
  429 + "LEFT JOIN attribute_kv ak2 ON de.id = ak2.entity_id AND ak2.entity_type = 'DEVICE' AND ak2.attribute_key = 'lastActivityTime'\n" +
  430 + "LEFT JOIN device_credentials dc ON de.id = dc.device_id\n" +
  431 + "WHERE de.organization_id = '3304ebd5-71ae-448a-91a2-e3b4d6ae258a'\n" +
  432 + "AND de.device_profile_id = '1f2183a0-0562-11f1-9cb8-e3376d1e7978'\n";
  433 +
  434 + statement = connection.prepareStatement(selectSql);
  435 + log.info("执行SQL查询: {}", selectSql);
  436 +
  437 + resultSet = statement.executeQuery();
  438 + ResultSetMetaData metaData = resultSet.getMetaData();
  439 + int columnCount = metaData.getColumnCount();
  440 + log.info("查询结果集元数据获取成功,共{}列", columnCount);
  441 +
  442 + int rowCount = 0;
  443 + while (resultSet.next()) {
  444 + List<Object> result = new ArrayList<>(columnCount);
  445 + for (int index = 1; index <= columnCount; index++) {
  446 + int columnType = metaData.getColumnType(index);
  447 + Object value = SqlTypedValueUtils.getTypedValue(resultSet, index, columnType);
  448 + result.add(value);
  449 + }
  450 + resultList.add(result);
  451 + rowCount++;
  452 +
  453 + // 每处理1000行记录一次日志
  454 + if (rowCount % 1000 == 0) {
  455 + log.info("已处理{}行数据", rowCount);
  456 + }
  457 + }
  458 +
  459 + log.info("数据查询完成,共获取{}行数据", rowCount);
  460 +
  461 + } catch (SQLException e) {
  462 + log.error("数据库操作异常,URL: {}, 用户名: {}", jdbcUrl, jdbcUserName, e);
  463 + } catch (Exception e) {
  464 + log.error("初始化数据库连接或查询数据时发生异常", e);
  465 + } finally {
  466 + // 释放资源
  467 + try {
  468 + if (resultSet != null) resultSet.close();
  469 + if (statement != null) statement.close();
  470 + if (connection != null) connection.close();
  471 + log.info("数据库连接资源已释放");
  472 + } catch (SQLException e) {
  473 + log.error("关闭数据库资源时发生异常", e);
  474 + }
  475 +
  476 + if (dataSource != null) {
  477 + try {
  478 + dataSource.close();
  479 + log.info("HikariDataSource连接池已关闭");
  480 + } catch (Exception e) {
  481 + log.error("关闭HikariDataSource连接池时发生异常", e);
  482 + }
  483 + }
  484 + }
  485 +
  486 + log.info("数据库操作完成,返回{}条记录", resultList.size());
168 487 List<String> deviceNameList = Arrays.asList(
169 488 "新发现KSJ-160智能纸杯机7oz-1", "新发现KSJ-160智能纸杯机7oz-2", "新发现KSJ-160智能纸杯机6.5oz", "新发现KSJ-160智能纸杯机8oz-1",
170 489 "新发现KSJ-160智能纸杯机8oz-2", "新发现PJJ-III型纸容器品检机6.5oz/7oz", "新发现PJJ-III型纸容器品检机7.5oz/8oz",
... ... @@ -175,19 +494,26 @@ public class ShzzDevicePullService {
175 494 "高速智能纸杯机DEBAO-100S", "纸机杯XC-L12齿轮340-B型-1", "纸机杯XC-L12齿轮340-B型-2", "中速外贴机SM100-KT490(12oz)",
176 495 "中速外贴机SM100-KT491(4oz)", "中速外贴机SM100-KY373", "中速外贴机SM100-KT489(16oz)", "外贴机8oz", "外贴机12oz", "模切机1",
177 496 "模切机2", "模切机3", "模切机4", "模切机5");
  497 +
178 498 JSONArray jsonArray = new JSONArray();
179   - List<JSONObject> jsonObjectList = new ArrayList<>(38);
180   - LocalTime currentTime = LocalTime.now();
181   - LocalTime startTime = LocalTime.of(8, 0, 0); // 08:00:00
182   - LocalTime endTime = LocalTime.of(18, 0, 0); // 18:00:00
183   - boolean isWithinRange =
184   - !currentTime.isBefore(startTime) &&
185   - currentTime.isBefore(endTime);
186   - for (int index = 0; index < deviceNameList.size(); index++) {
  499 + List<JSONObject> jsonObjectList = new ArrayList<>(resultList.size());
  500 + for (Object result : resultList) {
  501 + List<Object> dataList = (ArrayList) result;
  502 + int index = deviceNameList.indexOf(dataList.get(0));
187 503 Map<String, Object> map = new HashMap<>(3);
188   - map.put("deviceName", deviceNameList.get(index));
189   - map.put("dtuSn", "SGH20250123" + String.format("%03d", index));
190   - map.put("lampState", isWithinRange ? 3 : 0);
  504 + map.put("deviceName", dataList.get(0));
  505 + map.put("dtuSn", dataList.get(1));
  506 + String status = dataList.get(2).toString();
  507 + if ("OFF".equals(status)) {
  508 + map.put("lampState", 0);
  509 + } else if ("ERROR".equals(status)) {
  510 + map.put("lampState", 1);
  511 + } else if ("STAND".equals(status)) {
  512 + map.put("lampState", 2);
  513 + } else if ("RUN".equals(status)) {
  514 + map.put("lampState", 3);
  515 + }
  516 +
191 517 if (index < 11) {
192 518 map.put("production", 130D);
193 519 } else if (index == 11) {
... ... @@ -203,6 +529,7 @@ public class ShzzDevicePullService {
203 529 } else {
204 530 map.put("production", 80D);
205 531 }
  532 +
206 533 JSONObject jsonObject = new JSONObject();
207 534 jsonObject.putAll(map);
208 535 jsonObjectList.add(jsonObject);
... ... @@ -210,6 +537,43 @@ public class ShzzDevicePullService {
210 537
211 538 jsonArray.addAll(jsonObjectList);
212 539 return jsonArray;
  540 +
  541 +
  542 +// JSONArray jsonArray = new JSONArray();
  543 +// List<JSONObject> jsonObjectList = new ArrayList<>(38);
  544 +// LocalTime currentTime = LocalTime.now();
  545 +// LocalTime startTime = LocalTime.of(8, 0, 0); // 08:00:00
  546 +// LocalTime endTime = LocalTime.of(18, 0, 0); // 18:00:00
  547 +// boolean isWithinRange =
  548 +// !currentTime.isBefore(startTime) &&
  549 +// currentTime.isBefore(endTime);
  550 +// for (int index = 0; index < deviceNameList.size(); index++) {
  551 +// Map<String, Object> map = new HashMap<>(3);
  552 +// map.put("deviceName", deviceNameList.get(index));
  553 +// map.put("dtuSn", "SGH20250123" + String.format("%03d", index));
  554 +// map.put("lampState", isWithinRange ? 3 : 0);
  555 +// if (index < 11) {
  556 +// map.put("production", 130D);
  557 +// } else if (index == 11) {
  558 +// map.put("production", 120D);
  559 +// } else if (index < 23) {
  560 +// map.put("production", 80D);
  561 +// } else if (index == 23) {
  562 +// map.put("production", 110D);
  563 +// } else if (index < 26) {
  564 +// map.put("production", 50D);
  565 +// } else if (index < 30) {
  566 +// map.put("production", 120D);
  567 +// } else {
  568 +// map.put("production", 80D);
  569 +// }
  570 +// JSONObject jsonObject = new JSONObject();
  571 +// jsonObject.putAll(map);
  572 +// jsonObjectList.add(jsonObject);
  573 +// }
  574 +//
  575 +// jsonArray.addAll(jsonObjectList);
  576 +// return jsonArray;
213 577 }
214 578
215 579 private String getTotalCapacity(String key, Double production) {
... ...
... ... @@ -151,19 +151,29 @@ public class SlDevicePullService {
151 151 switch (lampState) {
152 152 case 0:
153 153 qxDeviceInfoDetail.setStatus("OFF");
  154 + //先从缓存里面拿token信息
  155 + String totalCapacity = getTotalCapacity("total_capacity_" + dtuSn, 0D);
  156 + qxDeviceInfoDetail.setCumulativeOutput(Double.valueOf(totalCapacity));
154 157 break;
155 158 case 1:
156 159 qxDeviceInfoDetail.setStatus("ERROR");
157 160 qxDeviceInfoDetail.setAlarm(true);
  161 + //先从缓存里面拿token信息
  162 + totalCapacity = getTotalCapacity("total_capacity_" + dtuSn, 0D);
  163 + qxDeviceInfoDetail.setCumulativeOutput(Double.valueOf(totalCapacity));
158 164 break;
159 165 case 2:
160 166 qxDeviceInfoDetail.setStatus("STAND");
  167 + //先从缓存里面拿token信息
  168 + totalCapacity = getTotalCapacity("total_capacity_" + dtuSn, 0D);
  169 + qxDeviceInfoDetail.setCumulativeOutput(Double.valueOf(totalCapacity));
161 170 break;
162 171 case 3:
163 172 qxDeviceInfoDetail.setStatus("RUN");
164 173 //先从缓存里面拿token信息
165   - String totalCapacity = getTotalCapacity("total_capacity_" + dtuSn, highSpeed);
  174 + totalCapacity = getTotalCapacity("total_capacity_" + dtuSn, highSpeed ? 120D : 100D);
166 175 qxDeviceInfoDetail.setCumulativeOutput(Double.valueOf(totalCapacity));
  176 + qxDeviceInfoDetail.setCapacity(highSpeed ? 120D : 100D);
167 177 break;
168 178 default:
169 179 continue;
... ... @@ -225,9 +235,8 @@ public class SlDevicePullService {
225 235 }
226 236 }
227 237
228   - private String getTotalCapacity(String key, boolean highSpeedDevice) {
  238 + private String getTotalCapacity(String key, Double production) {
229 239 String totalCapacity = redisTemplate.opsForValue().get(key);
230   - Double production = highSpeedDevice ? 120D : 100D;
231 240 Double totalCapacityD = 0D;
232 241 if (StringUtils.isEmpty(totalCapacity)) {
233 242 totalCapacityD = production;
... ...
  1 +package com.iot.scheduler.utils;
  2 +
  3 +import lombok.extern.slf4j.Slf4j;
  4 +
  5 +import java.sql.*;
  6 +
  7 +@Slf4j
  8 +public class SqlTypedValueUtils {
  9 +
  10 + public static Object getTypedValue(ResultSet rs, int index, int sqlType) throws SQLException {
  11 + Object value;
  12 +
  13 + try {
  14 + switch (sqlType) {
  15 + case Types.BIT:
  16 + case Types.BOOLEAN:
  17 + value = rs.getBoolean(index);
  18 + return rs.wasNull() ? null : value;
  19 +
  20 + case Types.TINYINT:
  21 + case Types.SMALLINT:
  22 + case Types.INTEGER:
  23 + value = rs.getInt(index);
  24 + return rs.wasNull() ? null : value;
  25 +
  26 + case Types.BIGINT:
  27 + value = rs.getLong(index);
  28 + return rs.wasNull() ? null : value;
  29 +
  30 + case Types.FLOAT:
  31 + case Types.REAL:
  32 + value = rs.getFloat(index);
  33 + return rs.wasNull() ? null : value;
  34 +
  35 + case Types.DOUBLE:
  36 + value = rs.getDouble(index);
  37 + return rs.wasNull() ? null : value;
  38 +
  39 + case Types.NUMERIC:
  40 + case Types.DECIMAL:
  41 + value = rs.getBigDecimal(index);
  42 + return rs.wasNull() ? null : value;
  43 +
  44 + case Types.CHAR:
  45 + case Types.VARCHAR:
  46 + case Types.LONGVARCHAR:
  47 + case Types.NCHAR:
  48 + case Types.NVARCHAR:
  49 + case Types.LONGNVARCHAR:
  50 + value = rs.getString(index);
  51 + return rs.wasNull() ? null : value;
  52 +
  53 + case Types.DATE:
  54 + Date date = rs.getDate(index);
  55 + return date != null ? date.toLocalDate() : null;
  56 +
  57 + case Types.TIME:
  58 + Time time = rs.getTime(index);
  59 + return time != null ? time.toLocalTime() : null;
  60 +
  61 + case Types.TIMESTAMP:
  62 + Timestamp timestamp = rs.getTimestamp(index);
  63 + return timestamp != null ? timestamp.toLocalDateTime() : null;
  64 +
  65 + case Types.BINARY:
  66 + case Types.VARBINARY:
  67 + case Types.LONGVARBINARY:
  68 + value = rs.getBytes(index);
  69 + return rs.wasNull() ? null : value;
  70 +
  71 + case Types.BLOB:
  72 + value = rs.getBlob(index);
  73 + return rs.wasNull() ? null : value;
  74 +
  75 + case Types.CLOB:
  76 + value = rs.getClob(index);
  77 + return rs.wasNull() ? null : value;
  78 +
  79 + default:
  80 + value = rs.getObject(index);
  81 + return rs.wasNull() ? null : value;
  82 + }
  83 + } catch (SQLException e) {
  84 + log.error("获取结果集第{}列数据时发生异常,数据类型: {}", index, sqlType, e);
  85 + throw e;
  86 + }
  87 + }
  88 +}
... ...
... ... @@ -36,8 +36,8 @@ public class ChizhouZoneScheduler extends AbstractZoneScheduler {
36 36 log.info("[{}] Simulating pulling devices...", getZoneName());
37 37 shDevicePullService.pullDeviceAndPushToIot();
38 38 slDevicePullService.pullDeviceAndPushToIot();
39   -// ghDevicePullService.pullDeviceAndPushToIot();
40   -// shzzDevicePullService.pullDeviceAndPushToIot();
  39 + ghDevicePullService.pullDeviceAndPushToIot();
  40 + shzzDevicePullService.pullDeviceAndPushToIot();
41 41 Thread.sleep(1000);
42 42 } catch (Exception e) {
43 43 logError(taskName, e);
... ...
... ... @@ -49,8 +49,8 @@ hn:
49 49 jdbcPassword: "postgres"
50 50 selectSql: "SELECT
51 51 dc.credentials_id AS sn,
52   - tkl1.str_v,
53   - tkl2.dbl_v
  52 + tkl1.str_v AS status,
  53 + tkl2.dbl_v AS cumulativeOutput
54 54 FROM
55 55 device de
56 56 LEFT JOIN device_credentials dc on de.id = dc.device_id
... ... @@ -61,10 +61,49 @@ hn:
61 61 WHERE
62 62 de.organization_id IN(
63 63 'f82530a0-93e4-4aeb-9339-f5b6d1127840',
64   - '752a7621-b59b-477c-b15e-e06d412e02d5',
65   - '3304ebd5-71ae-448a-91a2-e3b4d6ae258a',
66   - '875a4841-c7f2-4e2c-88a2-ea62d4642132'
67   - );"
  64 + '752a7621-b59b-477c-b15e-e06d412e02d5'
  65 + )
  66 + UNION all
  67 +
  68 +SELECT
  69 +dc.credentials_id AS sn,
  70 +CASE
  71 + WHEN ak2.long_v IS NULL OR (ak.bool_v = FALSE AND ak2.long_v IS NOT NULL) THEN 'OFF'
  72 + WHEN tkl.long_v = 1 THEN 'ERROR'
  73 + WHEN tkl2.long_v = 1 THEN 'STAND'
  74 + WHEN tkl3.long_v = 1 THEN 'RUN'
  75 + ELSE 'OFF'
  76 + END AS status,
  77 +tkl4.dbl_v AS cumulativeOutput
  78 +FROM device de
  79 +LEFT JOIN ts_kv_latest tkl on de.id = tkl.entity_id AND tkl.key = '64'
  80 +LEFT JOIN ts_kv_latest tkl2 on de.id = tkl2.entity_id AND tkl2.key = '535'
  81 +LEFT JOIN ts_kv_latest tkl3 on de.id = tkl3.entity_id AND tkl3.key = '534'
  82 +LEFT JOIN ts_kv_latest tkl4 ON de.id = tkl4.entity_id AND tkl4.key = '175'
  83 +LEFT JOIN attribute_kv ak ON de.id = ak.entity_id AND ak.entity_type = 'DEVICE' AND ak.attribute_key = 'active'
  84 +LEFT JOIN attribute_kv ak2 ON de.id = ak2.entity_id AND ak2.entity_type = 'DEVICE' AND ak2.attribute_key = 'lastActivityTime'
  85 +LEFT JOIN device_credentials dc ON de.id = dc.device_id
  86 +WHERE (de.organization_id = '875a4841-c7f2-4e2c-88a2-ea62d4642132' or de.organization_id = '3304ebd5-71ae-448a-91a2-e3b4d6ae258a')
  87 +AND de.device_profile_id = '1f2183a0-0562-11f1-9cb8-e3376d1e7978'
  88 +UNION ALL
  89 +SELECT
  90 +dc.credentials_id,
  91 +CASE
  92 + WHEN ak2.long_v IS NULL OR (ak.bool_v = FALSE AND ak2.long_v IS NOT NULL) THEN 'OFF'
  93 + WHEN tkl.str_v = 'ERROR' THEN 'ERROR'
  94 + WHEN tkl.str_v = 'STAND' THEN 'STAND'
  95 + ELSE 'RUN'
  96 + END AS status,
  97 +tkl2.dbl_v AS cumulativeOutput
  98 +FROM device de
  99 +LEFT JOIN ts_kv_latest tkl on de.id = tkl.entity_id AND tkl.key = '61'
  100 +LEFT JOIN ts_kv_latest tkl2 ON de.id = tkl2.entity_id AND tkl2.key = '175'
  101 +LEFT JOIN attribute_kv ak ON de.id = ak.entity_id AND ak.entity_type = 'DEVICE' AND ak.attribute_key = 'active'
  102 +LEFT JOIN attribute_kv ak2 ON de.id = ak2.entity_id AND ak2.entity_type = 'DEVICE' AND ak2.attribute_key = 'lastActivityTime'
  103 +LEFT JOIN device_credentials dc ON de.id = dc.device_id
  104 +WHERE de.organization_id = '3304ebd5-71ae-448a-91a2-e3b4d6ae258a'
  105 +AND de.device_profile_id = '63042200-02fe-11f1-9cb8-e3376d1e7978'"
  106 +
68 107 hnhsq:
69 108 third:
70 109 reportUrl: "http://58.243.79.51:31357/mainApi/formEngine/formData/batchAddOrUpate"
... ...