Commit f170d8fdc1347e8330d4a5b2371cd39fa406fb5d

Authored by yelan
1 parent 65b72b76

feat: 添加设备用电量和用水量计算功能

... ... @@ -43,7 +43,9 @@ public class CzDeviceReportService {
43 43 " 'OFF'\n" +
44 44 " END AS 设备状态,\n" +
45 45 " dc.credentials_id AS sn,\n" +
46   - " de.organization_id\n" +
  46 + " de.organization_id, \n" +
  47 + " de.device_profile_id, \n" +
  48 + " de.id \n" +
47 49 " FROM\n" +
48 50 " device de\n" +
49 51 " LEFT JOIN ts_kv_latest tkl ON de.id = tkl.entity_id\n" +
... ... @@ -71,7 +73,9 @@ public class CzDeviceReportService {
71 73 " 'RUN'\n" +
72 74 " END AS 设备状态,\n" +
73 75 " dc.credentials_id AS sn,\n" +
74   - " de.organization_id\n" +
  76 + " de.organization_id, \n" +
  77 + " de.device_profile_id, \n" +
  78 + " de.id \n" +
75 79 " FROM\n" +
76 80 " device de\n" +
77 81 " LEFT JOIN attribute_kv ak ON de.id = ak.entity_id\n" +
... ... @@ -93,7 +97,9 @@ public class CzDeviceReportService {
93 97 " 'RUN'\n" +
94 98 " END AS 设备状态,\n" +
95 99 " dc.credentials_id AS sn,\n" +
96   - " de.organization_id\n" +
  100 + " de.organization_id, \n" +
  101 + " de.device_profile_id, \n" +
  102 + " de.id \n" +
97 103 " FROM\n" +
98 104 " device de\n" +
99 105 " LEFT JOIN attribute_kv ak ON de.id = ak.entity_id\n" +
... ... @@ -157,6 +163,8 @@ public class CzDeviceReportService {
157 163 String deviceId = dataList.get(2).toString();
158 164 String status = dataList.get(1).toString();
159 165 String organizeId = dataList.get(3).toString();
  166 + String deviceProfileId = dataList.get(4).toString();
  167 + String id = dataList.get(5).toString();
160 168
161 169 // 根据index确定clientId
162 170 String clientId = organizeIdAndClientIdMap.get(organizeId);
... ... @@ -165,12 +173,18 @@ public class CzDeviceReportService {
165 173 // 获取设备状态
166 174 int deviceState = getDeviceState(status);
167 175
  176 + // 计算当日用电量和用水量
  177 + double electricity = calculateDailyElectricity(id, deviceProfileId);
  178 + double water = calculateDailyWater(id, deviceProfileId);
  179 +
168 180 Map<String, Object> properties = new HashMap<>(5);
169 181 properties.put("type", 1);
170 182 properties.put("state", deviceState);
171 183 properties.put("time", formattedDate);
172 184 properties.put("output", 0); // 当日产量,还未确定,暂定为0
173 185 properties.put("energy", 0); // 当日能耗,还未确定,暂定为0
  186 + properties.put("electricity", electricity); // 当日用电量
  187 + properties.put("water", water); // 当日用水量
174 188
175 189 Map<String, Object> deviceMap = new HashMap<>(2);
176 190 deviceMap.put("deviceId", deviceId);
... ... @@ -237,6 +251,135 @@ public class CzDeviceReportService {
237 251 return deviceState;
238 252 }
239 253
  254 + /**
  255 + * 计算当日用电量
  256 + * deviceProfileId = c2401630-ffec-11f0-926f-2f3182abc65f,key=64,读取dbl_v
  257 + * @param deviceId 设备ID(entity_id)
  258 + * @param deviceProfileId 设备配置ID
  259 + * @return 当日用电量
  260 + */
  261 + private double calculateDailyElectricity(String deviceId, String deviceProfileId) {
  262 + // 非用电设备类型,返回0
  263 + if (!"c2401630-ffec-11f0-926f-2f3182abc65f".equals(deviceProfileId)) {
  264 + return 0;
  265 + }
  266 +
  267 + String sql = "SELECT " +
  268 + " (SELECT COALESCE(dbl_v, 0) FROM ts_kv " +
  269 + " WHERE entity_id = ? AND key = 64 AND ts >= ? AND ts <= ? AND dbl_v IS NOT NULL " +
  270 + " ORDER BY ts ASC LIMIT 1) AS first_value, " +
  271 + " (SELECT COALESCE(dbl_v, 0) FROM ts_kv " +
  272 + " WHERE entity_id = ? AND key = 64 AND ts >= ? AND ts <= ? AND dbl_v IS NOT NULL " +
  273 + " ORDER BY ts DESC LIMIT 1) AS last_value";
  274 +
  275 + return calculateDailyConsumption(deviceId, sql, "用电量");
  276 + }
  277 +
  278 + /**
  279 + * 计算当日用水量
  280 + * deviceProfileId = 4e404b10-ffe7-11f0-926f-2f3182abc65f,key=83,读取dbl_v或long_v
  281 + * @param deviceId 设备ID(entity_id)
  282 + * @param deviceProfileId 设备配置ID
  283 + * @return 当日用水量
  284 + */
  285 + private double calculateDailyWater(String deviceId, String deviceProfileId) {
  286 + // 非用水设备类型,返回0
  287 + if (!"4e404b10-ffe7-11f0-926f-2f3182abc65f".equals(deviceProfileId)) {
  288 + return 0;
  289 + }
  290 +
  291 + String sql = "SELECT " +
  292 + " (SELECT COALESCE(dbl_v, long_v, 0) FROM ts_kv " +
  293 + " WHERE entity_id = ? AND key = 83 AND ts >= ? AND ts <= ? " +
  294 + " AND (dbl_v IS NOT NULL OR long_v IS NOT NULL) " +
  295 + " ORDER BY ts ASC LIMIT 1) AS first_value, " +
  296 + " (SELECT COALESCE(dbl_v, long_v, 0) FROM ts_kv " +
  297 + " WHERE entity_id = ? AND key = 83 AND ts >= ? AND ts <= ? " +
  298 + " AND (dbl_v IS NOT NULL OR long_v IS NOT NULL) " +
  299 + " ORDER BY ts DESC LIMIT 1) AS last_value";
  300 +
  301 + return calculateDailyConsumption(deviceId, sql, "用水量");
  302 + }
  303 +
  304 + /**
  305 + * 执行能耗计算查询
  306 + * @param deviceId 设备ID
  307 + * @param sql 查询SQL
  308 + * @param logName 日志名称
  309 + * @return 当日消耗量
  310 + */
  311 + private double calculateDailyConsumption(String deviceId, String sql, String logName) {
  312 + Connection connection = null;
  313 + PreparedStatement statement = null;
  314 + ResultSet resultSet = null;
  315 + HikariDataSource dataSource = null;
  316 +
  317 + try {
  318 + HikariConfig config = new HikariConfig();
  319 + config.setJdbcUrl(jdbcUrl);
  320 + config.setUsername(jdbcUserName);
  321 + config.setPassword(jdbcPassword);
  322 + config.setDriverClassName("org.postgresql.Driver");
  323 + config.setMaximumPoolSize(5);
  324 + config.setMinimumIdle(5);
  325 + config.setConnectionTimeout(60000);
  326 + config.setConnectionTestQuery("SELECT 1");
  327 +
  328 + dataSource = new HikariDataSource(config);
  329 + connection = dataSource.getConnection();
  330 +
  331 + // 获取当天开始和结束时间戳(毫秒)
  332 + Calendar calendar = Calendar.getInstance();
  333 + calendar.set(Calendar.HOUR_OF_DAY, 0);
  334 + calendar.set(Calendar.MINUTE, 0);
  335 + calendar.set(Calendar.SECOND, 0);
  336 + calendar.set(Calendar.MILLISECOND, 0);
  337 + long startOfDay = calendar.getTimeInMillis();
  338 + calendar.set(Calendar.HOUR_OF_DAY, 23);
  339 + calendar.set(Calendar.MINUTE, 59);
  340 + calendar.set(Calendar.SECOND, 59);
  341 + calendar.set(Calendar.MILLISECOND, 999);
  342 + long endOfDay = calendar.getTimeInMillis();
  343 +
  344 + statement = connection.prepareStatement(sql);
  345 + statement.setString(1, deviceId);
  346 + statement.setLong(2, startOfDay);
  347 + statement.setLong(3, endOfDay);
  348 + statement.setString(4, deviceId);
  349 + statement.setLong(5, startOfDay);
  350 + statement.setLong(6, endOfDay);
  351 +
  352 + resultSet = statement.executeQuery();
  353 + if (resultSet.next()) {
  354 + double firstValue = resultSet.getDouble("first_value");
  355 + double lastValue = resultSet.getDouble("last_value");
  356 + double consumption = lastValue - firstValue;
  357 + log.debug("设备 {} 当日{}计算: 首值={}, 末值={}, 消耗={}", deviceId, logName, firstValue, lastValue, consumption);
  358 + return Math.max(consumption, 0); // 确保非负
  359 + }
  360 + } catch (SQLException e) {
  361 + log.error("查询设备 {} 当日{}失败: {}", deviceId, logName, e.getMessage(), e);
  362 + } catch (Exception e) {
  363 + log.error("计算设备 {} 当日{}时发生异常", deviceId, logName, e);
  364 + } finally {
  365 + try {
  366 + if (resultSet != null) resultSet.close();
  367 + if (statement != null) statement.close();
  368 + if (connection != null) connection.close();
  369 + } catch (SQLException e) {
  370 + log.error("关闭数据库资源时发生异常", e);
  371 + }
  372 + if (dataSource != null) {
  373 + try {
  374 + dataSource.close();
  375 + } catch (Exception e) {
  376 + log.error("关闭HikariDataSource连接池时发生异常", e);
  377 + }
  378 + }
  379 + }
  380 + return 0;
  381 + }
  382 +
240 383 private List<Object> initConnectAndSelectData() {
241 384 Connection connection = null;
242 385 PreparedStatement statement = null;
... ...