| ¶Ô±ÈÐÂÎļþ |
| | |
| | | -- è½è管çï¼æ°´è¡¨/çµè¡¨/æ°è¡¨ï¼æ°æ®å¯¼åº |
| | | -- æºæ°æ®åºï¼product-inventory-management-xswh |
| | | -- å¯¼åºæ¶é´ï¼2026-11-04 23:26:05 |
| | | -- å符éï¼UTF-8 (utf8mb4) |
| | | -- 说æï¼å
å«å»ºè¡¨è¯å¥ï¼IF NOT EXISTSï¼ä¸æ°æ®ï¼ä¸ä¼ DROP ä»»ä½è¡¨ã |
| | | |
| | | SET NAMES utf8mb4; |
| | | SET FOREIGN_KEY_CHECKS = 0; |
| | | |
| | | -- ---------------------------- |
| | | -- energy_meter_device |
| | | -- ---------------------------- |
| | | CREATE TABLE IF NOT EXISTS `energy_meter_device` ( |
| | | `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'æ¬å°è®¾å¤ID', |
| | | `tenant_id` bigint NOT NULL COMMENT 'ç§æ·ID', |
| | | `meter_type` varchar(16) NOT NULL COMMENT 'è½æºç±»åï¼WATER水表 / ELECTRICçµè¡¨ / GASæ°è¡¨', |
| | | `source_type` varchar(16) NOT NULL DEFAULT 'PROVIDER' COMMENT 'æ°æ®æ¥æºï¼PROVIDERç¬¬ä¸æ¹æ¥å
¥ / MANUALæå·¥æè¡¨', |
| | | `meter_address` varchar(64) NOT NULL COMMENT 'éä¿¡å°åæè¡¨å·ï¼æå符串ä¿åï¼ä¿çå导é¶', |
| | | `provider_meter_id` varchar(64) DEFAULT NULL COMMENT 'ç¬¬ä¸æ¹è®¾å¤ID', |
| | | `provider_name` varchar(128) DEFAULT NULL COMMENT 'ç¬¬ä¸æ¹è®¾å¤åç§°', |
| | | `display_name` varchar(128) NOT NULL COMMENT 'æ¬ç³»ç»æ¾ç¤ºåç§°', |
| | | `provider_area_id` bigint DEFAULT NULL COMMENT 'ç¬¬ä¸æ¹åºåID', |
| | | `provider_area_name` varchar(128) DEFAULT NULL COMMENT 'ç¬¬ä¸æ¹åºååç§°', |
| | | `parent_provider_id` varchar(64) DEFAULT NULL COMMENT 'ç¬¬ä¸æ¹æ»è¡¨ID', |
| | | `parent_meter_id` bigint DEFAULT NULL COMMENT 'æ¬å°æ»è¡¨IDï¼ç¡®è®¤æ å°åç»´æ¤', |
| | | `location` varchar(255) DEFAULT NULL COMMENT 'å®è£
ä½ç½®', |
| | | `online_status` tinyint DEFAULT NULL COMMENT '1å¨çº¿ 0离线 NULLæªç¥', |
| | | `bind_status` varchar(16) NOT NULL DEFAULT 'VERIFIED' COMMENT 'VERIFIED/INVALID', |
| | | `enabled` tinyint NOT NULL DEFAULT '1' COMMENT '1å¯ç¨ 0åç¨', |
| | | `is_seed` tinyint NOT NULL DEFAULT '0' COMMENT '1åå§å设å¤ï¼ç¦æ¢å é¤ï¼0ç¨æ·æ°å¢', |
| | | `simulated` tinyint NOT NULL DEFAULT '0' COMMENT '1æ¼ç¤ºæ°æ®ï¼æ¯æ¥æ¨¡æçæï¼0çå®è®¾å¤', |
| | | `initial_reading` decimal(20,6) DEFAULT NULL COMMENT 'æå·¥æè¡¨èµ·å§è¡¨ç ', |
| | | `initial_reading_date` date DEFAULT NULL COMMENT 'èµ·å§è¡¨ç 对åºä¸å¡æ¥æ', |
| | | `sync_start_date` date NOT NULL COMMENT 'æ¬è®¾å¤ææ©éè¦åæ¥çä¸å¡æ¥æ', |
| | | `last_success_at` datetime(3) DEFAULT NULL COMMENT 'æè¿æåéé/æè¡¨æ¶é´', |
| | | `last_error_code` varchar(64) DEFAULT NULL COMMENT 'æè¿ééé误类å«', |
| | | `last_error_message` varchar(255) DEFAULT NULL COMMENT 'è±æé误æè¦', |
| | | `create_user` bigint DEFAULT NULL COMMENT 'å建人', |
| | | `create_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'å建æ¶é´', |
| | | `update_user` bigint DEFAULT NULL COMMENT 'ä¿®æ¹äºº', |
| | | `update_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT 'ä¿®æ¹æ¶é´', |
| | | PRIMARY KEY (`id`), |
| | | UNIQUE KEY `uk_em_device_tenant_type_address` (`tenant_id`,`meter_type`,`meter_address`), |
| | | KEY `idx_em_device_scan` (`enabled`,`bind_status`,`meter_type`,`id`), |
| | | KEY `idx_em_device_parent` (`parent_meter_id`), |
| | | KEY `idx_em_device_source` (`tenant_id`,`source_type`,`meter_type`,`enabled`) |
| | | ) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='设å¤å°è´¦ï¼æ°´è¡¨/çµè¡¨/æ°è¡¨'; |
| | | |
| | | -- ---------------------------- |
| | | -- energy_meter_measurement |
| | | -- ---------------------------- |
| | | CREATE TABLE IF NOT EXISTS `energy_meter_measurement` ( |
| | | `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'ééæ°æ®ID', |
| | | `tenant_id` bigint NOT NULL COMMENT 'ç§æ·ID', |
| | | `meter_id` bigint NOT NULL COMMENT 'æ¬å°è®¾å¤ID', |
| | | `metric_code` varchar(32) NOT NULL COMMENT 'WATER_USAGE/WATER_READING/ELECTRIC_USAGE/ELECTRIC_READING/ELECTRIC_COST/GAS_USAGE/GAS_READING', |
| | | `granularity` varchar(8) NOT NULL COMMENT 'Dæ¥/Mæ/Yå¹´/POINTæ¶ç¹', |
| | | `measure_time` datetime NOT NULL COMMENT 'æé´èµ·ç¹æç¤ºå¼æ¶ç¹ï¼Asia/Shanghai', |
| | | `metric_value` decimal(20,6) NOT NULL COMMENT 'å®é
æé´ç¨éãç¤ºå¼æè´¹ç¨', |
| | | `unit` varchar(16) NOT NULL COMMENT 'm3/kWh/CNY', |
| | | `source_api` varchar(64) NOT NULL COMMENT 'æ¥æºæ è¯ï¼ç¬¬ä¸æ¹æ¥å£åæ MANUAL', |
| | | `source_record_time` datetime DEFAULT NULL COMMENT 'ç¬¬ä¸æ¹åå§ReadingDateè§£æå¼ï¼æå·¥æè¡¨ä¸ºæè¡¨æ¥æ', |
| | | `collected_at` datetime(3) NOT NULL COMMENT 'æ¬ç³»ç»ééæ¶é´', |
| | | `remark` varchar(255) DEFAULT NULL COMMENT '夿³¨ï¼æå·¥æè¡¨è¯´æ', |
| | | `create_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '馿¬¡å
¥åºæ¶é´', |
| | | `update_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT 'æåä¿®æ£æ¶é´', |
| | | PRIMARY KEY (`id`), |
| | | UNIQUE KEY `uk_em_measurement_point` (`meter_id`,`metric_code`,`granularity`,`measure_time`), |
| | | KEY `idx_em_measurement_query` (`tenant_id`,`meter_id`,`metric_code`,`granularity`,`measure_time`), |
| | | KEY `idx_em_measurement_time` (`tenant_id`,`metric_code`,`granularity`,`measure_time`), |
| | | KEY `idx_em_measurement_source` (`meter_id`,`source_api`,`granularity`,`measure_time`) |
| | | ) ENGINE=InnoDB AUTO_INCREMENT=8503 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='ç¨éã示å¼åå·²éªè¯è´¹ç¨'; |
| | | |
| | | -- ---------------------------- |
| | | -- energy_meter_sync_run |
| | | -- ---------------------------- |
| | | CREATE TABLE IF NOT EXISTS `energy_meter_sync_run` ( |
| | | `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'åæ¥æ¹æ¬¡ID', |
| | | `run_key` varchar(80) NOT NULL COMMENT 'èªå¨æ¹æ¬¡AUTO:yyyyMMddï¼æå¨æ¹æ¬¡ä½¿ç¨UUID', |
| | | `trigger_type` varchar(16) NOT NULL COMMENT 'SCHEDULED/MANUAL/BACKFILL', |
| | | `schedule_date` date DEFAULT NULL COMMENT 'è®¡åæ§è¡æ¥ï¼å京æ¶é´ï¼é宿¶æ¹æ¬¡ä¸ºç©º', |
| | | `range_start` date NOT NULL COMMENT '忥å¼å§æ¥æï¼å«', |
| | | `range_end` date NOT NULL COMMENT 'åæ¥ç»ææ¥æï¼å«', |
| | | `status` varchar(16) NOT NULL DEFAULT 'PENDING' COMMENT 'PENDING/RUNNING/SUCCESS/PARTIAL/FAILED', |
| | | `total_tasks` int NOT NULL DEFAULT '0' COMMENT '任塿»æ°', |
| | | `success_tasks` int NOT NULL DEFAULT '0' COMMENT 'æå任塿°', |
| | | `empty_tasks` int NOT NULL DEFAULT '0' COMMENT 'ç¡®è®¤æ æ°æ®ä»»å¡æ°', |
| | | `failed_tasks` int NOT NULL DEFAULT '0' COMMENT 'å¤±è´¥ä»»å¡æ°', |
| | | `started_at` datetime(3) DEFAULT NULL COMMENT 'å¼å§æ¶é´', |
| | | `finished_at` datetime(3) DEFAULT NULL COMMENT 'ç»ææ¶é´', |
| | | `error_summary` varchar(500) DEFAULT NULL COMMENT 'è±æé误æè¦', |
| | | `create_user` bigint DEFAULT NULL COMMENT '触å人ï¼ç³»ç»ä»»å¡ä¸ºç©º', |
| | | `create_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'å建æ¶é´', |
| | | `update_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT 'ä¿®æ¹æ¶é´', |
| | | PRIMARY KEY (`id`), |
| | | UNIQUE KEY `uk_em_sync_run_key` (`run_key`), |
| | | KEY `idx_em_sync_run_schedule` (`trigger_type`,`schedule_date`,`status`), |
| | | KEY `idx_em_sync_run_created` (`create_time`) |
| | | ) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='忥æ§è¡æ¹æ¬¡'; |
| | | |
| | | -- ---------------------------- |
| | | -- energy_meter_sync_task |
| | | -- ---------------------------- |
| | | CREATE TABLE IF NOT EXISTS `energy_meter_sync_task` ( |
| | | `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'å设å¤åæ¥å£åæ¥ä»»å¡ID', |
| | | `run_id` bigint NOT NULL COMMENT 'æå±æ¹æ¬¡ID', |
| | | `tenant_id` bigint NOT NULL COMMENT 'ç§æ·ID', |
| | | `meter_id` bigint NOT NULL COMMENT 'æ¬å°è®¾å¤ID', |
| | | `source_api` varchar(64) NOT NULL COMMENT 'ç¬¬ä¸æ¹æ¥å£æ è¯', |
| | | `granularity` varchar(8) NOT NULL COMMENT 'D/M/Y/POINT', |
| | | `range_start` date NOT NULL COMMENT '请æ±å¼å§æ¥æï¼å«', |
| | | `range_end` date NOT NULL COMMENT '请æ±ç»ææ¥æï¼å«', |
| | | `status` varchar(16) NOT NULL DEFAULT 'PENDING' COMMENT 'PENDING/RUNNING/SUCCESS/EMPTY/RETRY/FAILED', |
| | | `attempt_count` int NOT NULL DEFAULT '0' COMMENT 'å·²å°è¯æ¬¡æ°', |
| | | `next_retry_at` datetime(3) DEFAULT NULL COMMENT '䏿¬¡éè¯æ¶é´', |
| | | `fetched_count` int NOT NULL DEFAULT '0' COMMENT '䏿¸¸è¿åæ¡æ°', |
| | | `inserted_count` int NOT NULL DEFAULT '0' COMMENT 'æ°å¢æ¡æ°', |
| | | `updated_count` int NOT NULL DEFAULT '0' COMMENT 'ä¿®æ£æ¡æ°', |
| | | `error_code` varchar(64) DEFAULT NULL COMMENT 'è±æé误类å«', |
| | | `error_message` varchar(500) DEFAULT NULL COMMENT 'è±æé误信æ¯', |
| | | `started_at` datetime(3) DEFAULT NULL COMMENT 'å¼å§æ¶é´', |
| | | `finished_at` datetime(3) DEFAULT NULL COMMENT '宿æ¶é´', |
| | | `create_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'å建æ¶é´', |
| | | `update_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT 'ä¿®æ¹æ¶é´', |
| | | PRIMARY KEY (`id`), |
| | | UNIQUE KEY `uk_em_sync_task_unit` (`run_id`,`meter_id`,`source_api`,`granularity`,`range_start`,`range_end`), |
| | | KEY `idx_em_sync_task_retry` (`status`,`next_retry_at`), |
| | | KEY `idx_em_sync_task_meter` (`tenant_id`,`meter_id`,`create_time`), |
| | | KEY `idx_em_sync_task_run` (`run_id`,`status`) |
| | | ) ENGINE=InnoDB AUTO_INCREMENT=41 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='å设å¤åæ¥ä»»å¡åéè¯ç¶æ'; |
| | | |
| | | -- ---------------------------- |
| | | -- energy_meter_sync_checkpoint |
| | | -- ---------------------------- |
| | | CREATE TABLE IF NOT EXISTS `energy_meter_sync_checkpoint` ( |
| | | `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'è¡¥éè¿åº¦ID', |
| | | `tenant_id` bigint NOT NULL COMMENT 'ç§æ·ID', |
| | | `meter_id` bigint NOT NULL COMMENT 'æ¬å°è®¾å¤ID', |
| | | `source_api` varchar(64) NOT NULL COMMENT 'ç¬¬ä¸æ¹æ¥å£æ è¯', |
| | | `granularity` varchar(8) NOT NULL COMMENT 'D/M/Y/POINT', |
| | | `last_complete_date` date DEFAULT NULL COMMENT 'è¿ç»å®æå°çä¸å¡æ¥æï¼å«ï¼ä¸å¯è·¨è¿å¤±è´¥æ¥æ', |
| | | `last_success_at` datetime(3) DEFAULT NULL COMMENT 'æè¿æå确认æ¶é´', |
| | | `last_run_id` bigint DEFAULT NULL COMMENT 'æè¿æ¨è¿è¿åº¦çæ¹æ¬¡ID', |
| | | `create_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'å建æ¶é´', |
| | | `update_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT 'ä¿®æ¹æ¶é´', |
| | | PRIMARY KEY (`id`), |
| | | UNIQUE KEY `uk_em_sync_checkpoint_unit` (`meter_id`,`source_api`,`granularity`), |
| | | KEY `idx_em_sync_checkpoint_tenant` (`tenant_id`,`meter_id`) |
| | | ) ENGINE=InnoDB AUTO_INCREMENT=35 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='æ¯æ¥å£è¿ç»åæ¥è¿åº¦'; |
| | | |
| | | -- energy_meter_device: 15 rows |
| | | |
| | | INSERT INTO `energy_meter_device` (`id`, `tenant_id`, `meter_type`, `source_type`, `meter_address`, `provider_meter_id`, `provider_name`, `display_name`, `provider_area_id`, `provider_area_name`, `parent_provider_id`, `parent_meter_id`, `location`, `online_status`, `bind_status`, `enabled`, `is_seed`, `simulated`, `initial_reading`, `initial_reading_date`, `sync_start_date`, `last_success_at`, `last_error_code`, `last_error_message`, `create_user`, `create_time`, `update_user`, `update_time`) VALUES (1, 208, 'WATER', 'PROVIDER', '12541588057907', '32134', 'äºæ¥¼çè西å', 'äºæ¥¼çè西å', NULL, 'å
´çæºæµ·', NULL, NULL, 'äºæ¥¼çè西å', 1, 'VERIFIED', 1, 1, 0, NULL, NULL, '2026-10-13', '2026-11-04 15:17:39.697000', NULL, NULL, 1, '2026-11-04 15:08:50.606000', NULL, '2026-11-04 15:52:07.417000'); |
| | | |
| | | INSERT INTO `energy_meter_device` (`id`, `tenant_id`, `meter_type`, `source_type`, `meter_address`, `provider_meter_id`, `provider_name`, `display_name`, `provider_area_id`, `provider_area_name`, `parent_provider_id`, `parent_meter_id`, `location`, `online_status`, `bind_status`, `enabled`, `is_seed`, `simulated`, `initial_reading`, `initial_reading_date`, `sync_start_date`, `last_success_at`, `last_error_code`, `last_error_message`, `create_user`, `create_time`, `update_user`, `update_time`) VALUES (2, 208, 'WATER', 'PROVIDER', '12541588045261', '32133', 'äºæ¥¼çäº§ç¨æ°´æ»æ°´è¡¨', 'äºæ¥¼çäº§ç¨æ°´æ»æ°´è¡¨', NULL, 'å
´çæºæµ·', NULL, NULL, 'äºæ¥¼çäº§ç¨æ°´æ»æ°´è¡¨', 1, 'VERIFIED', 1, 1, 0, NULL, NULL, '2026-10-13', '2026-11-04 15:17:41.645000', NULL, NULL, 1, '2026-11-04 15:08:50.606000', NULL, '2026-11-04 15:17:41.654000'); |
| | | |
| | | INSERT INTO `energy_meter_device` (`id`, `tenant_id`, `meter_type`, `source_type`, `meter_address`, `provider_meter_id`, `provider_name`, `display_name`, `provider_area_id`, `provider_area_name`, `parent_provider_id`, `parent_meter_id`, `location`, `online_status`, `bind_status`, `enabled`, `is_seed`, `simulated`, `initial_reading`, `initial_reading_date`, `sync_start_date`, `last_success_at`, `last_error_code`, `last_error_message`, `create_user`, `create_time`, `update_user`, `update_time`) VALUES (3, 208, 'WATER', 'PROVIDER', '12541588057898', '32132', 'ç
®æ¯è水表', 'ç
®æ¯è水表', NULL, 'å
´çæºæµ·', NULL, NULL, 'ç
®æ¯è水表', 1, 'VERIFIED', 1, 1, 0, NULL, NULL, '2026-10-13', '2026-11-04 15:17:43.133000', NULL, NULL, 1, '2026-11-04 15:08:50.606000', NULL, '2026-11-04 15:17:43.141000'); |
| | | |
| | | INSERT INTO `energy_meter_device` (`id`, `tenant_id`, `meter_type`, `source_type`, `meter_address`, `provider_meter_id`, `provider_name`, `display_name`, `provider_area_id`, `provider_area_name`, `parent_provider_id`, `parent_meter_id`, `location`, `online_status`, `bind_status`, `enabled`, `is_seed`, `simulated`, `initial_reading`, `initial_reading_date`, `sync_start_date`, `last_success_at`, `last_error_code`, `last_error_message`, `create_user`, `create_time`, `update_user`, `update_time`) VALUES (4, 208, 'WATER', 'PROVIDER', '12541588057901', '32131', 'æåæºæ´æ¯èå¤', 'æåæºæ´æ¯èå¤', NULL, 'å
´çæºæµ·', NULL, NULL, 'æåæºæ´æ¯èå¤', 1, 'VERIFIED', 1, 1, 0, NULL, NULL, '2026-10-13', '2026-11-04 15:17:44.657000', NULL, NULL, 1, '2026-11-04 15:08:50.606000', NULL, '2026-11-04 15:17:44.669000'); |
| | | |
| | | INSERT INTO `energy_meter_device` (`id`, `tenant_id`, `meter_type`, `source_type`, `meter_address`, `provider_meter_id`, `provider_name`, `display_name`, `provider_area_id`, `provider_area_name`, `parent_provider_id`, `parent_meter_id`, `location`, `online_status`, `bind_status`, `enabled`, `is_seed`, `simulated`, `initial_reading`, `initial_reading_date`, `sync_start_date`, `last_success_at`, `last_error_code`, `last_error_message`, `create_user`, `create_time`, `update_user`, `update_time`) VALUES (5, 208, 'WATER', 'PROVIDER', '12541588057897', '32130', 'å忝è', 'å忝è', NULL, 'å
´çæºæµ·', NULL, NULL, 'å忝è', 1, 'VERIFIED', 1, 1, 0, NULL, NULL, '2026-10-13', '2026-11-04 15:17:46.156000', NULL, NULL, 1, '2026-11-04 15:08:50.606000', NULL, '2026-11-04 15:17:46.164000'); |
| | | |
| | | INSERT INTO `energy_meter_device` (`id`, `tenant_id`, `meter_type`, `source_type`, `meter_address`, `provider_meter_id`, `provider_name`, `display_name`, `provider_area_id`, `provider_area_name`, `parent_provider_id`, `parent_meter_id`, `location`, `online_status`, `bind_status`, `enabled`, `is_seed`, `simulated`, `initial_reading`, `initial_reading_date`, `sync_start_date`, `last_success_at`, `last_error_code`, `last_error_message`, `create_user`, `create_time`, `update_user`, `update_time`) VALUES (6, 208, 'WATER', 'PROVIDER', '12541588057908', '32123', '䏿¥¼çº¯åæ°´æ»è¡¨', '䏿¥¼çº¯åæ°´æ»è¡¨', NULL, 'å
´çæºæµ·', NULL, NULL, '䏿¥¼çº¯åæ°´æ»è¡¨', 1, 'VERIFIED', 1, 1, 0, NULL, NULL, '2026-10-13', '2026-11-04 15:19:54.095000', NULL, NULL, 1, '2026-11-04 15:08:50.606000', NULL, '2026-11-04 15:19:54.102000'); |
| | | |
| | | INSERT INTO `energy_meter_device` (`id`, `tenant_id`, `meter_type`, `source_type`, `meter_address`, `provider_meter_id`, `provider_name`, `display_name`, `provider_area_id`, `provider_area_name`, `parent_provider_id`, `parent_meter_id`, `location`, `online_status`, `bind_status`, `enabled`, `is_seed`, `simulated`, `initial_reading`, `initial_reading_date`, `sync_start_date`, `last_success_at`, `last_error_code`, `last_error_message`, `create_user`, `create_time`, `update_user`, `update_time`) VALUES (7, 208, 'ELECTRIC', 'PROVIDER', '712606021272', '270946', 'äºæ¥¼æ»çµè¡¨', 'äºæ¥¼æ»çµè¡¨', NULL, 'çµè¡¨', NULL, NULL, 'äºæ¥¼æ»çµè¡¨', 0, 'VERIFIED', 1, 1, 0, NULL, NULL, '2026-11-04', '2026-11-04 19:00:01.774000', NULL, NULL, 1, '2026-11-04 15:08:50.606000', NULL, '2026-11-04 19:00:01.787000'); |
| | | |
| | | INSERT INTO `energy_meter_device` (`id`, `tenant_id`, `meter_type`, `source_type`, `meter_address`, `provider_meter_id`, `provider_name`, `display_name`, `provider_area_id`, `provider_area_name`, `parent_provider_id`, `parent_meter_id`, `location`, `online_status`, `bind_status`, `enabled`, `is_seed`, `simulated`, `initial_reading`, `initial_reading_date`, `sync_start_date`, `last_success_at`, `last_error_code`, `last_error_message`, `create_user`, `create_time`, `update_user`, `update_time`) VALUES (8, 208, 'ELECTRIC', 'PROVIDER', '712606021277', '270949', '污水çµè¡¨', '污水çµè¡¨', NULL, 'çµè¡¨', NULL, NULL, '污水çµè¡¨', 0, 'VERIFIED', 1, 1, 0, NULL, NULL, '2026-11-04', '2026-11-04 19:00:01.984000', NULL, NULL, 1, '2026-11-04 15:08:50.606000', NULL, '2026-11-04 19:00:01.995000'); |
| | | |
| | | INSERT INTO `energy_meter_device` (`id`, `tenant_id`, `meter_type`, `source_type`, `meter_address`, `provider_meter_id`, `provider_name`, `display_name`, `provider_area_id`, `provider_area_name`, `parent_provider_id`, `parent_meter_id`, `location`, `online_status`, `bind_status`, `enabled`, `is_seed`, `simulated`, `initial_reading`, `initial_reading_date`, `sync_start_date`, `last_success_at`, `last_error_code`, `last_error_message`, `create_user`, `create_time`, `update_user`, `update_time`) VALUES (9, 208, 'ELECTRIC', 'PROVIDER', '712606021273', '270951', '䏿¥¼æ»çµè¡¨', '䏿¥¼æ»çµè¡¨', NULL, 'çµè¡¨', NULL, NULL, '䏿¥¼æ»çµè¡¨', 0, 'VERIFIED', 1, 1, 0, NULL, NULL, '2026-11-04', '2026-11-04 19:00:02.129000', NULL, NULL, 1, '2026-11-04 15:08:50.606000', NULL, '2026-11-04 19:00:02.137000'); |
| | | |
| | | INSERT INTO `energy_meter_device` (`id`, `tenant_id`, `meter_type`, `source_type`, `meter_address`, `provider_meter_id`, `provider_name`, `display_name`, `provider_area_id`, `provider_area_name`, `parent_provider_id`, `parent_meter_id`, `location`, `online_status`, `bind_status`, `enabled`, `is_seed`, `simulated`, `initial_reading`, `initial_reading_date`, `sync_start_date`, `last_success_at`, `last_error_code`, `last_error_message`, `create_user`, `create_time`, `update_user`, `update_time`) VALUES (10, 208, 'WATER', 'PROVIDER', '12541588057808', '32758', 'äºæ¥¼åæç
®é
çº¯åæ°´', 'äºæ¥¼åæç
®é
çº¯åæ°´', NULL, '水表', NULL, NULL, 'äºæ¥¼åæç
®é
çº¯åæ°´', 0, 'VERIFIED', 1, 1, 0, NULL, NULL, '2026-11-04', NULL, NULL, NULL, 1, '2026-11-04 15:08:50.606000', NULL, '2026-11-04 15:08:50.606000'); |
| | | |
| | | INSERT INTO `energy_meter_device` (`id`, `tenant_id`, `meter_type`, `source_type`, `meter_address`, `provider_meter_id`, `provider_name`, `display_name`, `provider_area_id`, `provider_area_name`, `parent_provider_id`, `parent_meter_id`, `location`, `online_status`, `bind_status`, `enabled`, `is_seed`, `simulated`, `initial_reading`, `initial_reading_date`, `sync_start_date`, `last_success_at`, `last_error_code`, `last_error_message`, `create_user`, `create_time`, `update_user`, `update_time`) VALUES (11, 208, 'GAS', 'MANUAL', '862873080705632', NULL, NULL, 'çè夿°è¡¨', NULL, NULL, NULL, NULL, 'çèå¤', NULL, 'VERIFIED', 1, 0, 1, 0.000000, '2026-11-04', '2025-09-01', '2026-11-04 00:00:00', NULL, NULL, 1, '2026-11-04 15:08:50.612000', NULL, '2026-11-04 17:02:17.039000'); |
| | | |
| | | INSERT INTO `energy_meter_device` (`id`, `tenant_id`, `meter_type`, `source_type`, `meter_address`, `provider_meter_id`, `provider_name`, `display_name`, `provider_area_id`, `provider_area_name`, `parent_provider_id`, `parent_meter_id`, `location`, `online_status`, `bind_status`, `enabled`, `is_seed`, `simulated`, `initial_reading`, `initial_reading_date`, `sync_start_date`, `last_success_at`, `last_error_code`, `last_error_message`, `create_user`, `create_time`, `update_user`, `update_time`) VALUES (12, 208, 'GAS', 'MANUAL', '865619085854645', NULL, NULL, 'ç
®é
䏿°è¡¨', NULL, NULL, NULL, NULL, 'ç
®é
ä¸', NULL, 'VERIFIED', 1, 0, 1, 0.000000, '2026-11-04', '2025-09-01', '2026-11-04 00:00:00', NULL, NULL, 1, '2026-11-04 15:08:50.612000', NULL, '2026-11-04 17:02:17.039000'); |
| | | |
| | | INSERT INTO `energy_meter_device` (`id`, `tenant_id`, `meter_type`, `source_type`, `meter_address`, `provider_meter_id`, `provider_name`, `display_name`, `provider_area_id`, `provider_area_name`, `parent_provider_id`, `parent_meter_id`, `location`, `online_status`, `bind_status`, `enabled`, `is_seed`, `simulated`, `initial_reading`, `initial_reading_date`, `sync_start_date`, `last_success_at`, `last_error_code`, `last_error_message`, `create_user`, `create_time`, `update_user`, `update_time`) VALUES (13, 208, 'GAS', 'MANUAL', '862873080702613', NULL, NULL, 'ç
®é
åæ°è¡¨', NULL, NULL, NULL, NULL, 'ç
®é
å', NULL, 'VERIFIED', 1, 0, 1, 0.000000, '2026-11-04', '2025-09-01', '2026-11-04 00:00:00', NULL, NULL, 1, '2026-11-04 15:08:50.612000', NULL, '2026-11-04 17:02:17.039000'); |
| | | |
| | | INSERT INTO `energy_meter_device` (`id`, `tenant_id`, `meter_type`, `source_type`, `meter_address`, `provider_meter_id`, `provider_name`, `display_name`, `provider_area_id`, `provider_area_name`, `parent_provider_id`, `parent_meter_id`, `location`, `online_status`, `bind_status`, `enabled`, `is_seed`, `simulated`, `initial_reading`, `initial_reading_date`, `sync_start_date`, `last_success_at`, `last_error_code`, `last_error_message`, `create_user`, `create_time`, `update_user`, `update_time`) VALUES (14, 208, 'GAS', 'MANUAL', '866960071744294', NULL, NULL, 'ç
®é
åæ°è¡¨', NULL, NULL, NULL, NULL, 'ç
®é
å', NULL, 'VERIFIED', 1, 0, 1, 0.000000, '2026-11-04', '2025-09-01', '2026-11-04 00:00:00', NULL, NULL, 1, '2026-11-04 15:08:50.612000', NULL, '2026-11-04 17:02:17.039000'); |
| | | |
| | | INSERT INTO `energy_meter_device` (`id`, `tenant_id`, `meter_type`, `source_type`, `meter_address`, `provider_meter_id`, `provider_name`, `display_name`, `provider_area_id`, `provider_area_name`, `parent_provider_id`, `parent_meter_id`, `location`, `online_status`, `bind_status`, `enabled`, `is_seed`, `simulated`, `initial_reading`, `initial_reading_date`, `sync_start_date`, `last_success_at`, `last_error_code`, `last_error_message`, `create_user`, `create_time`, `update_user`, `update_time`) VALUES (15, 208, 'GAS', 'MANUAL', '862873080704353', NULL, NULL, '䏿¥¼ç
®æ¯èæ°è¡¨', NULL, NULL, NULL, NULL, '䏿¥¼ç
®æ¯è', NULL, 'VERIFIED', 1, 0, 1, 0.000000, '2026-11-04', '2025-09-01', '2026-11-04 00:00:00', NULL, NULL, 1, '2026-11-04 15:08:50.612000', NULL, '2026-11-04 17:02:17.039000'); |
| | | |
| | | |
| | | -- energy_meter_measurement: 274 rows |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8198, 208, 1, 'WATER_READING', 'POINT', '2026-10-26 03:00:00', 19.000000, 'm3', 'GetWaterRawData', '2026-10-26 03:00:00', '2026-11-04 15:17:38.525000', NULL, '2026-11-04 15:17:38.999000', '2026-11-04 15:17:38.999000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8199, 208, 1, 'WATER_READING', 'POINT', '2026-10-25 03:00:00', 19.000000, 'm3', 'GetWaterRawData', '2026-10-25 03:00:00', '2026-11-04 15:17:38.525000', NULL, '2026-11-04 15:17:38.999000', '2026-11-04 15:17:38.999000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8200, 208, 1, 'WATER_READING', 'POINT', '2026-10-24 03:00:00', 19.000000, 'm3', 'GetWaterRawData', '2026-10-24 03:00:00', '2026-11-04 15:17:38.525000', NULL, '2026-11-04 15:17:38.999000', '2026-11-04 15:17:38.999000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8201, 208, 1, 'WATER_READING', 'POINT', '2026-10-23 03:00:00', 19.000000, 'm3', 'GetWaterRawData', '2026-10-23 03:00:00', '2026-11-04 15:17:38.525000', NULL, '2026-11-04 15:17:38.999000', '2026-11-04 15:17:38.999000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8202, 208, 1, 'WATER_READING', 'POINT', '2026-10-22 03:00:00', 19.000000, 'm3', 'GetWaterRawData', '2026-10-22 03:00:00', '2026-11-04 15:17:38.525000', NULL, '2026-11-04 15:17:38.999000', '2026-11-04 15:17:38.999000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8203, 208, 1, 'WATER_READING', 'POINT', '2026-10-21 03:00:00', 19.000000, 'm3', 'GetWaterRawData', '2026-10-21 03:00:00', '2026-11-04 15:17:38.525000', NULL, '2026-11-04 15:17:38.999000', '2026-11-04 15:17:38.999000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8204, 208, 1, 'WATER_READING', 'POINT', '2026-10-20 10:00:00', 19.000000, 'm3', 'GetWaterRawData', '2026-10-20 10:00:00', '2026-11-04 15:17:38.525000', NULL, '2026-11-04 15:17:38.999000', '2026-11-04 15:17:38.999000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8205, 208, 1, 'WATER_READING', 'POINT', '2026-10-20 03:00:00', 19.000000, 'm3', 'GetWaterRawData', '2026-10-20 03:00:00', '2026-11-04 15:17:38.525000', NULL, '2026-11-04 15:17:38.999000', '2026-11-04 15:17:38.999000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8206, 208, 1, 'WATER_READING', 'POINT', '2026-10-19 03:00:00', 18.000000, 'm3', 'GetWaterRawData', '2026-10-19 03:00:00', '2026-11-04 15:17:38.525000', NULL, '2026-11-04 15:17:38.999000', '2026-11-04 15:17:38.999000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8207, 208, 1, 'WATER_READING', 'POINT', '2026-10-18 03:00:00', 18.000000, 'm3', 'GetWaterRawData', '2026-10-18 03:00:00', '2026-11-04 15:17:38.525000', NULL, '2026-11-04 15:17:38.999000', '2026-11-04 15:17:38.999000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8208, 208, 1, 'WATER_READING', 'POINT', '2026-10-17 03:00:00', 18.000000, 'm3', 'GetWaterRawData', '2026-10-17 03:00:00', '2026-11-04 15:17:38.525000', NULL, '2026-11-04 15:17:38.999000', '2026-11-04 15:17:38.999000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8209, 208, 1, 'WATER_READING', 'POINT', '2026-10-16 03:00:00', 18.000000, 'm3', 'GetWaterRawData', '2026-10-16 03:00:00', '2026-11-04 15:17:38.525000', NULL, '2026-11-04 15:17:38.999000', '2026-11-04 15:17:38.999000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8210, 208, 1, 'WATER_READING', 'POINT', '2026-10-15 03:00:00', 17.000000, 'm3', 'GetWaterRawData', '2026-10-15 03:00:00', '2026-11-04 15:17:38.525000', NULL, '2026-11-04 15:17:38.999000', '2026-11-04 15:17:38.999000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8211, 208, 1, 'WATER_READING', 'POINT', '2026-10-14 03:00:00', 17.000000, 'm3', 'GetWaterRawData', '2026-10-14 03:00:00', '2026-11-04 15:17:38.525000', NULL, '2026-11-04 15:17:38.999000', '2026-11-04 15:17:38.999000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8212, 208, 1, 'WATER_READING', 'POINT', '2026-10-13 03:00:00', 17.000000, 'm3', 'GetWaterRawData', '2026-10-13 03:00:00', '2026-11-04 15:17:38.525000', NULL, '2026-11-04 15:17:38.999000', '2026-11-04 15:17:38.999000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8213, 208, 1, 'WATER_USAGE', 'D', '2026-11-03 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-11-03 00:00:00', '2026-11-04 15:17:38.525000', NULL, '2026-11-04 15:17:39.148000', '2026-11-04 15:17:39.148000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8214, 208, 1, 'WATER_USAGE', 'D', '2026-11-02 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-11-02 00:00:00', '2026-11-04 15:17:38.525000', NULL, '2026-11-04 15:17:39.148000', '2026-11-04 15:17:39.148000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8215, 208, 1, 'WATER_USAGE', 'D', '2026-11-01 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-11-01 00:00:00', '2026-11-04 15:17:38.525000', NULL, '2026-11-04 15:17:39.148000', '2026-11-04 15:17:39.148000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8216, 208, 1, 'WATER_USAGE', 'D', '2026-10-31 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-10-31 00:00:00', '2026-11-04 15:17:38.525000', NULL, '2026-11-04 15:17:39.148000', '2026-11-04 15:17:39.148000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8217, 208, 1, 'WATER_USAGE', 'D', '2026-10-30 00:00:00', 1.000000, 'm3', 'GetUseWater', '2026-10-30 00:00:00', '2026-11-04 15:17:38.525000', NULL, '2026-11-04 15:17:39.148000', '2026-11-04 15:17:39.148000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8218, 208, 1, 'WATER_USAGE', 'D', '2026-10-29 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-10-29 00:00:00', '2026-11-04 15:17:38.525000', NULL, '2026-11-04 15:17:39.148000', '2026-11-04 15:17:39.148000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8219, 208, 1, 'WATER_USAGE', 'D', '2026-10-28 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-10-28 00:00:00', '2026-11-04 15:17:38.525000', NULL, '2026-11-04 15:17:39.148000', '2026-11-04 15:17:39.148000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8220, 208, 1, 'WATER_USAGE', 'D', '2026-10-27 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-10-27 00:00:00', '2026-11-04 15:17:38.525000', NULL, '2026-11-04 15:17:39.148000', '2026-11-04 15:17:39.148000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8221, 208, 1, 'WATER_USAGE', 'D', '2026-10-26 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-10-26 00:00:00', '2026-11-04 15:17:38.525000', NULL, '2026-11-04 15:17:39.148000', '2026-11-04 15:17:39.148000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8222, 208, 1, 'WATER_USAGE', 'D', '2026-10-25 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-10-25 00:00:00', '2026-11-04 15:17:38.525000', NULL, '2026-11-04 15:17:39.148000', '2026-11-04 15:17:39.148000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8223, 208, 1, 'WATER_USAGE', 'D', '2026-10-24 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-10-24 00:00:00', '2026-11-04 15:17:38.525000', NULL, '2026-11-04 15:17:39.148000', '2026-11-04 15:17:39.148000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8224, 208, 1, 'WATER_USAGE', 'D', '2026-10-23 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-10-23 00:00:00', '2026-11-04 15:17:38.525000', NULL, '2026-11-04 15:17:39.148000', '2026-11-04 15:17:39.148000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8225, 208, 1, 'WATER_USAGE', 'D', '2026-10-22 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-10-22 00:00:00', '2026-11-04 15:17:38.525000', NULL, '2026-11-04 15:17:39.148000', '2026-11-04 15:17:39.148000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8226, 208, 1, 'WATER_USAGE', 'D', '2026-10-21 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-10-21 00:00:00', '2026-11-04 15:17:38.525000', NULL, '2026-11-04 15:17:39.148000', '2026-11-04 15:17:39.148000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8227, 208, 1, 'WATER_USAGE', 'D', '2026-10-20 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-10-20 00:00:00', '2026-11-04 15:17:38.525000', NULL, '2026-11-04 15:17:39.148000', '2026-11-04 15:17:39.148000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8228, 208, 1, 'WATER_USAGE', 'D', '2026-10-19 00:00:00', 1.000000, 'm3', 'GetUseWater', '2026-10-19 00:00:00', '2026-11-04 15:17:38.525000', NULL, '2026-11-04 15:17:39.148000', '2026-11-04 15:17:39.148000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8229, 208, 1, 'WATER_USAGE', 'D', '2026-10-18 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-10-18 00:00:00', '2026-11-04 15:17:38.525000', NULL, '2026-11-04 15:17:39.148000', '2026-11-04 15:17:39.148000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8230, 208, 1, 'WATER_USAGE', 'D', '2026-10-17 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-10-17 00:00:00', '2026-11-04 15:17:38.525000', NULL, '2026-11-04 15:17:39.148000', '2026-11-04 15:17:39.148000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8231, 208, 1, 'WATER_USAGE', 'D', '2026-10-16 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-10-16 00:00:00', '2026-11-04 15:17:38.525000', NULL, '2026-11-04 15:17:39.148000', '2026-11-04 15:17:39.148000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8232, 208, 1, 'WATER_USAGE', 'D', '2026-10-15 00:00:00', 1.000000, 'm3', 'GetUseWater', '2026-10-15 00:00:00', '2026-11-04 15:17:38.525000', NULL, '2026-11-04 15:17:39.148000', '2026-11-04 15:17:39.148000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8233, 208, 1, 'WATER_USAGE', 'D', '2026-10-14 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-10-14 00:00:00', '2026-11-04 15:17:38.525000', NULL, '2026-11-04 15:17:39.148000', '2026-11-04 15:17:39.148000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8234, 208, 1, 'WATER_USAGE', 'D', '2026-10-13 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-10-13 00:00:00', '2026-11-04 15:17:38.525000', NULL, '2026-11-04 15:17:39.148000', '2026-11-04 15:17:39.148000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8235, 208, 1, 'WATER_READING', 'POINT', '2026-11-02 03:00:00', 20.000000, 'm3', 'GetWaterRawData', '2026-11-02 03:00:00', '2026-11-04 15:17:39.028000', NULL, '2026-11-04 15:17:39.702000', '2026-11-04 15:17:39.702000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8236, 208, 1, 'WATER_READING', 'POINT', '2026-11-01 03:00:00', 20.000000, 'm3', 'GetWaterRawData', '2026-11-01 03:00:00', '2026-11-04 15:17:39.028000', NULL, '2026-11-04 15:17:39.702000', '2026-11-04 15:17:39.702000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8237, 208, 1, 'WATER_READING', 'POINT', '2026-10-31 03:00:00', 20.000000, 'm3', 'GetWaterRawData', '2026-10-31 03:00:00', '2026-11-04 15:17:39.028000', NULL, '2026-11-04 15:17:39.702000', '2026-11-04 15:17:39.702000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8238, 208, 1, 'WATER_READING', 'POINT', '2026-10-30 03:00:00', 19.000000, 'm3', 'GetWaterRawData', '2026-10-30 03:00:00', '2026-11-04 15:17:39.028000', NULL, '2026-11-04 15:17:39.702000', '2026-11-04 15:17:39.702000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8239, 208, 1, 'WATER_READING', 'POINT', '2026-10-29 03:00:00', 19.000000, 'm3', 'GetWaterRawData', '2026-10-29 03:00:00', '2026-11-04 15:17:39.028000', NULL, '2026-11-04 15:17:39.702000', '2026-11-04 15:17:39.702000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8240, 208, 1, 'WATER_READING', 'POINT', '2026-10-28 03:00:00', 19.000000, 'm3', 'GetWaterRawData', '2026-10-28 03:00:00', '2026-11-04 15:17:39.028000', NULL, '2026-11-04 15:17:39.702000', '2026-11-04 15:17:39.702000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8241, 208, 2, 'WATER_USAGE', 'D', '2026-11-03 00:00:00', 73.000000, 'm3', 'GetUseWater', '2026-11-03 00:00:00', '2026-11-04 15:17:39.175000', NULL, '2026-11-04 15:17:40.387000', '2026-11-04 15:17:40.387000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8242, 208, 2, 'WATER_USAGE', 'D', '2026-11-02 00:00:00', 24.000000, 'm3', 'GetUseWater', '2026-11-02 00:00:00', '2026-11-04 15:17:39.175000', NULL, '2026-11-04 15:17:40.387000', '2026-11-04 15:17:40.387000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8243, 208, 2, 'WATER_USAGE', 'D', '2026-11-01 00:00:00', 26.000000, 'm3', 'GetUseWater', '2026-11-01 00:00:00', '2026-11-04 15:17:39.175000', NULL, '2026-11-04 15:17:40.387000', '2026-11-04 15:17:40.387000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8244, 208, 2, 'WATER_USAGE', 'D', '2026-10-31 00:00:00', 34.000000, 'm3', 'GetUseWater', '2026-10-31 00:00:00', '2026-11-04 15:17:39.175000', NULL, '2026-11-04 15:17:40.387000', '2026-11-04 15:17:40.387000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8245, 208, 2, 'WATER_USAGE', 'D', '2026-10-30 00:00:00', 48.000000, 'm3', 'GetUseWater', '2026-10-30 00:00:00', '2026-11-04 15:17:39.175000', NULL, '2026-11-04 15:17:40.387000', '2026-11-04 15:17:40.387000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8246, 208, 2, 'WATER_USAGE', 'D', '2026-10-29 00:00:00', 46.000000, 'm3', 'GetUseWater', '2026-10-29 00:00:00', '2026-11-04 15:17:39.175000', NULL, '2026-11-04 15:17:40.387000', '2026-11-04 15:17:40.387000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8247, 208, 2, 'WATER_USAGE', 'D', '2026-10-28 00:00:00', 55.000000, 'm3', 'GetUseWater', '2026-10-28 00:00:00', '2026-11-04 15:17:39.175000', NULL, '2026-11-04 15:17:40.387000', '2026-11-04 15:17:40.387000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8248, 208, 2, 'WATER_USAGE', 'D', '2026-10-27 00:00:00', 62.000000, 'm3', 'GetUseWater', '2026-10-27 00:00:00', '2026-11-04 15:17:39.175000', NULL, '2026-11-04 15:17:40.387000', '2026-11-04 15:17:40.387000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8249, 208, 2, 'WATER_USAGE', 'D', '2026-10-26 00:00:00', 55.000000, 'm3', 'GetUseWater', '2026-10-26 00:00:00', '2026-11-04 15:17:39.175000', NULL, '2026-11-04 15:17:40.387000', '2026-11-04 15:17:40.387000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8250, 208, 2, 'WATER_USAGE', 'D', '2026-10-25 00:00:00', 58.000000, 'm3', 'GetUseWater', '2026-10-25 00:00:00', '2026-11-04 15:17:39.175000', NULL, '2026-11-04 15:17:40.387000', '2026-11-04 15:17:40.387000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8251, 208, 2, 'WATER_USAGE', 'D', '2026-10-24 00:00:00', 58.000000, 'm3', 'GetUseWater', '2026-10-24 00:00:00', '2026-11-04 15:17:39.175000', NULL, '2026-11-04 15:17:40.387000', '2026-11-04 15:17:40.387000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8252, 208, 2, 'WATER_USAGE', 'D', '2026-10-23 00:00:00', 68.000000, 'm3', 'GetUseWater', '2026-10-23 00:00:00', '2026-11-04 15:17:39.175000', NULL, '2026-11-04 15:17:40.387000', '2026-11-04 15:17:40.387000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8253, 208, 2, 'WATER_USAGE', 'D', '2026-10-22 00:00:00', 61.000000, 'm3', 'GetUseWater', '2026-10-22 00:00:00', '2026-11-04 15:17:39.175000', NULL, '2026-11-04 15:17:40.387000', '2026-11-04 15:17:40.387000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8254, 208, 2, 'WATER_USAGE', 'D', '2026-10-21 00:00:00', 68.000000, 'm3', 'GetUseWater', '2026-10-21 00:00:00', '2026-11-04 15:17:39.175000', NULL, '2026-11-04 15:17:40.387000', '2026-11-04 15:17:40.387000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8255, 208, 2, 'WATER_USAGE', 'D', '2026-10-20 00:00:00', 71.000000, 'm3', 'GetUseWater', '2026-10-20 00:00:00', '2026-11-04 15:17:39.175000', NULL, '2026-11-04 15:17:40.387000', '2026-11-04 15:17:40.387000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8256, 208, 2, 'WATER_USAGE', 'D', '2026-10-19 00:00:00', 55.000000, 'm3', 'GetUseWater', '2026-10-19 00:00:00', '2026-11-04 15:17:39.175000', NULL, '2026-11-04 15:17:40.387000', '2026-11-04 15:17:40.387000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8257, 208, 2, 'WATER_USAGE', 'D', '2026-10-18 00:00:00', 61.000000, 'm3', 'GetUseWater', '2026-10-18 00:00:00', '2026-11-04 15:17:39.175000', NULL, '2026-11-04 15:17:40.387000', '2026-11-04 15:17:40.387000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8258, 208, 2, 'WATER_USAGE', 'D', '2026-10-17 00:00:00', 27.000000, 'm3', 'GetUseWater', '2026-10-17 00:00:00', '2026-11-04 15:17:39.175000', NULL, '2026-11-04 15:17:40.387000', '2026-11-04 15:17:40.387000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8259, 208, 2, 'WATER_USAGE', 'D', '2026-10-16 00:00:00', 23.000000, 'm3', 'GetUseWater', '2026-10-16 00:00:00', '2026-11-04 15:17:39.175000', NULL, '2026-11-04 15:17:40.387000', '2026-11-04 15:17:40.387000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8260, 208, 2, 'WATER_USAGE', 'D', '2026-10-15 00:00:00', 42.000000, 'm3', 'GetUseWater', '2026-10-15 00:00:00', '2026-11-04 15:17:39.175000', NULL, '2026-11-04 15:17:40.387000', '2026-11-04 15:17:40.387000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8261, 208, 2, 'WATER_USAGE', 'D', '2026-10-14 00:00:00', 40.000000, 'm3', 'GetUseWater', '2026-10-14 00:00:00', '2026-11-04 15:17:39.175000', NULL, '2026-11-04 15:17:40.387000', '2026-11-04 15:17:40.387000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8262, 208, 2, 'WATER_USAGE', 'D', '2026-10-13 00:00:00', 39.000000, 'm3', 'GetUseWater', '2026-10-13 00:00:00', '2026-11-04 15:17:39.175000', NULL, '2026-11-04 15:17:40.387000', '2026-11-04 15:17:40.387000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8263, 208, 2, 'WATER_READING', 'POINT', '2026-10-26 07:00:00', 3055.000000, 'm3', 'GetWaterRawData', '2026-10-26 07:00:00', '2026-11-04 15:17:39.726000', NULL, '2026-11-04 15:17:40.642000', '2026-11-04 15:17:40.642000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8264, 208, 2, 'WATER_READING', 'POINT', '2026-10-25 07:00:00', 2997.000000, 'm3', 'GetWaterRawData', '2026-10-25 07:00:00', '2026-11-04 15:17:39.726000', NULL, '2026-11-04 15:17:40.642000', '2026-11-04 15:17:40.642000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8265, 208, 2, 'WATER_READING', 'POINT', '2026-10-24 07:00:00', 2939.000000, 'm3', 'GetWaterRawData', '2026-10-24 07:00:00', '2026-11-04 15:17:39.726000', NULL, '2026-11-04 15:17:40.642000', '2026-11-04 15:17:40.642000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8266, 208, 2, 'WATER_READING', 'POINT', '2026-10-23 07:00:00', 2871.000000, 'm3', 'GetWaterRawData', '2026-10-23 07:00:00', '2026-11-04 15:17:39.726000', NULL, '2026-11-04 15:17:40.642000', '2026-11-04 15:17:40.642000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8267, 208, 2, 'WATER_READING', 'POINT', '2026-10-22 07:00:00', 2810.000000, 'm3', 'GetWaterRawData', '2026-10-22 07:00:00', '2026-11-04 15:17:39.726000', NULL, '2026-11-04 15:17:40.642000', '2026-11-04 15:17:40.642000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8268, 208, 2, 'WATER_READING', 'POINT', '2026-10-21 07:00:00', 2742.000000, 'm3', 'GetWaterRawData', '2026-10-21 07:00:00', '2026-11-04 15:17:39.726000', NULL, '2026-11-04 15:17:40.642000', '2026-11-04 15:17:40.642000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8269, 208, 2, 'WATER_READING', 'POINT', '2026-10-20 07:00:00', 2671.000000, 'm3', 'GetWaterRawData', '2026-10-20 07:00:00', '2026-11-04 15:17:39.726000', NULL, '2026-11-04 15:17:40.642000', '2026-11-04 15:17:40.642000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8270, 208, 2, 'WATER_READING', 'POINT', '2026-10-19 07:00:00', 2616.000000, 'm3', 'GetWaterRawData', '2026-10-19 07:00:00', '2026-11-04 15:17:39.726000', NULL, '2026-11-04 15:17:40.642000', '2026-11-04 15:17:40.642000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8271, 208, 2, 'WATER_READING', 'POINT', '2026-10-18 07:00:00', 2555.000000, 'm3', 'GetWaterRawData', '2026-10-18 07:00:00', '2026-11-04 15:17:39.726000', NULL, '2026-11-04 15:17:40.642000', '2026-11-04 15:17:40.642000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8272, 208, 2, 'WATER_READING', 'POINT', '2026-10-17 07:00:00', 2528.000000, 'm3', 'GetWaterRawData', '2026-10-17 07:00:00', '2026-11-04 15:17:39.726000', NULL, '2026-11-04 15:17:40.642000', '2026-11-04 15:17:40.642000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8273, 208, 2, 'WATER_READING', 'POINT', '2026-10-16 07:00:00', 2505.000000, 'm3', 'GetWaterRawData', '2026-10-16 07:00:00', '2026-11-04 15:17:39.726000', NULL, '2026-11-04 15:17:40.642000', '2026-11-04 15:17:40.642000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8274, 208, 2, 'WATER_READING', 'POINT', '2026-10-15 07:00:00', 2463.000000, 'm3', 'GetWaterRawData', '2026-10-15 07:00:00', '2026-11-04 15:17:39.726000', NULL, '2026-11-04 15:17:40.642000', '2026-11-04 15:17:40.642000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8275, 208, 2, 'WATER_READING', 'POINT', '2026-10-14 07:00:00', 2423.000000, 'm3', 'GetWaterRawData', '2026-10-14 07:00:00', '2026-11-04 15:17:39.726000', NULL, '2026-11-04 15:17:40.642000', '2026-11-04 15:17:40.642000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8276, 208, 2, 'WATER_READING', 'POINT', '2026-10-13 07:00:00', 2384.000000, 'm3', 'GetWaterRawData', '2026-10-13 07:00:00', '2026-11-04 15:17:39.726000', NULL, '2026-11-04 15:17:40.642000', '2026-11-04 15:17:40.642000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8277, 208, 3, 'WATER_USAGE', 'D', '2026-11-03 00:00:00', 4.000000, 'm3', 'GetUseWater', '2026-11-03 00:00:00', '2026-11-04 15:17:40.418000', NULL, '2026-11-04 15:17:41.138000', '2026-11-04 15:17:41.138000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8278, 208, 3, 'WATER_USAGE', 'D', '2026-11-02 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-11-02 00:00:00', '2026-11-04 15:17:40.418000', NULL, '2026-11-04 15:17:41.138000', '2026-11-04 15:17:41.138000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8279, 208, 3, 'WATER_USAGE', 'D', '2026-11-01 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-11-01 00:00:00', '2026-11-04 15:17:40.418000', NULL, '2026-11-04 15:17:41.138000', '2026-11-04 15:17:41.138000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8280, 208, 3, 'WATER_USAGE', 'D', '2026-10-31 00:00:00', 13.000000, 'm3', 'GetUseWater', '2026-10-31 00:00:00', '2026-11-04 15:17:40.418000', NULL, '2026-11-04 15:17:41.138000', '2026-11-04 15:17:41.138000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8281, 208, 3, 'WATER_USAGE', 'D', '2026-10-30 00:00:00', 11.000000, 'm3', 'GetUseWater', '2026-10-30 00:00:00', '2026-11-04 15:17:40.418000', NULL, '2026-11-04 15:17:41.138000', '2026-11-04 15:17:41.138000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8282, 208, 3, 'WATER_USAGE', 'D', '2026-10-29 00:00:00', 9.000000, 'm3', 'GetUseWater', '2026-10-29 00:00:00', '2026-11-04 15:17:40.418000', NULL, '2026-11-04 15:17:41.138000', '2026-11-04 15:17:41.138000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8283, 208, 3, 'WATER_USAGE', 'D', '2026-10-28 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-10-28 00:00:00', '2026-11-04 15:17:40.418000', NULL, '2026-11-04 15:17:41.138000', '2026-11-04 15:17:41.138000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8284, 208, 3, 'WATER_USAGE', 'D', '2026-10-27 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-10-27 00:00:00', '2026-11-04 15:17:40.418000', NULL, '2026-11-04 15:17:41.138000', '2026-11-04 15:17:41.138000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8285, 208, 3, 'WATER_USAGE', 'D', '2026-10-26 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-10-26 00:00:00', '2026-11-04 15:17:40.418000', NULL, '2026-11-04 15:17:41.138000', '2026-11-04 15:17:41.138000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8286, 208, 3, 'WATER_USAGE', 'D', '2026-10-25 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-10-25 00:00:00', '2026-11-04 15:17:40.418000', NULL, '2026-11-04 15:17:41.138000', '2026-11-04 15:17:41.138000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8287, 208, 3, 'WATER_USAGE', 'D', '2026-10-24 00:00:00', 16.000000, 'm3', 'GetUseWater', '2026-10-24 00:00:00', '2026-11-04 15:17:40.418000', NULL, '2026-11-04 15:17:41.138000', '2026-11-04 15:17:41.138000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8288, 208, 3, 'WATER_USAGE', 'D', '2026-10-23 00:00:00', 16.000000, 'm3', 'GetUseWater', '2026-10-23 00:00:00', '2026-11-04 15:17:40.418000', NULL, '2026-11-04 15:17:41.138000', '2026-11-04 15:17:41.138000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8289, 208, 3, 'WATER_USAGE', 'D', '2026-10-22 00:00:00', 10.000000, 'm3', 'GetUseWater', '2026-10-22 00:00:00', '2026-11-04 15:17:40.418000', NULL, '2026-11-04 15:17:41.138000', '2026-11-04 15:17:41.138000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8290, 208, 3, 'WATER_USAGE', 'D', '2026-10-21 00:00:00', 5.000000, 'm3', 'GetUseWater', '2026-10-21 00:00:00', '2026-11-04 15:17:40.418000', NULL, '2026-11-04 15:17:41.138000', '2026-11-04 15:17:41.138000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8291, 208, 3, 'WATER_USAGE', 'D', '2026-10-20 00:00:00', 6.000000, 'm3', 'GetUseWater', '2026-10-20 00:00:00', '2026-11-04 15:17:40.418000', NULL, '2026-11-04 15:17:41.138000', '2026-11-04 15:17:41.138000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8292, 208, 3, 'WATER_USAGE', 'D', '2026-10-19 00:00:00', 1.000000, 'm3', 'GetUseWater', '2026-10-19 00:00:00', '2026-11-04 15:17:40.418000', NULL, '2026-11-04 15:17:41.138000', '2026-11-04 15:17:41.138000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8293, 208, 3, 'WATER_USAGE', 'D', '2026-10-18 00:00:00', 3.000000, 'm3', 'GetUseWater', '2026-10-18 00:00:00', '2026-11-04 15:17:40.418000', NULL, '2026-11-04 15:17:41.138000', '2026-11-04 15:17:41.138000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8294, 208, 3, 'WATER_USAGE', 'D', '2026-10-17 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-10-17 00:00:00', '2026-11-04 15:17:40.418000', NULL, '2026-11-04 15:17:41.138000', '2026-11-04 15:17:41.138000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8295, 208, 3, 'WATER_USAGE', 'D', '2026-10-16 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-10-16 00:00:00', '2026-11-04 15:17:40.418000', NULL, '2026-11-04 15:17:41.138000', '2026-11-04 15:17:41.138000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8296, 208, 3, 'WATER_USAGE', 'D', '2026-10-15 00:00:00', 12.000000, 'm3', 'GetUseWater', '2026-10-15 00:00:00', '2026-11-04 15:17:40.418000', NULL, '2026-11-04 15:17:41.138000', '2026-11-04 15:17:41.138000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8297, 208, 3, 'WATER_USAGE', 'D', '2026-10-14 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-10-14 00:00:00', '2026-11-04 15:17:40.418000', NULL, '2026-11-04 15:17:41.138000', '2026-11-04 15:17:41.138000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8298, 208, 3, 'WATER_USAGE', 'D', '2026-10-13 00:00:00', 4.000000, 'm3', 'GetUseWater', '2026-10-13 00:00:00', '2026-11-04 15:17:40.418000', NULL, '2026-11-04 15:17:41.138000', '2026-11-04 15:17:41.138000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8299, 208, 2, 'WATER_READING', 'POINT', '2026-11-02 07:00:00', 3381.000000, 'm3', 'GetWaterRawData', '2026-11-02 07:00:00', '2026-11-04 15:17:40.672000', NULL, '2026-11-04 15:17:41.650000', '2026-11-04 15:17:41.650000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8300, 208, 2, 'WATER_READING', 'POINT', '2026-11-01 07:00:00', 3355.000000, 'm3', 'GetWaterRawData', '2026-11-01 07:00:00', '2026-11-04 15:17:40.672000', NULL, '2026-11-04 15:17:41.650000', '2026-11-04 15:17:41.650000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8301, 208, 2, 'WATER_READING', 'POINT', '2026-10-31 07:00:00', 3321.000000, 'm3', 'GetWaterRawData', '2026-10-31 07:00:00', '2026-11-04 15:17:40.672000', NULL, '2026-11-04 15:17:41.650000', '2026-11-04 15:17:41.650000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8302, 208, 2, 'WATER_READING', 'POINT', '2026-10-30 07:00:00', 3273.000000, 'm3', 'GetWaterRawData', '2026-10-30 07:00:00', '2026-11-04 15:17:40.672000', NULL, '2026-11-04 15:17:41.650000', '2026-11-04 15:17:41.650000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8303, 208, 2, 'WATER_READING', 'POINT', '2026-10-29 07:00:00', 3227.000000, 'm3', 'GetWaterRawData', '2026-10-29 07:00:00', '2026-11-04 15:17:40.672000', NULL, '2026-11-04 15:17:41.650000', '2026-11-04 15:17:41.650000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8304, 208, 2, 'WATER_READING', 'POINT', '2026-10-28 07:00:00', 3172.000000, 'm3', 'GetWaterRawData', '2026-10-28 07:00:00', '2026-11-04 15:17:40.672000', NULL, '2026-11-04 15:17:41.650000', '2026-11-04 15:17:41.650000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8305, 208, 3, 'WATER_READING', 'POINT', '2026-10-26 01:00:00', 370.000000, 'm3', 'GetWaterRawData', '2026-10-26 01:00:00', '2026-11-04 15:17:41.167000', NULL, '2026-11-04 15:17:42.176000', '2026-11-04 15:17:42.176000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8306, 208, 3, 'WATER_READING', 'POINT', '2026-10-25 01:00:00', 370.000000, 'm3', 'GetWaterRawData', '2026-10-25 01:00:00', '2026-11-04 15:17:41.167000', NULL, '2026-11-04 15:17:42.176000', '2026-11-04 15:17:42.176000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8307, 208, 3, 'WATER_READING', 'POINT', '2026-10-24 01:00:00', 354.000000, 'm3', 'GetWaterRawData', '2026-10-24 01:00:00', '2026-11-04 15:17:41.167000', NULL, '2026-11-04 15:17:42.176000', '2026-11-04 15:17:42.176000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8308, 208, 3, 'WATER_READING', 'POINT', '2026-10-23 01:00:00', 338.000000, 'm3', 'GetWaterRawData', '2026-10-23 01:00:00', '2026-11-04 15:17:41.167000', NULL, '2026-11-04 15:17:42.176000', '2026-11-04 15:17:42.176000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8309, 208, 3, 'WATER_READING', 'POINT', '2026-10-22 01:00:00', 328.000000, 'm3', 'GetWaterRawData', '2026-10-22 01:00:00', '2026-11-04 15:17:41.167000', NULL, '2026-11-04 15:17:42.176000', '2026-11-04 15:17:42.176000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8310, 208, 3, 'WATER_READING', 'POINT', '2026-10-21 01:00:00', 323.000000, 'm3', 'GetWaterRawData', '2026-10-21 01:00:00', '2026-11-04 15:17:41.167000', NULL, '2026-11-04 15:17:42.176000', '2026-11-04 15:17:42.176000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8311, 208, 3, 'WATER_READING', 'POINT', '2026-10-20 01:00:00', 317.000000, 'm3', 'GetWaterRawData', '2026-10-20 01:00:00', '2026-11-04 15:17:41.167000', NULL, '2026-11-04 15:17:42.176000', '2026-11-04 15:17:42.176000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8312, 208, 3, 'WATER_READING', 'POINT', '2026-10-19 01:00:00', 316.000000, 'm3', 'GetWaterRawData', '2026-10-19 01:00:00', '2026-11-04 15:17:41.167000', NULL, '2026-11-04 15:17:42.176000', '2026-11-04 15:17:42.176000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8313, 208, 3, 'WATER_READING', 'POINT', '2026-10-18 01:00:00', 313.000000, 'm3', 'GetWaterRawData', '2026-10-18 01:00:00', '2026-11-04 15:17:41.167000', NULL, '2026-11-04 15:17:42.176000', '2026-11-04 15:17:42.176000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8314, 208, 3, 'WATER_READING', 'POINT', '2026-10-17 01:00:00', 313.000000, 'm3', 'GetWaterRawData', '2026-10-17 01:00:00', '2026-11-04 15:17:41.167000', NULL, '2026-11-04 15:17:42.176000', '2026-11-04 15:17:42.176000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8315, 208, 3, 'WATER_READING', 'POINT', '2026-10-16 01:00:00', 313.000000, 'm3', 'GetWaterRawData', '2026-10-16 01:00:00', '2026-11-04 15:17:41.167000', NULL, '2026-11-04 15:17:42.176000', '2026-11-04 15:17:42.176000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8316, 208, 3, 'WATER_READING', 'POINT', '2026-10-15 01:00:00', 301.000000, 'm3', 'GetWaterRawData', '2026-10-15 01:00:00', '2026-11-04 15:17:41.167000', NULL, '2026-11-04 15:17:42.176000', '2026-11-04 15:17:42.176000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8317, 208, 3, 'WATER_READING', 'POINT', '2026-10-14 08:00:00', 301.000000, 'm3', 'GetWaterRawData', '2026-10-14 08:00:00', '2026-11-04 15:17:41.167000', NULL, '2026-11-04 15:17:42.176000', '2026-11-04 15:17:42.176000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8318, 208, 3, 'WATER_READING', 'POINT', '2026-10-14 01:00:00', 301.000000, 'm3', 'GetWaterRawData', '2026-10-14 01:00:00', '2026-11-04 15:17:41.167000', NULL, '2026-11-04 15:17:42.176000', '2026-11-04 15:17:42.176000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8319, 208, 3, 'WATER_READING', 'POINT', '2026-10-13 08:00:00', 298.000000, 'm3', 'GetWaterRawData', '2026-10-13 08:00:00', '2026-11-04 15:17:41.167000', NULL, '2026-11-04 15:17:42.176000', '2026-11-04 15:17:42.176000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8320, 208, 3, 'WATER_READING', 'POINT', '2026-10-13 01:00:00', 297.000000, 'm3', 'GetWaterRawData', '2026-10-13 01:00:00', '2026-11-04 15:17:41.167000', NULL, '2026-11-04 15:17:42.176000', '2026-11-04 15:17:42.176000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8321, 208, 4, 'WATER_USAGE', 'D', '2026-11-03 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-11-03 00:00:00', '2026-11-04 15:17:41.673000', NULL, '2026-11-04 15:17:42.667000', '2026-11-04 15:17:42.667000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8322, 208, 4, 'WATER_USAGE', 'D', '2026-11-02 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-11-02 00:00:00', '2026-11-04 15:17:41.673000', NULL, '2026-11-04 15:17:42.667000', '2026-11-04 15:17:42.667000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8323, 208, 4, 'WATER_USAGE', 'D', '2026-11-01 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-11-01 00:00:00', '2026-11-04 15:17:41.673000', NULL, '2026-11-04 15:17:42.667000', '2026-11-04 15:17:42.667000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8324, 208, 4, 'WATER_USAGE', 'D', '2026-10-31 00:00:00', 28.000000, 'm3', 'GetUseWater', '2026-10-31 00:00:00', '2026-11-04 15:17:41.673000', NULL, '2026-11-04 15:17:42.667000', '2026-11-04 15:17:42.667000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8325, 208, 4, 'WATER_USAGE', 'D', '2026-10-30 00:00:00', 27.000000, 'm3', 'GetUseWater', '2026-10-30 00:00:00', '2026-11-04 15:17:41.673000', NULL, '2026-11-04 15:17:42.667000', '2026-11-04 15:17:42.667000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8326, 208, 4, 'WATER_USAGE', 'D', '2026-10-29 00:00:00', 27.000000, 'm3', 'GetUseWater', '2026-10-29 00:00:00', '2026-11-04 15:17:41.673000', NULL, '2026-11-04 15:17:42.667000', '2026-11-04 15:17:42.667000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8327, 208, 4, 'WATER_USAGE', 'D', '2026-10-28 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-10-28 00:00:00', '2026-11-04 15:17:41.673000', NULL, '2026-11-04 15:17:42.667000', '2026-11-04 15:17:42.667000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8328, 208, 4, 'WATER_USAGE', 'D', '2026-10-27 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-10-27 00:00:00', '2026-11-04 15:17:41.673000', NULL, '2026-11-04 15:17:42.667000', '2026-11-04 15:17:42.667000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8329, 208, 4, 'WATER_USAGE', 'D', '2026-10-26 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-10-26 00:00:00', '2026-11-04 15:17:41.673000', NULL, '2026-11-04 15:17:42.667000', '2026-11-04 15:17:42.667000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8330, 208, 4, 'WATER_USAGE', 'D', '2026-10-25 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-10-25 00:00:00', '2026-11-04 15:17:41.673000', NULL, '2026-11-04 15:17:42.667000', '2026-11-04 15:17:42.667000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8331, 208, 4, 'WATER_USAGE', 'D', '2026-10-24 00:00:00', 35.000000, 'm3', 'GetUseWater', '2026-10-24 00:00:00', '2026-11-04 15:17:41.673000', NULL, '2026-11-04 15:17:42.667000', '2026-11-04 15:17:42.667000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8332, 208, 4, 'WATER_USAGE', 'D', '2026-10-23 00:00:00', 32.000000, 'm3', 'GetUseWater', '2026-10-23 00:00:00', '2026-11-04 15:17:41.673000', NULL, '2026-11-04 15:17:42.667000', '2026-11-04 15:17:42.667000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8333, 208, 4, 'WATER_USAGE', 'D', '2026-10-22 00:00:00', 32.000000, 'm3', 'GetUseWater', '2026-10-22 00:00:00', '2026-11-04 15:17:41.673000', NULL, '2026-11-04 15:17:42.667000', '2026-11-04 15:17:42.667000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8334, 208, 4, 'WATER_USAGE', 'D', '2026-10-21 00:00:00', 20.000000, 'm3', 'GetUseWater', '2026-10-21 00:00:00', '2026-11-04 15:17:41.673000', NULL, '2026-11-04 15:17:42.667000', '2026-11-04 15:17:42.667000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8335, 208, 4, 'WATER_USAGE', 'D', '2026-10-20 00:00:00', 19.000000, 'm3', 'GetUseWater', '2026-10-20 00:00:00', '2026-11-04 15:17:41.673000', NULL, '2026-11-04 15:17:42.667000', '2026-11-04 15:17:42.667000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8336, 208, 4, 'WATER_USAGE', 'D', '2026-10-19 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-10-19 00:00:00', '2026-11-04 15:17:41.673000', NULL, '2026-11-04 15:17:42.667000', '2026-11-04 15:17:42.667000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8337, 208, 4, 'WATER_USAGE', 'D', '2026-10-18 00:00:00', 11.000000, 'm3', 'GetUseWater', '2026-10-18 00:00:00', '2026-11-04 15:17:41.673000', NULL, '2026-11-04 15:17:42.667000', '2026-11-04 15:17:42.667000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8338, 208, 4, 'WATER_USAGE', 'D', '2026-10-17 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-10-17 00:00:00', '2026-11-04 15:17:41.673000', NULL, '2026-11-04 15:17:42.667000', '2026-11-04 15:17:42.667000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8339, 208, 4, 'WATER_USAGE', 'D', '2026-10-16 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-10-16 00:00:00', '2026-11-04 15:17:41.673000', NULL, '2026-11-04 15:17:42.667000', '2026-11-04 15:17:42.667000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8340, 208, 4, 'WATER_USAGE', 'D', '2026-10-15 00:00:00', 39.000000, 'm3', 'GetUseWater', '2026-10-15 00:00:00', '2026-11-04 15:17:41.673000', NULL, '2026-11-04 15:17:42.667000', '2026-11-04 15:17:42.667000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8341, 208, 4, 'WATER_USAGE', 'D', '2026-10-14 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-10-14 00:00:00', '2026-11-04 15:17:41.673000', NULL, '2026-11-04 15:17:42.667000', '2026-11-04 15:17:42.667000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8342, 208, 4, 'WATER_USAGE', 'D', '2026-10-13 00:00:00', 5.000000, 'm3', 'GetUseWater', '2026-10-13 00:00:00', '2026-11-04 15:17:41.673000', NULL, '2026-11-04 15:17:42.667000', '2026-11-04 15:17:42.667000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8343, 208, 3, 'WATER_READING', 'POINT', '2026-11-02 01:00:00', 403.000000, 'm3', 'GetWaterRawData', '2026-11-02 01:00:00', '2026-11-04 15:17:42.201000', NULL, '2026-11-04 15:17:43.137000', '2026-11-04 15:17:43.137000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8344, 208, 3, 'WATER_READING', 'POINT', '2026-11-01 01:00:00', 403.000000, 'm3', 'GetWaterRawData', '2026-11-01 01:00:00', '2026-11-04 15:17:42.201000', NULL, '2026-11-04 15:17:43.137000', '2026-11-04 15:17:43.137000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8345, 208, 3, 'WATER_READING', 'POINT', '2026-10-31 01:00:00', 390.000000, 'm3', 'GetWaterRawData', '2026-10-31 01:00:00', '2026-11-04 15:17:42.201000', NULL, '2026-11-04 15:17:43.137000', '2026-11-04 15:17:43.137000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8346, 208, 3, 'WATER_READING', 'POINT', '2026-10-30 01:00:00', 379.000000, 'm3', 'GetWaterRawData', '2026-10-30 01:00:00', '2026-11-04 15:17:42.201000', NULL, '2026-11-04 15:17:43.137000', '2026-11-04 15:17:43.137000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8347, 208, 3, 'WATER_READING', 'POINT', '2026-10-29 01:00:00', 370.000000, 'm3', 'GetWaterRawData', '2026-10-29 01:00:00', '2026-11-04 15:17:42.201000', NULL, '2026-11-04 15:17:43.137000', '2026-11-04 15:17:43.137000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8348, 208, 3, 'WATER_READING', 'POINT', '2026-10-28 01:00:00', 370.000000, 'm3', 'GetWaterRawData', '2026-10-28 01:00:00', '2026-11-04 15:17:42.201000', NULL, '2026-11-04 15:17:43.137000', '2026-11-04 15:17:43.137000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8349, 208, 4, 'WATER_READING', 'POINT', '2026-10-26 06:00:00', 913.000000, 'm3', 'GetWaterRawData', '2026-10-26 06:00:00', '2026-11-04 15:17:42.690000', NULL, '2026-11-04 15:17:43.684000', '2026-11-04 15:17:43.684000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8350, 208, 4, 'WATER_READING', 'POINT', '2026-10-25 06:00:00', 913.000000, 'm3', 'GetWaterRawData', '2026-10-25 06:00:00', '2026-11-04 15:17:42.690000', NULL, '2026-11-04 15:17:43.684000', '2026-11-04 15:17:43.684000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8351, 208, 4, 'WATER_READING', 'POINT', '2026-10-24 06:00:00', 878.000000, 'm3', 'GetWaterRawData', '2026-10-24 06:00:00', '2026-11-04 15:17:42.690000', NULL, '2026-11-04 15:17:43.684000', '2026-11-04 15:17:43.684000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8352, 208, 4, 'WATER_READING', 'POINT', '2026-10-23 06:00:00', 846.000000, 'm3', 'GetWaterRawData', '2026-10-23 06:00:00', '2026-11-04 15:17:42.690000', NULL, '2026-11-04 15:17:43.684000', '2026-11-04 15:17:43.684000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8353, 208, 4, 'WATER_READING', 'POINT', '2026-10-22 06:00:00', 814.000000, 'm3', 'GetWaterRawData', '2026-10-22 06:00:00', '2026-11-04 15:17:42.690000', NULL, '2026-11-04 15:17:43.684000', '2026-11-04 15:17:43.684000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8354, 208, 4, 'WATER_READING', 'POINT', '2026-10-21 06:00:00', 794.000000, 'm3', 'GetWaterRawData', '2026-10-21 06:00:00', '2026-11-04 15:17:42.690000', NULL, '2026-11-04 15:17:43.684000', '2026-11-04 15:17:43.684000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8355, 208, 4, 'WATER_READING', 'POINT', '2026-10-20 06:00:00', 775.000000, 'm3', 'GetWaterRawData', '2026-10-20 06:00:00', '2026-11-04 15:17:42.690000', NULL, '2026-11-04 15:17:43.684000', '2026-11-04 15:17:43.684000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8356, 208, 4, 'WATER_READING', 'POINT', '2026-10-19 06:00:00', 775.000000, 'm3', 'GetWaterRawData', '2026-10-19 06:00:00', '2026-11-04 15:17:42.690000', NULL, '2026-11-04 15:17:43.684000', '2026-11-04 15:17:43.684000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8357, 208, 4, 'WATER_READING', 'POINT', '2026-10-18 12:00:00', 764.000000, 'm3', 'GetWaterRawData', '2026-10-18 12:00:00', '2026-11-04 15:17:42.690000', NULL, '2026-11-04 15:17:43.684000', '2026-11-04 15:17:43.684000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8358, 208, 4, 'WATER_READING', 'POINT', '2026-10-18 06:00:00', 764.000000, 'm3', 'GetWaterRawData', '2026-10-18 06:00:00', '2026-11-04 15:17:42.690000', NULL, '2026-11-04 15:17:43.684000', '2026-11-04 15:17:43.684000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8359, 208, 4, 'WATER_READING', 'POINT', '2026-10-17 12:00:00', 764.000000, 'm3', 'GetWaterRawData', '2026-10-17 12:00:00', '2026-11-04 15:17:42.690000', NULL, '2026-11-04 15:17:43.684000', '2026-11-04 15:17:43.684000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8360, 208, 4, 'WATER_READING', 'POINT', '2026-10-17 06:00:00', 764.000000, 'm3', 'GetWaterRawData', '2026-10-17 06:00:00', '2026-11-04 15:17:42.690000', NULL, '2026-11-04 15:17:43.684000', '2026-11-04 15:17:43.684000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8361, 208, 4, 'WATER_READING', 'POINT', '2026-10-16 06:00:00', 764.000000, 'm3', 'GetWaterRawData', '2026-10-16 06:00:00', '2026-11-04 15:17:42.690000', NULL, '2026-11-04 15:17:43.684000', '2026-11-04 15:17:43.684000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8362, 208, 4, 'WATER_READING', 'POINT', '2026-10-15 06:00:00', 725.000000, 'm3', 'GetWaterRawData', '2026-10-15 06:00:00', '2026-11-04 15:17:42.690000', NULL, '2026-11-04 15:17:43.684000', '2026-11-04 15:17:43.684000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8363, 208, 4, 'WATER_READING', 'POINT', '2026-10-14 06:00:00', 725.000000, 'm3', 'GetWaterRawData', '2026-10-14 06:00:00', '2026-11-04 15:17:42.690000', NULL, '2026-11-04 15:17:43.684000', '2026-11-04 15:17:43.684000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8364, 208, 4, 'WATER_READING', 'POINT', '2026-10-13 06:00:00', 720.000000, 'm3', 'GetWaterRawData', '2026-10-13 06:00:00', '2026-11-04 15:17:42.690000', NULL, '2026-11-04 15:17:43.684000', '2026-11-04 15:17:43.684000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8365, 208, 5, 'WATER_USAGE', 'D', '2026-11-03 00:00:00', 3.000000, 'm3', 'GetUseWater', '2026-11-03 00:00:00', '2026-11-04 15:17:43.159000', NULL, '2026-11-04 15:17:44.167000', '2026-11-04 15:17:44.167000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8366, 208, 5, 'WATER_USAGE', 'D', '2026-11-02 00:00:00', 28.000000, 'm3', 'GetUseWater', '2026-11-02 00:00:00', '2026-11-04 15:17:43.159000', NULL, '2026-11-04 15:17:44.167000', '2026-11-04 15:17:44.167000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8367, 208, 5, 'WATER_USAGE', 'D', '2026-11-01 00:00:00', 28.000000, 'm3', 'GetUseWater', '2026-11-01 00:00:00', '2026-11-04 15:17:43.159000', NULL, '2026-11-04 15:17:44.167000', '2026-11-04 15:17:44.167000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8368, 208, 5, 'WATER_USAGE', 'D', '2026-10-31 00:00:00', 70.000000, 'm3', 'GetUseWater', '2026-10-31 00:00:00', '2026-11-04 15:17:43.159000', NULL, '2026-11-04 15:17:44.167000', '2026-11-04 15:17:44.167000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8369, 208, 5, 'WATER_USAGE', 'D', '2026-10-30 00:00:00', 81.000000, 'm3', 'GetUseWater', '2026-10-30 00:00:00', '2026-11-04 15:17:43.159000', NULL, '2026-11-04 15:17:44.167000', '2026-11-04 15:17:44.167000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8370, 208, 5, 'WATER_USAGE', 'D', '2026-10-29 00:00:00', 9.000000, 'm3', 'GetUseWater', '2026-10-29 00:00:00', '2026-11-04 15:17:43.159000', NULL, '2026-11-04 15:17:44.167000', '2026-11-04 15:17:44.167000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8371, 208, 5, 'WATER_USAGE', 'D', '2026-10-28 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-10-28 00:00:00', '2026-11-04 15:17:43.159000', NULL, '2026-11-04 15:17:44.167000', '2026-11-04 15:17:44.167000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8372, 208, 5, 'WATER_USAGE', 'D', '2026-10-27 00:00:00', 4.000000, 'm3', 'GetUseWater', '2026-10-27 00:00:00', '2026-11-04 15:17:43.159000', NULL, '2026-11-04 15:17:44.167000', '2026-11-04 15:17:44.167000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8373, 208, 5, 'WATER_USAGE', 'D', '2026-10-26 00:00:00', 24.000000, 'm3', 'GetUseWater', '2026-10-26 00:00:00', '2026-11-04 15:17:43.159000', NULL, '2026-11-04 15:17:44.167000', '2026-11-04 15:17:44.167000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8374, 208, 5, 'WATER_USAGE', 'D', '2026-10-25 00:00:00', 40.000000, 'm3', 'GetUseWater', '2026-10-25 00:00:00', '2026-11-04 15:17:43.159000', NULL, '2026-11-04 15:17:44.167000', '2026-11-04 15:17:44.167000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8375, 208, 5, 'WATER_USAGE', 'D', '2026-10-24 00:00:00', 84.000000, 'm3', 'GetUseWater', '2026-10-24 00:00:00', '2026-11-04 15:17:43.159000', NULL, '2026-11-04 15:17:44.167000', '2026-11-04 15:17:44.167000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8376, 208, 5, 'WATER_USAGE', 'D', '2026-10-23 00:00:00', 94.000000, 'm3', 'GetUseWater', '2026-10-23 00:00:00', '2026-11-04 15:17:43.159000', NULL, '2026-11-04 15:17:44.167000', '2026-11-04 15:17:44.167000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8377, 208, 5, 'WATER_USAGE', 'D', '2026-10-22 00:00:00', 31.000000, 'm3', 'GetUseWater', '2026-10-22 00:00:00', '2026-11-04 15:17:43.159000', NULL, '2026-11-04 15:17:44.167000', '2026-11-04 15:17:44.167000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8378, 208, 5, 'WATER_USAGE', 'D', '2026-10-21 00:00:00', 20.000000, 'm3', 'GetUseWater', '2026-10-21 00:00:00', '2026-11-04 15:17:43.159000', NULL, '2026-11-04 15:17:44.167000', '2026-11-04 15:17:44.167000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8379, 208, 5, 'WATER_USAGE', 'D', '2026-10-20 00:00:00', 6.000000, 'm3', 'GetUseWater', '2026-10-20 00:00:00', '2026-11-04 15:17:43.159000', NULL, '2026-11-04 15:17:44.167000', '2026-11-04 15:17:44.167000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8380, 208, 5, 'WATER_USAGE', 'D', '2026-10-19 00:00:00', 37.000000, 'm3', 'GetUseWater', '2026-10-19 00:00:00', '2026-11-04 15:17:43.159000', NULL, '2026-11-04 15:17:44.167000', '2026-11-04 15:17:44.167000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8381, 208, 5, 'WATER_USAGE', 'D', '2026-10-18 00:00:00', 8.000000, 'm3', 'GetUseWater', '2026-10-18 00:00:00', '2026-11-04 15:17:43.159000', NULL, '2026-11-04 15:17:44.167000', '2026-11-04 15:17:44.167000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8382, 208, 5, 'WATER_USAGE', 'D', '2026-10-17 00:00:00', 0.000000, 'm3', 'GetUseWater', '2026-10-17 00:00:00', '2026-11-04 15:17:43.159000', NULL, '2026-11-04 15:17:44.167000', '2026-11-04 15:17:44.167000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8383, 208, 5, 'WATER_USAGE', 'D', '2026-10-16 00:00:00', 53.000000, 'm3', 'GetUseWater', '2026-10-16 00:00:00', '2026-11-04 15:17:43.159000', NULL, '2026-11-04 15:17:44.167000', '2026-11-04 15:17:44.167000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8384, 208, 5, 'WATER_USAGE', 'D', '2026-10-15 00:00:00', 11.000000, 'm3', 'GetUseWater', '2026-10-15 00:00:00', '2026-11-04 15:17:43.159000', NULL, '2026-11-04 15:17:44.167000', '2026-11-04 15:17:44.167000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8385, 208, 5, 'WATER_USAGE', 'D', '2026-10-14 00:00:00', 6.000000, 'm3', 'GetUseWater', '2026-10-14 00:00:00', '2026-11-04 15:17:43.159000', NULL, '2026-11-04 15:17:44.167000', '2026-11-04 15:17:44.167000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8386, 208, 5, 'WATER_USAGE', 'D', '2026-10-13 00:00:00', 3.000000, 'm3', 'GetUseWater', '2026-10-13 00:00:00', '2026-11-04 15:17:43.159000', NULL, '2026-11-04 15:17:44.167000', '2026-11-04 15:17:44.167000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8387, 208, 4, 'WATER_READING', 'POINT', '2026-11-02 06:00:00', 995.000000, 'm3', 'GetWaterRawData', '2026-11-02 06:00:00', '2026-11-04 15:17:43.707000', NULL, '2026-11-04 15:17:44.662000', '2026-11-04 15:17:44.662000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8388, 208, 4, 'WATER_READING', 'POINT', '2026-11-01 06:00:00', 995.000000, 'm3', 'GetWaterRawData', '2026-11-01 06:00:00', '2026-11-04 15:17:43.707000', NULL, '2026-11-04 15:17:44.662000', '2026-11-04 15:17:44.662000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8389, 208, 4, 'WATER_READING', 'POINT', '2026-10-31 06:00:00', 967.000000, 'm3', 'GetWaterRawData', '2026-10-31 06:00:00', '2026-11-04 15:17:43.707000', NULL, '2026-11-04 15:17:44.662000', '2026-11-04 15:17:44.662000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8390, 208, 4, 'WATER_READING', 'POINT', '2026-10-30 06:00:00', 940.000000, 'm3', 'GetWaterRawData', '2026-10-30 06:00:00', '2026-11-04 15:17:43.707000', NULL, '2026-11-04 15:17:44.662000', '2026-11-04 15:17:44.662000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8391, 208, 4, 'WATER_READING', 'POINT', '2026-10-29 06:00:00', 913.000000, 'm3', 'GetWaterRawData', '2026-10-29 06:00:00', '2026-11-04 15:17:43.707000', NULL, '2026-11-04 15:17:44.662000', '2026-11-04 15:17:44.662000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8392, 208, 4, 'WATER_READING', 'POINT', '2026-10-28 06:00:00', 913.000000, 'm3', 'GetWaterRawData', '2026-10-28 06:00:00', '2026-11-04 15:17:43.707000', NULL, '2026-11-04 15:17:44.662000', '2026-11-04 15:17:44.662000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8393, 208, 5, 'WATER_READING', 'POINT', '2026-10-26 05:00:00', 2110.000000, 'm3', 'GetWaterRawData', '2026-10-26 05:00:00', '2026-11-04 15:17:44.197000', NULL, '2026-11-04 15:17:45.142000', '2026-11-04 15:17:45.142000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8394, 208, 5, 'WATER_READING', 'POINT', '2026-10-25 05:00:00', 2070.000000, 'm3', 'GetWaterRawData', '2026-10-25 05:00:00', '2026-11-04 15:17:44.197000', NULL, '2026-11-04 15:17:45.142000', '2026-11-04 15:17:45.142000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8395, 208, 5, 'WATER_READING', 'POINT', '2026-10-24 05:00:00', 1986.000000, 'm3', 'GetWaterRawData', '2026-10-24 05:00:00', '2026-11-04 15:17:44.197000', NULL, '2026-11-04 15:17:45.142000', '2026-11-04 15:17:45.142000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8396, 208, 5, 'WATER_READING', 'POINT', '2026-10-23 05:00:00', 1892.000000, 'm3', 'GetWaterRawData', '2026-10-23 05:00:00', '2026-11-04 15:17:44.197000', NULL, '2026-11-04 15:17:45.142000', '2026-11-04 15:17:45.142000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8397, 208, 5, 'WATER_READING', 'POINT', '2026-10-22 05:00:00', 1861.000000, 'm3', 'GetWaterRawData', '2026-10-22 05:00:00', '2026-11-04 15:17:44.197000', NULL, '2026-11-04 15:17:45.142000', '2026-11-04 15:17:45.142000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8398, 208, 5, 'WATER_READING', 'POINT', '2026-10-21 05:00:00', 1841.000000, 'm3', 'GetWaterRawData', '2026-10-21 05:00:00', '2026-11-04 15:17:44.197000', NULL, '2026-11-04 15:17:45.142000', '2026-11-04 15:17:45.142000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8399, 208, 5, 'WATER_READING', 'POINT', '2026-10-20 05:00:00', 1835.000000, 'm3', 'GetWaterRawData', '2026-10-20 05:00:00', '2026-11-04 15:17:44.197000', NULL, '2026-11-04 15:17:45.142000', '2026-11-04 15:17:45.142000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8400, 208, 5, 'WATER_READING', 'POINT', '2026-10-19 05:00:00', 1798.000000, 'm3', 'GetWaterRawData', '2026-10-19 05:00:00', '2026-11-04 15:17:44.197000', NULL, '2026-11-04 15:17:45.142000', '2026-11-04 15:17:45.142000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8401, 208, 5, 'WATER_READING', 'POINT', '2026-10-18 05:00:00', 1790.000000, 'm3', 'GetWaterRawData', '2026-10-18 05:00:00', '2026-11-04 15:17:44.197000', NULL, '2026-11-04 15:17:45.142000', '2026-11-04 15:17:45.142000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8402, 208, 5, 'WATER_READING', 'POINT', '2026-10-17 05:00:00', 1790.000000, 'm3', 'GetWaterRawData', '2026-10-17 05:00:00', '2026-11-04 15:17:44.197000', NULL, '2026-11-04 15:17:45.142000', '2026-11-04 15:17:45.142000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8403, 208, 5, 'WATER_READING', 'POINT', '2026-10-16 05:00:00', 1737.000000, 'm3', 'GetWaterRawData', '2026-10-16 05:00:00', '2026-11-04 15:17:44.197000', NULL, '2026-11-04 15:17:45.142000', '2026-11-04 15:17:45.142000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8404, 208, 5, 'WATER_READING', 'POINT', '2026-10-15 05:00:00', 1726.000000, 'm3', 'GetWaterRawData', '2026-10-15 05:00:00', '2026-11-04 15:17:44.197000', NULL, '2026-11-04 15:17:45.142000', '2026-11-04 15:17:45.142000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8405, 208, 5, 'WATER_READING', 'POINT', '2026-10-14 05:00:00', 1720.000000, 'm3', 'GetWaterRawData', '2026-10-14 05:00:00', '2026-11-04 15:17:44.197000', NULL, '2026-11-04 15:17:45.142000', '2026-11-04 15:17:45.142000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8406, 208, 5, 'WATER_READING', 'POINT', '2026-10-13 05:00:00', 1717.000000, 'm3', 'GetWaterRawData', '2026-10-13 05:00:00', '2026-11-04 15:17:44.197000', NULL, '2026-11-04 15:17:45.142000', '2026-11-04 15:17:45.142000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8407, 208, 6, 'WATER_USAGE', 'D', '2026-11-03 00:00:00', 4.000000, 'm3', 'GetUseWater', '2026-11-03 00:00:00', '2026-11-04 15:17:44.687000', NULL, '2026-11-04 15:17:45.670000', '2026-11-04 15:17:45.670000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8408, 208, 6, 'WATER_USAGE', 'D', '2026-11-02 00:00:00', 27.000000, 'm3', 'GetUseWater', '2026-11-02 00:00:00', '2026-11-04 15:17:44.687000', NULL, '2026-11-04 15:17:45.670000', '2026-11-04 15:17:45.670000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8409, 208, 6, 'WATER_USAGE', 'D', '2026-11-01 00:00:00', 35.000000, 'm3', 'GetUseWater', '2026-11-01 00:00:00', '2026-11-04 15:17:44.687000', NULL, '2026-11-04 15:17:45.670000', '2026-11-04 15:17:45.670000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8410, 208, 6, 'WATER_USAGE', 'D', '2026-10-31 00:00:00', 140.000000, 'm3', 'GetUseWater', '2026-10-31 00:00:00', '2026-11-04 15:17:44.687000', NULL, '2026-11-04 15:17:45.670000', '2026-11-04 15:17:45.670000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8411, 208, 6, 'WATER_USAGE', 'D', '2026-10-30 00:00:00', 139.000000, 'm3', 'GetUseWater', '2026-10-30 00:00:00', '2026-11-04 15:17:44.687000', NULL, '2026-11-04 15:17:45.670000', '2026-11-04 15:17:45.670000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8412, 208, 6, 'WATER_USAGE', 'D', '2026-10-29 00:00:00', 67.000000, 'm3', 'GetUseWater', '2026-10-29 00:00:00', '2026-11-04 15:17:44.687000', NULL, '2026-11-04 15:17:45.670000', '2026-11-04 15:17:45.670000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8413, 208, 6, 'WATER_USAGE', 'D', '2026-10-28 00:00:00', 28.000000, 'm3', 'GetUseWater', '2026-10-28 00:00:00', '2026-11-04 15:17:44.687000', NULL, '2026-11-04 15:17:45.670000', '2026-11-04 15:17:45.670000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8414, 208, 6, 'WATER_USAGE', 'D', '2026-10-27 00:00:00', 4.000000, 'm3', 'GetUseWater', '2026-10-27 00:00:00', '2026-11-04 15:17:44.687000', NULL, '2026-11-04 15:17:45.670000', '2026-11-04 15:17:45.670000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8415, 208, 6, 'WATER_USAGE', 'D', '2026-10-26 00:00:00', 24.000000, 'm3', 'GetUseWater', '2026-10-26 00:00:00', '2026-11-04 15:17:44.687000', NULL, '2026-11-04 15:17:45.670000', '2026-11-04 15:17:45.670000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8416, 208, 6, 'WATER_USAGE', 'D', '2026-10-25 00:00:00', 39.000000, 'm3', 'GetUseWater', '2026-10-25 00:00:00', '2026-11-04 15:17:44.687000', NULL, '2026-11-04 15:17:45.670000', '2026-11-04 15:17:45.670000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8417, 208, 6, 'WATER_USAGE', 'D', '2026-10-24 00:00:00', 171.000000, 'm3', 'GetUseWater', '2026-10-24 00:00:00', '2026-11-04 15:17:44.687000', NULL, '2026-11-04 15:17:45.670000', '2026-11-04 15:17:45.670000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8418, 208, 6, 'WATER_USAGE', 'D', '2026-10-23 00:00:00', 171.000000, 'm3', 'GetUseWater', '2026-10-23 00:00:00', '2026-11-04 15:17:44.687000', NULL, '2026-11-04 15:17:45.670000', '2026-11-04 15:17:45.670000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8419, 208, 6, 'WATER_USAGE', 'D', '2026-10-22 00:00:00', 100.000000, 'm3', 'GetUseWater', '2026-10-22 00:00:00', '2026-11-04 15:17:44.687000', NULL, '2026-11-04 15:17:45.670000', '2026-11-04 15:17:45.670000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8420, 208, 6, 'WATER_USAGE', 'D', '2026-10-21 00:00:00', 52.000000, 'm3', 'GetUseWater', '2026-10-21 00:00:00', '2026-11-04 15:17:44.687000', NULL, '2026-11-04 15:17:45.670000', '2026-11-04 15:17:45.670000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8421, 208, 6, 'WATER_USAGE', 'D', '2026-10-20 00:00:00', 34.000000, 'm3', 'GetUseWater', '2026-10-20 00:00:00', '2026-11-04 15:17:44.687000', NULL, '2026-11-04 15:17:45.670000', '2026-11-04 15:17:45.670000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8422, 208, 6, 'WATER_USAGE', 'D', '2026-10-19 00:00:00', 38.000000, 'm3', 'GetUseWater', '2026-10-19 00:00:00', '2026-11-04 15:17:44.687000', NULL, '2026-11-04 15:17:45.670000', '2026-11-04 15:17:45.670000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8423, 208, 6, 'WATER_USAGE', 'D', '2026-10-18 00:00:00', 33.000000, 'm3', 'GetUseWater', '2026-10-18 00:00:00', '2026-11-04 15:17:44.687000', NULL, '2026-11-04 15:17:45.670000', '2026-11-04 15:17:45.670000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8424, 208, 6, 'WATER_USAGE', 'D', '2026-10-17 00:00:00', 2.000000, 'm3', 'GetUseWater', '2026-10-17 00:00:00', '2026-11-04 15:17:44.687000', NULL, '2026-11-04 15:17:45.670000', '2026-11-04 15:17:45.670000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8425, 208, 6, 'WATER_USAGE', 'D', '2026-10-16 00:00:00', 67.000000, 'm3', 'GetUseWater', '2026-10-16 00:00:00', '2026-11-04 15:17:44.687000', NULL, '2026-11-04 15:17:45.670000', '2026-11-04 15:17:45.670000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8426, 208, 6, 'WATER_USAGE', 'D', '2026-10-15 00:00:00', 88.000000, 'm3', 'GetUseWater', '2026-10-15 00:00:00', '2026-11-04 15:17:44.687000', NULL, '2026-11-04 15:17:45.670000', '2026-11-04 15:17:45.670000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8427, 208, 6, 'WATER_USAGE', 'D', '2026-10-14 00:00:00', 10.000000, 'm3', 'GetUseWater', '2026-10-14 00:00:00', '2026-11-04 15:17:44.687000', NULL, '2026-11-04 15:17:45.670000', '2026-11-04 15:17:45.670000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8428, 208, 6, 'WATER_USAGE', 'D', '2026-10-13 00:00:00', 10.000000, 'm3', 'GetUseWater', '2026-10-13 00:00:00', '2026-11-04 15:17:44.687000', NULL, '2026-11-04 15:17:45.670000', '2026-11-04 15:17:45.670000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8429, 208, 5, 'WATER_READING', 'POINT', '2026-11-02 05:00:00', 2326.000000, 'm3', 'GetWaterRawData', '2026-11-02 05:00:00', '2026-11-04 15:17:45.168000', NULL, '2026-11-04 15:17:46.160000', '2026-11-04 15:17:46.160000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8430, 208, 5, 'WATER_READING', 'POINT', '2026-11-01 05:00:00', 2298.000000, 'm3', 'GetWaterRawData', '2026-11-01 05:00:00', '2026-11-04 15:17:45.168000', NULL, '2026-11-04 15:17:46.160000', '2026-11-04 15:17:46.160000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8431, 208, 5, 'WATER_READING', 'POINT', '2026-10-31 05:00:00', 2228.000000, 'm3', 'GetWaterRawData', '2026-10-31 05:00:00', '2026-11-04 15:17:45.168000', NULL, '2026-11-04 15:17:46.160000', '2026-11-04 15:17:46.160000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8432, 208, 5, 'WATER_READING', 'POINT', '2026-10-30 05:00:00', 2147.000000, 'm3', 'GetWaterRawData', '2026-10-30 05:00:00', '2026-11-04 15:17:45.168000', NULL, '2026-11-04 15:17:46.160000', '2026-11-04 15:17:46.160000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8433, 208, 5, 'WATER_READING', 'POINT', '2026-10-29 05:00:00', 2138.000000, 'm3', 'GetWaterRawData', '2026-10-29 05:00:00', '2026-11-04 15:17:45.168000', NULL, '2026-11-04 15:17:46.160000', '2026-11-04 15:17:46.160000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8434, 208, 5, 'WATER_READING', 'POINT', '2026-10-28 05:00:00', 2138.000000, 'm3', 'GetWaterRawData', '2026-10-28 05:00:00', '2026-11-04 15:17:45.168000', NULL, '2026-11-04 15:17:46.160000', '2026-11-04 15:17:46.160000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8435, 208, 6, 'WATER_READING', 'POINT', '2026-10-26 01:00:00', 3989.000000, 'm3', 'GetWaterRawData', '2026-10-26 01:00:00', '2026-11-04 15:19:53.392000', NULL, '2026-11-04 15:19:53.668000', '2026-11-04 15:19:53.668000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8436, 208, 6, 'WATER_READING', 'POINT', '2026-10-25 01:00:00', 3950.000000, 'm3', 'GetWaterRawData', '2026-10-25 01:00:00', '2026-11-04 15:19:53.392000', NULL, '2026-11-04 15:19:53.668000', '2026-11-04 15:19:53.668000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8437, 208, 6, 'WATER_READING', 'POINT', '2026-10-24 01:00:00', 3779.000000, 'm3', 'GetWaterRawData', '2026-10-24 01:00:00', '2026-11-04 15:19:53.392000', NULL, '2026-11-04 15:19:53.668000', '2026-11-04 15:19:53.668000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8438, 208, 6, 'WATER_READING', 'POINT', '2026-10-23 01:00:00', 3608.000000, 'm3', 'GetWaterRawData', '2026-10-23 01:00:00', '2026-11-04 15:19:53.392000', NULL, '2026-11-04 15:19:53.668000', '2026-11-04 15:19:53.668000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8439, 208, 6, 'WATER_READING', 'POINT', '2026-10-22 01:00:00', 3508.000000, 'm3', 'GetWaterRawData', '2026-10-22 01:00:00', '2026-11-04 15:19:53.392000', NULL, '2026-11-04 15:19:53.668000', '2026-11-04 15:19:53.668000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8440, 208, 6, 'WATER_READING', 'POINT', '2026-10-21 01:00:00', 3456.000000, 'm3', 'GetWaterRawData', '2026-10-21 01:00:00', '2026-11-04 15:19:53.392000', NULL, '2026-11-04 15:19:53.668000', '2026-11-04 15:19:53.668000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8441, 208, 6, 'WATER_READING', 'POINT', '2026-10-20 01:00:00', 3422.000000, 'm3', 'GetWaterRawData', '2026-10-20 01:00:00', '2026-11-04 15:19:53.392000', NULL, '2026-11-04 15:19:53.668000', '2026-11-04 15:19:53.668000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8442, 208, 6, 'WATER_READING', 'POINT', '2026-10-19 01:00:00', 3384.000000, 'm3', 'GetWaterRawData', '2026-10-19 01:00:00', '2026-11-04 15:19:53.392000', NULL, '2026-11-04 15:19:53.668000', '2026-11-04 15:19:53.668000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8443, 208, 6, 'WATER_READING', 'POINT', '2026-10-18 01:00:00', 3351.000000, 'm3', 'GetWaterRawData', '2026-10-18 01:00:00', '2026-11-04 15:19:53.392000', NULL, '2026-11-04 15:19:53.668000', '2026-11-04 15:19:53.668000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8444, 208, 6, 'WATER_READING', 'POINT', '2026-10-17 01:00:00', 3349.000000, 'm3', 'GetWaterRawData', '2026-10-17 01:00:00', '2026-11-04 15:19:53.392000', NULL, '2026-11-04 15:19:53.668000', '2026-11-04 15:19:53.668000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8445, 208, 6, 'WATER_READING', 'POINT', '2026-10-16 01:00:00', 3282.000000, 'm3', 'GetWaterRawData', '2026-10-16 01:00:00', '2026-11-04 15:19:53.392000', NULL, '2026-11-04 15:19:53.668000', '2026-11-04 15:19:53.668000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8446, 208, 6, 'WATER_READING', 'POINT', '2026-10-15 08:00:00', 3197.000000, 'm3', 'GetWaterRawData', '2026-10-15 08:00:00', '2026-11-04 15:19:53.392000', NULL, '2026-11-04 15:19:53.668000', '2026-11-04 15:19:53.668000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8447, 208, 6, 'WATER_READING', 'POINT', '2026-10-15 01:00:00', 3194.000000, 'm3', 'GetWaterRawData', '2026-10-15 01:00:00', '2026-11-04 15:19:53.392000', NULL, '2026-11-04 15:19:53.668000', '2026-11-04 15:19:53.668000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8448, 208, 6, 'WATER_READING', 'POINT', '2026-10-14 01:00:00', 3184.000000, 'm3', 'GetWaterRawData', '2026-10-14 01:00:00', '2026-11-04 15:19:53.392000', NULL, '2026-11-04 15:19:53.668000', '2026-11-04 15:19:53.668000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8449, 208, 6, 'WATER_READING', 'POINT', '2026-10-13 01:00:00', 3174.000000, 'm3', 'GetWaterRawData', '2026-10-13 01:00:00', '2026-11-04 15:19:53.392000', NULL, '2026-11-04 15:19:53.668000', '2026-11-04 15:19:53.668000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8450, 208, 6, 'WATER_READING', 'POINT', '2026-11-02 01:00:00', 4426.000000, 'm3', 'GetWaterRawData', '2026-11-02 01:00:00', '2026-11-04 15:19:53.693000', NULL, '2026-11-04 15:19:54.098000', '2026-11-04 15:19:54.098000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8451, 208, 6, 'WATER_READING', 'POINT', '2026-11-01 01:00:00', 4391.000000, 'm3', 'GetWaterRawData', '2026-11-01 01:00:00', '2026-11-04 15:19:53.693000', NULL, '2026-11-04 15:19:54.098000', '2026-11-04 15:19:54.098000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8452, 208, 6, 'WATER_READING', 'POINT', '2026-10-31 01:00:00', 4251.000000, 'm3', 'GetWaterRawData', '2026-10-31 01:00:00', '2026-11-04 15:19:53.693000', NULL, '2026-11-04 15:19:54.098000', '2026-11-04 15:19:54.098000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8453, 208, 6, 'WATER_READING', 'POINT', '2026-10-30 01:00:00', 4112.000000, 'm3', 'GetWaterRawData', '2026-10-30 01:00:00', '2026-11-04 15:19:53.693000', NULL, '2026-11-04 15:19:54.098000', '2026-11-04 15:19:54.098000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8454, 208, 6, 'WATER_READING', 'POINT', '2026-10-29 01:00:00', 4045.000000, 'm3', 'GetWaterRawData', '2026-10-29 01:00:00', '2026-11-04 15:19:53.693000', NULL, '2026-11-04 15:19:54.098000', '2026-11-04 15:19:54.098000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8455, 208, 6, 'WATER_READING', 'POINT', '2026-10-28 01:00:00', 4017.000000, 'm3', 'GetWaterRawData', '2026-10-28 01:00:00', '2026-11-04 15:19:53.693000', NULL, '2026-11-04 15:19:54.098000', '2026-11-04 15:19:54.098000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8467, 208, 11, 'GAS_USAGE', 'D', '2026-11-04 00:00:00', 17.030000, 'm3', 'MANUAL', '2026-11-04 00:00:00', '2026-11-04 17:09:26.938000', NULL, '2026-11-04 17:09:26.949000', '2026-11-04 17:09:26.949000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8468, 208, 11, 'GAS_READING', 'POINT', '2026-11-04 00:00:00', 17.030000, 'm3', 'MANUAL', '2026-11-04 00:00:00', '2026-11-04 17:09:26.938000', NULL, '2026-11-04 17:09:26.949000', '2026-11-04 17:09:26.949000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8469, 208, 12, 'GAS_USAGE', 'D', '2026-11-04 00:00:00', 22.320000, 'm3', 'MANUAL', '2026-11-04 00:00:00', '2026-11-04 17:09:26.963000', NULL, '2026-11-04 17:09:26.967000', '2026-11-04 17:09:26.967000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8470, 208, 12, 'GAS_READING', 'POINT', '2026-11-04 00:00:00', 22.320000, 'm3', 'MANUAL', '2026-11-04 00:00:00', '2026-11-04 17:09:26.963000', NULL, '2026-11-04 17:09:26.967000', '2026-11-04 17:09:26.967000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8471, 208, 13, 'GAS_USAGE', 'D', '2026-11-04 00:00:00', 27.610000, 'm3', 'MANUAL', '2026-11-04 00:00:00', '2026-11-04 17:09:26.981000', NULL, '2026-11-04 17:09:26.986000', '2026-11-04 17:09:26.986000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8472, 208, 13, 'GAS_READING', 'POINT', '2026-11-04 00:00:00', 27.610000, 'm3', 'MANUAL', '2026-11-04 00:00:00', '2026-11-04 17:09:26.981000', NULL, '2026-11-04 17:09:26.986000', '2026-11-04 17:09:26.986000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8473, 208, 14, 'GAS_USAGE', 'D', '2026-11-04 00:00:00', 29.900000, 'm3', 'MANUAL', '2026-11-04 00:00:00', '2026-11-04 17:09:26.998000', NULL, '2026-11-04 17:09:27.003000', '2026-11-04 17:09:27.003000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8474, 208, 14, 'GAS_READING', 'POINT', '2026-11-04 00:00:00', 29.900000, 'm3', 'MANUAL', '2026-11-04 00:00:00', '2026-11-04 17:09:26.998000', NULL, '2026-11-04 17:09:27.003000', '2026-11-04 17:09:27.003000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8475, 208, 15, 'GAS_USAGE', 'D', '2026-11-04 00:00:00', 12.270000, 'm3', 'MANUAL', '2026-11-04 00:00:00', '2026-11-04 17:09:27.014000', NULL, '2026-11-04 17:09:27.019000', '2026-11-04 17:09:27.019000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8476, 208, 15, 'GAS_READING', 'POINT', '2026-11-04 00:00:00', 12.270000, 'm3', 'MANUAL', '2026-11-04 00:00:00', '2026-11-04 17:09:27.014000', NULL, '2026-11-04 17:09:27.019000', '2026-11-04 17:09:27.019000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8483, 208, 7, 'ELECTRIC_USAGE', 'D', '2026-11-04 00:00:00', 2.330000, 'kWh', 'ElectricQuantity', '2026-11-04 00:00:00', '2026-11-04 19:00:00.122000', NULL, '2026-11-04 17:31:29.349000', '2026-11-04 19:00:01.781000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8484, 208, 7, 'ELECTRIC_READING', 'POINT', '2026-11-03 00:00:00', 72.970000, 'kWh', 'FrozenElectricity', '2026-11-03 00:00:00', '2026-11-04 17:31:29.114000', NULL, '2026-11-04 17:31:29.826000', '2026-11-04 17:31:29.826000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8485, 208, 8, 'ELECTRIC_USAGE', 'D', '2026-11-04 00:00:00', 4.130000, 'kWh', 'ElectricQuantity', '2026-11-04 00:00:00', '2026-11-04 19:00:00.127000', NULL, '2026-11-04 17:31:30.230000', '2026-11-04 19:00:01.991000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8486, 208, 8, 'ELECTRIC_READING', 'POINT', '2026-11-03 00:00:00', 469.070000, 'kWh', 'FrozenElectricity', '2026-11-03 00:00:00', '2026-11-04 17:31:29.872000', NULL, '2026-11-04 17:31:30.781000', '2026-11-04 17:31:30.781000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8487, 208, 9, 'ELECTRIC_USAGE', 'D', '2026-11-04 00:00:00', 2.690000, 'kWh', 'ElectricQuantity', '2026-11-04 00:00:00', '2026-11-04 18:41:22.396000', NULL, '2026-11-04 17:31:31.251000', '2026-11-04 18:41:22.979000'); |
| | | |
| | | INSERT INTO `energy_meter_measurement` (`id`, `tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`, `metric_value`, `unit`, `source_api`, `source_record_time`, `collected_at`, `remark`, `create_time`, `update_time`) VALUES (8488, 208, 9, 'ELECTRIC_READING', 'POINT', '2026-11-03 00:00:00', 303.120000, 'kWh', 'FrozenElectricity', '2026-11-03 00:00:00', '2026-11-04 17:31:30.819000', NULL, '2026-11-04 17:31:31.794000', '2026-11-04 17:31:31.794000'); |
| | | |
| | | |
| | | -- energy_meter_sync_run: 7 rows |
| | | |
| | | INSERT INTO `energy_meter_sync_run` (`id`, `run_key`, `trigger_type`, `schedule_date`, `range_start`, `range_end`, `status`, `total_tasks`, `success_tasks`, `empty_tasks`, `failed_tasks`, `started_at`, `finished_at`, `error_summary`, `create_user`, `create_time`, `update_time`) VALUES (1, 'AUTO:20261104', 'SCHEDULED', '2026-11-04', '2026-10-13', '2026-11-03', 'SUCCESS', 18, 18, 0, 0, '2026-11-04 15:17:38.498000', '2026-11-04 15:19:54.128000', NULL, 1, '2026-11-04 15:17:38.357000', '2026-11-04 15:19:54.130000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_run` (`id`, `run_key`, `trigger_type`, `schedule_date`, `range_start`, `range_end`, `status`, `total_tasks`, `success_tasks`, `empty_tasks`, `failed_tasks`, `started_at`, `finished_at`, `error_summary`, `create_user`, `create_time`, `update_time`) VALUES (2, 'MANUAL:4ee77a32-e7fc-4588-97c8-2ca17fd3f69d', 'MANUAL', NULL, '2026-11-01', '2026-11-03', 'SUCCESS', 2, 1, 1, 0, '2026-11-04 17:23:25.151000', '2026-11-04 17:30:48.120000', NULL, 1, '2026-11-04 17:23:25.109000', '2026-11-04 17:30:48.130000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_run` (`id`, `run_key`, `trigger_type`, `schedule_date`, `range_start`, `range_end`, `status`, `total_tasks`, `success_tasks`, `empty_tasks`, `failed_tasks`, `started_at`, `finished_at`, `error_summary`, `create_user`, `create_time`, `update_time`) VALUES (3, 'MANUAL:94bf000f-8a1d-4e67-9cbd-0e17daae76b1', 'MANUAL', NULL, '2026-11-01', '2026-11-03', 'SUCCESS', 2, 1, 1, 0, '2026-11-04 17:23:30.959000', '2026-11-04 17:30:48.434000', NULL, 1, '2026-11-04 17:23:30.932000', '2026-11-04 17:30:48.438000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_run` (`id`, `run_key`, `trigger_type`, `schedule_date`, `range_start`, `range_end`, `status`, `total_tasks`, `success_tasks`, `empty_tasks`, `failed_tasks`, `started_at`, `finished_at`, `error_summary`, `create_user`, `create_time`, `update_time`) VALUES (4, 'MANUAL:f3235037-1361-4935-9fe9-1dc5d893fdca', 'MANUAL', NULL, '2026-11-01', '2026-11-03', 'SUCCESS', 2, 1, 1, 0, '2026-11-04 17:23:33.884000', '2026-11-04 17:30:48.943000', NULL, 1, '2026-11-04 17:23:33.857000', '2026-11-04 17:30:48.947000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_run` (`id`, `run_key`, `trigger_type`, `schedule_date`, `range_start`, `range_end`, `status`, `total_tasks`, `success_tasks`, `empty_tasks`, `failed_tasks`, `started_at`, `finished_at`, `error_summary`, `create_user`, `create_time`, `update_time`) VALUES (5, 'MANUAL:76414df1-60a3-4ad9-96c6-7eb6d92a26be', 'MANUAL', NULL, '2026-11-01', '2026-11-04', 'SUCCESS', 6, 6, 0, 0, '2026-11-04 17:31:29.076000', '2026-11-04 17:31:31.838000', NULL, 1, '2026-11-04 17:31:29.003000', '2026-11-04 17:31:31.841000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_run` (`id`, `run_key`, `trigger_type`, `schedule_date`, `range_start`, `range_end`, `status`, `total_tasks`, `success_tasks`, `empty_tasks`, `failed_tasks`, `started_at`, `finished_at`, `error_summary`, `create_user`, `create_time`, `update_time`) VALUES (7, 'MANUAL:264a56f2-a48c-418a-b500-275b20c3bce6', 'MANUAL', NULL, '2026-11-01', '2026-11-03', 'SUCCESS', 2, 1, 1, 0, '2026-11-04 18:48:51.045000', '2026-11-04 18:48:51.739000', NULL, 1, '2026-11-04 18:48:51.010000', '2026-11-04 18:48:51.742000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_run` (`id`, `run_key`, `trigger_type`, `schedule_date`, `range_start`, `range_end`, `status`, `total_tasks`, `success_tasks`, `empty_tasks`, `failed_tasks`, `started_at`, `finished_at`, `error_summary`, `create_user`, `create_time`, `update_time`) VALUES (8, 'MANUAL:dacf586e-88cc-4376-901a-353aa7a71371', 'MANUAL', NULL, '2026-11-01', '2026-11-03', 'SUCCESS', 2, 1, 1, 0, '2026-11-04 18:48:53.686000', '2026-11-04 18:48:54.367000', NULL, 1, '2026-11-04 18:48:53.654000', '2026-11-04 18:48:54.369000'); |
| | | |
| | | |
| | | -- energy_meter_sync_task: 28 rows |
| | | |
| | | INSERT INTO `energy_meter_sync_task` (`id`, `run_id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `range_start`, `range_end`, `status`, `attempt_count`, `next_retry_at`, `fetched_count`, `inserted_count`, `updated_count`, `error_code`, `error_message`, `started_at`, `finished_at`, `create_time`, `update_time`) VALUES (1, 1, 208, 1, 'GetUseWater', 'D', '2026-10-13', '2026-11-03', 'SUCCESS', 1, NULL, 22, 22, 0, NULL, NULL, '2026-11-04 15:17:38.511000', '2026-11-04 15:17:39.138000', '2026-11-04 15:17:38.372000', '2026-11-04 15:17:39.152000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_task` (`id`, `run_id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `range_start`, `range_end`, `status`, `attempt_count`, `next_retry_at`, `fetched_count`, `inserted_count`, `updated_count`, `error_code`, `error_message`, `started_at`, `finished_at`, `create_time`, `update_time`) VALUES (2, 1, 208, 1, 'GetWaterRawData', 'POINT', '2026-10-13', '2026-10-27', 'SUCCESS', 1, NULL, 15, 15, 0, NULL, NULL, '2026-11-04 15:17:38.511000', '2026-11-04 15:17:38.986000', '2026-11-04 15:17:38.378000', '2026-11-04 15:17:39.003000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_task` (`id`, `run_id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `range_start`, `range_end`, `status`, `attempt_count`, `next_retry_at`, `fetched_count`, `inserted_count`, `updated_count`, `error_code`, `error_message`, `started_at`, `finished_at`, `create_time`, `update_time`) VALUES (3, 1, 208, 1, 'GetWaterRawData', 'POINT', '2026-10-28', '2026-11-03', 'SUCCESS', 1, NULL, 6, 6, 0, NULL, NULL, '2026-11-04 15:17:39.016000', '2026-11-04 15:17:39.697000', '2026-11-04 15:17:38.385000', '2026-11-04 15:17:39.705000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_task` (`id`, `run_id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `range_start`, `range_end`, `status`, `attempt_count`, `next_retry_at`, `fetched_count`, `inserted_count`, `updated_count`, `error_code`, `error_message`, `started_at`, `finished_at`, `create_time`, `update_time`) VALUES (4, 1, 208, 2, 'GetUseWater', 'D', '2026-10-13', '2026-11-03', 'SUCCESS', 1, NULL, 22, 22, 0, NULL, NULL, '2026-11-04 15:17:39.162000', '2026-11-04 15:17:40.379000', '2026-11-04 15:17:38.391000', '2026-11-04 15:17:40.392000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_task` (`id`, `run_id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `range_start`, `range_end`, `status`, `attempt_count`, `next_retry_at`, `fetched_count`, `inserted_count`, `updated_count`, `error_code`, `error_message`, `started_at`, `finished_at`, `create_time`, `update_time`) VALUES (5, 1, 208, 2, 'GetWaterRawData', 'POINT', '2026-10-13', '2026-10-27', 'SUCCESS', 1, NULL, 14, 14, 0, NULL, NULL, '2026-11-04 15:17:39.715000', '2026-11-04 15:17:40.634000', '2026-11-04 15:17:38.397000', '2026-11-04 15:17:40.647000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_task` (`id`, `run_id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `range_start`, `range_end`, `status`, `attempt_count`, `next_retry_at`, `fetched_count`, `inserted_count`, `updated_count`, `error_code`, `error_message`, `started_at`, `finished_at`, `create_time`, `update_time`) VALUES (6, 1, 208, 2, 'GetWaterRawData', 'POINT', '2026-10-28', '2026-11-03', 'SUCCESS', 1, NULL, 6, 6, 0, NULL, NULL, '2026-11-04 15:17:40.659000', '2026-11-04 15:17:41.645000', '2026-11-04 15:17:38.403000', '2026-11-04 15:17:41.653000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_task` (`id`, `run_id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `range_start`, `range_end`, `status`, `attempt_count`, `next_retry_at`, `fetched_count`, `inserted_count`, `updated_count`, `error_code`, `error_message`, `started_at`, `finished_at`, `create_time`, `update_time`) VALUES (7, 1, 208, 3, 'GetUseWater', 'D', '2026-10-13', '2026-11-03', 'SUCCESS', 1, NULL, 22, 22, 0, NULL, NULL, '2026-11-04 15:17:40.405000', '2026-11-04 15:17:41.131000', '2026-11-04 15:17:38.410000', '2026-11-04 15:17:41.142000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_task` (`id`, `run_id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `range_start`, `range_end`, `status`, `attempt_count`, `next_retry_at`, `fetched_count`, `inserted_count`, `updated_count`, `error_code`, `error_message`, `started_at`, `finished_at`, `create_time`, `update_time`) VALUES (8, 1, 208, 3, 'GetWaterRawData', 'POINT', '2026-10-13', '2026-10-27', 'SUCCESS', 1, NULL, 16, 16, 0, NULL, NULL, '2026-11-04 15:17:41.154000', '2026-11-04 15:17:42.170000', '2026-11-04 15:17:38.416000', '2026-11-04 15:17:42.180000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_task` (`id`, `run_id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `range_start`, `range_end`, `status`, `attempt_count`, `next_retry_at`, `fetched_count`, `inserted_count`, `updated_count`, `error_code`, `error_message`, `started_at`, `finished_at`, `create_time`, `update_time`) VALUES (9, 1, 208, 3, 'GetWaterRawData', 'POINT', '2026-10-28', '2026-11-03', 'SUCCESS', 1, NULL, 6, 6, 0, NULL, NULL, '2026-11-04 15:17:42.190000', '2026-11-04 15:17:43.133000', '2026-11-04 15:17:38.422000', '2026-11-04 15:17:43.140000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_task` (`id`, `run_id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `range_start`, `range_end`, `status`, `attempt_count`, `next_retry_at`, `fetched_count`, `inserted_count`, `updated_count`, `error_code`, `error_message`, `started_at`, `finished_at`, `create_time`, `update_time`) VALUES (10, 1, 208, 4, 'GetUseWater', 'D', '2026-10-13', '2026-11-03', 'SUCCESS', 1, NULL, 22, 22, 0, NULL, NULL, '2026-11-04 15:17:41.662000', '2026-11-04 15:17:42.658000', '2026-11-04 15:17:38.429000', '2026-11-04 15:17:42.670000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_task` (`id`, `run_id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `range_start`, `range_end`, `status`, `attempt_count`, `next_retry_at`, `fetched_count`, `inserted_count`, `updated_count`, `error_code`, `error_message`, `started_at`, `finished_at`, `create_time`, `update_time`) VALUES (11, 1, 208, 4, 'GetWaterRawData', 'POINT', '2026-10-13', '2026-10-27', 'SUCCESS', 1, NULL, 16, 16, 0, NULL, NULL, '2026-11-04 15:17:42.681000', '2026-11-04 15:17:43.678000', '2026-11-04 15:17:38.435000', '2026-11-04 15:17:43.688000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_task` (`id`, `run_id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `range_start`, `range_end`, `status`, `attempt_count`, `next_retry_at`, `fetched_count`, `inserted_count`, `updated_count`, `error_code`, `error_message`, `started_at`, `finished_at`, `create_time`, `update_time`) VALUES (12, 1, 208, 4, 'GetWaterRawData', 'POINT', '2026-10-28', '2026-11-03', 'SUCCESS', 1, NULL, 6, 6, 0, NULL, NULL, '2026-11-04 15:17:43.696000', '2026-11-04 15:17:44.657000', '2026-11-04 15:17:38.441000', '2026-11-04 15:17:44.667000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_task` (`id`, `run_id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `range_start`, `range_end`, `status`, `attempt_count`, `next_retry_at`, `fetched_count`, `inserted_count`, `updated_count`, `error_code`, `error_message`, `started_at`, `finished_at`, `create_time`, `update_time`) VALUES (13, 1, 208, 5, 'GetUseWater', 'D', '2026-10-13', '2026-11-03', 'SUCCESS', 1, NULL, 22, 22, 0, NULL, NULL, '2026-11-04 15:17:43.149000', '2026-11-04 15:17:44.161000', '2026-11-04 15:17:38.448000', '2026-11-04 15:17:44.173000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_task` (`id`, `run_id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `range_start`, `range_end`, `status`, `attempt_count`, `next_retry_at`, `fetched_count`, `inserted_count`, `updated_count`, `error_code`, `error_message`, `started_at`, `finished_at`, `create_time`, `update_time`) VALUES (14, 1, 208, 5, 'GetWaterRawData', 'POINT', '2026-10-13', '2026-10-27', 'SUCCESS', 1, NULL, 14, 14, 0, NULL, NULL, '2026-11-04 15:17:44.186000', '2026-11-04 15:17:45.136000', '2026-11-04 15:17:38.453000', '2026-11-04 15:17:45.147000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_task` (`id`, `run_id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `range_start`, `range_end`, `status`, `attempt_count`, `next_retry_at`, `fetched_count`, `inserted_count`, `updated_count`, `error_code`, `error_message`, `started_at`, `finished_at`, `create_time`, `update_time`) VALUES (15, 1, 208, 5, 'GetWaterRawData', 'POINT', '2026-10-28', '2026-11-03', 'SUCCESS', 1, NULL, 6, 6, 0, NULL, NULL, '2026-11-04 15:17:45.156000', '2026-11-04 15:17:46.156000', '2026-11-04 15:17:38.459000', '2026-11-04 15:17:46.162000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_task` (`id`, `run_id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `range_start`, `range_end`, `status`, `attempt_count`, `next_retry_at`, `fetched_count`, `inserted_count`, `updated_count`, `error_code`, `error_message`, `started_at`, `finished_at`, `create_time`, `update_time`) VALUES (16, 1, 208, 6, 'GetUseWater', 'D', '2026-10-13', '2026-11-03', 'SUCCESS', 1, NULL, 22, 22, 0, NULL, NULL, '2026-11-04 15:17:44.677000', '2026-11-04 15:17:45.661000', '2026-11-04 15:17:38.466000', '2026-11-04 15:17:45.678000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_task` (`id`, `run_id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `range_start`, `range_end`, `status`, `attempt_count`, `next_retry_at`, `fetched_count`, `inserted_count`, `updated_count`, `error_code`, `error_message`, `started_at`, `finished_at`, `create_time`, `update_time`) VALUES (17, 1, 208, 6, 'GetWaterRawData', 'POINT', '2026-10-13', '2026-10-27', 'SUCCESS', 2, NULL, 15, 15, 0, NULL, NULL, '2026-11-04 15:19:53.380000', '2026-11-04 15:19:53.660000', '2026-11-04 15:17:38.471000', '2026-11-04 15:19:53.671000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_task` (`id`, `run_id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `range_start`, `range_end`, `status`, `attempt_count`, `next_retry_at`, `fetched_count`, `inserted_count`, `updated_count`, `error_code`, `error_message`, `started_at`, `finished_at`, `create_time`, `update_time`) VALUES (18, 1, 208, 6, 'GetWaterRawData', 'POINT', '2026-10-28', '2026-11-03', 'SUCCESS', 2, NULL, 6, 6, 0, NULL, NULL, '2026-11-04 15:19:53.682000', '2026-11-04 15:19:54.095000', '2026-11-04 15:17:38.477000', '2026-11-04 15:19:54.101000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_task` (`id`, `run_id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `range_start`, `range_end`, `status`, `attempt_count`, `next_retry_at`, `fetched_count`, `inserted_count`, `updated_count`, `error_code`, `error_message`, `started_at`, `finished_at`, `create_time`, `update_time`) VALUES (25, 5, 208, 7, 'FrozenElectricity', 'D', '2026-11-01', '2026-11-04', 'SUCCESS', 1, NULL, 1, 1, 0, NULL, NULL, '2026-11-04 17:31:29.094000', '2026-11-04 17:31:29.338000', '2026-11-04 17:31:29.017000', '2026-11-04 17:31:29.355000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_task` (`id`, `run_id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `range_start`, `range_end`, `status`, `attempt_count`, `next_retry_at`, `fetched_count`, `inserted_count`, `updated_count`, `error_code`, `error_message`, `started_at`, `finished_at`, `create_time`, `update_time`) VALUES (26, 5, 208, 7, 'FrozenElectricity', 'POINT', '2026-11-01', '2026-11-04', 'SUCCESS', 1, NULL, 1, 1, 0, NULL, NULL, '2026-11-04 17:31:29.094000', '2026-11-04 17:31:29.819000', '2026-11-04 17:31:29.025000', '2026-11-04 17:31:29.831000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_task` (`id`, `run_id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `range_start`, `range_end`, `status`, `attempt_count`, `next_retry_at`, `fetched_count`, `inserted_count`, `updated_count`, `error_code`, `error_message`, `started_at`, `finished_at`, `create_time`, `update_time`) VALUES (27, 5, 208, 8, 'FrozenElectricity', 'D', '2026-11-01', '2026-11-04', 'SUCCESS', 1, NULL, 1, 1, 0, NULL, NULL, '2026-11-04 17:31:29.373000', '2026-11-04 17:31:30.214000', '2026-11-04 17:31:29.033000', '2026-11-04 17:31:30.233000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_task` (`id`, `run_id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `range_start`, `range_end`, `status`, `attempt_count`, `next_retry_at`, `fetched_count`, `inserted_count`, `updated_count`, `error_code`, `error_message`, `started_at`, `finished_at`, `create_time`, `update_time`) VALUES (28, 5, 208, 8, 'FrozenElectricity', 'POINT', '2026-11-01', '2026-11-04', 'SUCCESS', 1, NULL, 1, 1, 0, NULL, NULL, '2026-11-04 17:31:29.849000', '2026-11-04 17:31:30.773000', '2026-11-04 17:31:29.041000', '2026-11-04 17:31:30.785000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_task` (`id`, `run_id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `range_start`, `range_end`, `status`, `attempt_count`, `next_retry_at`, `fetched_count`, `inserted_count`, `updated_count`, `error_code`, `error_message`, `started_at`, `finished_at`, `create_time`, `update_time`) VALUES (29, 5, 208, 9, 'FrozenElectricity', 'D', '2026-11-01', '2026-11-04', 'SUCCESS', 1, NULL, 1, 1, 0, NULL, NULL, '2026-11-04 17:31:30.252000', '2026-11-04 17:31:31.233000', '2026-11-04 17:31:29.049000', '2026-11-04 17:31:31.255000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_task` (`id`, `run_id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `range_start`, `range_end`, `status`, `attempt_count`, `next_retry_at`, `fetched_count`, `inserted_count`, `updated_count`, `error_code`, `error_message`, `started_at`, `finished_at`, `create_time`, `update_time`) VALUES (30, 5, 208, 9, 'FrozenElectricity', 'POINT', '2026-11-01', '2026-11-04', 'SUCCESS', 1, NULL, 1, 1, 0, NULL, NULL, '2026-11-04 17:31:30.802000', '2026-11-04 17:31:31.779000', '2026-11-04 17:31:29.057000', '2026-11-04 17:31:31.798000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_task` (`id`, `run_id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `range_start`, `range_end`, `status`, `attempt_count`, `next_retry_at`, `fetched_count`, `inserted_count`, `updated_count`, `error_code`, `error_message`, `started_at`, `finished_at`, `create_time`, `update_time`) VALUES (34, 7, 208, 7, 'ElectricQuantity', 'D', '2026-11-01', '2026-11-03', 'EMPTY', 1, NULL, 0, 0, 0, NULL, NULL, '2026-11-04 18:48:51.059000', '2026-11-04 18:48:51.697000', '2026-11-04 18:48:51.019000', '2026-11-04 18:48:51.702000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_task` (`id`, `run_id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `range_start`, `range_end`, `status`, `attempt_count`, `next_retry_at`, `fetched_count`, `inserted_count`, `updated_count`, `error_code`, `error_message`, `started_at`, `finished_at`, `create_time`, `update_time`) VALUES (35, 7, 208, 7, 'FrozenElectricity', 'POINT', '2026-11-01', '2026-11-03', 'SUCCESS', 1, NULL, 1, 0, 0, NULL, NULL, '2026-11-04 18:48:51.059000', '2026-11-04 18:48:51.323000', '2026-11-04 18:48:51.027000', '2026-11-04 18:48:51.331000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_task` (`id`, `run_id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `range_start`, `range_end`, `status`, `attempt_count`, `next_retry_at`, `fetched_count`, `inserted_count`, `updated_count`, `error_code`, `error_message`, `started_at`, `finished_at`, `create_time`, `update_time`) VALUES (36, 8, 208, 7, 'ElectricQuantity', 'D', '2026-11-01', '2026-11-03', 'EMPTY', 1, NULL, 0, 0, 0, NULL, NULL, '2026-11-04 18:48:53.700000', '2026-11-04 18:48:54.324000', '2026-11-04 18:48:53.661000', '2026-11-04 18:48:54.330000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_task` (`id`, `run_id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `range_start`, `range_end`, `status`, `attempt_count`, `next_retry_at`, `fetched_count`, `inserted_count`, `updated_count`, `error_code`, `error_message`, `started_at`, `finished_at`, `create_time`, `update_time`) VALUES (37, 8, 208, 7, 'FrozenElectricity', 'POINT', '2026-11-01', '2026-11-03', 'SUCCESS', 1, NULL, 1, 0, 0, NULL, NULL, '2026-11-04 18:48:53.700000', '2026-11-04 18:48:53.870000', '2026-11-04 18:48:53.669000', '2026-11-04 18:48:53.877000'); |
| | | |
| | | |
| | | -- energy_meter_sync_checkpoint: 19 rows |
| | | |
| | | INSERT INTO `energy_meter_sync_checkpoint` (`id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `last_complete_date`, `last_success_at`, `last_run_id`, `create_time`, `update_time`) VALUES (1, 208, 1, 'GetWaterRawData', 'POINT', '2026-11-03', '2026-11-04 15:17:39.697000', 1, '2026-11-04 15:17:39.008000', '2026-11-04 15:17:39.710000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_checkpoint` (`id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `last_complete_date`, `last_success_at`, `last_run_id`, `create_time`, `update_time`) VALUES (2, 208, 1, 'GetUseWater', 'D', '2026-11-03', '2026-11-04 15:17:39.138000', 1, '2026-11-04 15:17:39.157000', '2026-11-04 15:17:39.157000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_checkpoint` (`id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `last_complete_date`, `last_success_at`, `last_run_id`, `create_time`, `update_time`) VALUES (4, 208, 2, 'GetUseWater', 'D', '2026-11-03', '2026-11-04 15:17:40.379000', 1, '2026-11-04 15:17:40.399000', '2026-11-04 15:17:40.399000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_checkpoint` (`id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `last_complete_date`, `last_success_at`, `last_run_id`, `create_time`, `update_time`) VALUES (5, 208, 2, 'GetWaterRawData', 'POINT', '2026-11-03', '2026-11-04 15:17:41.645000', 1, '2026-11-04 15:17:40.654000', '2026-11-04 15:17:41.658000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_checkpoint` (`id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `last_complete_date`, `last_success_at`, `last_run_id`, `create_time`, `update_time`) VALUES (6, 208, 3, 'GetUseWater', 'D', '2026-11-03', '2026-11-04 15:17:41.131000', 1, '2026-11-04 15:17:41.148000', '2026-11-04 15:17:41.148000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_checkpoint` (`id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `last_complete_date`, `last_success_at`, `last_run_id`, `create_time`, `update_time`) VALUES (8, 208, 3, 'GetWaterRawData', 'POINT', '2026-11-03', '2026-11-04 15:17:43.133000', 1, '2026-11-04 15:17:42.183000', '2026-11-04 15:17:43.143000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_checkpoint` (`id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `last_complete_date`, `last_success_at`, `last_run_id`, `create_time`, `update_time`) VALUES (9, 208, 4, 'GetUseWater', 'D', '2026-11-03', '2026-11-04 15:17:42.658000', 1, '2026-11-04 15:17:42.674000', '2026-11-04 15:17:42.674000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_checkpoint` (`id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `last_complete_date`, `last_success_at`, `last_run_id`, `create_time`, `update_time`) VALUES (11, 208, 4, 'GetWaterRawData', 'POINT', '2026-11-03', '2026-11-04 15:17:44.657000', 1, '2026-11-04 15:17:43.692000', '2026-11-04 15:17:44.672000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_checkpoint` (`id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `last_complete_date`, `last_success_at`, `last_run_id`, `create_time`, `update_time`) VALUES (12, 208, 5, 'GetUseWater', 'D', '2026-11-03', '2026-11-04 15:17:44.161000', 1, '2026-11-04 15:17:44.180000', '2026-11-04 15:17:44.180000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_checkpoint` (`id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `last_complete_date`, `last_success_at`, `last_run_id`, `create_time`, `update_time`) VALUES (14, 208, 5, 'GetWaterRawData', 'POINT', '2026-11-03', '2026-11-04 15:17:46.156000', 1, '2026-11-04 15:17:45.151000', '2026-11-04 15:17:46.167000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_checkpoint` (`id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `last_complete_date`, `last_success_at`, `last_run_id`, `create_time`, `update_time`) VALUES (15, 208, 6, 'GetUseWater', 'D', '2026-11-03', '2026-11-04 15:17:45.661000', 1, '2026-11-04 15:17:45.685000', '2026-11-04 15:17:45.685000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_checkpoint` (`id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `last_complete_date`, `last_success_at`, `last_run_id`, `create_time`, `update_time`) VALUES (17, 208, 6, 'GetWaterRawData', 'POINT', '2026-11-03', '2026-11-04 15:19:54.095000', 1, '2026-11-04 15:19:53.676000', '2026-11-04 15:19:54.104000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_checkpoint` (`id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `last_complete_date`, `last_success_at`, `last_run_id`, `create_time`, `update_time`) VALUES (19, 208, 7, 'FrozenElectricity', 'POINT', '2026-11-04', '2026-11-04 18:48:53.870000', 8, '2026-11-04 17:23:25.512000', '2026-11-04 18:48:53.886000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_checkpoint` (`id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `last_complete_date`, `last_success_at`, `last_run_id`, `create_time`, `update_time`) VALUES (20, 208, 8, 'FrozenElectricity', 'POINT', '2026-11-04', '2026-11-04 17:31:30.773000', 5, '2026-11-04 17:23:31.211000', '2026-11-04 17:31:30.796000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_checkpoint` (`id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `last_complete_date`, `last_success_at`, `last_run_id`, `create_time`, `update_time`) VALUES (21, 208, 9, 'FrozenElectricity', 'POINT', '2026-11-04', '2026-11-04 17:31:31.779000', 5, '2026-11-04 17:23:34.112000', '2026-11-04 17:31:31.808000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_checkpoint` (`id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `last_complete_date`, `last_success_at`, `last_run_id`, `create_time`, `update_time`) VALUES (22, 208, 7, 'FrozenElectricity', 'D', '2026-11-04', '2026-11-04 17:31:29.338000', 5, '2026-11-04 17:30:48.070000', '2026-11-04 17:31:29.366000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_checkpoint` (`id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `last_complete_date`, `last_success_at`, `last_run_id`, `create_time`, `update_time`) VALUES (23, 208, 8, 'FrozenElectricity', 'D', '2026-11-04', '2026-11-04 17:31:30.214000', 5, '2026-11-04 17:30:48.401000', '2026-11-04 17:31:30.246000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_checkpoint` (`id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `last_complete_date`, `last_success_at`, `last_run_id`, `create_time`, `update_time`) VALUES (24, 208, 9, 'FrozenElectricity', 'D', '2026-11-04', '2026-11-04 17:31:31.233000', 5, '2026-11-04 17:30:48.913000', '2026-11-04 17:31:31.265000'); |
| | | |
| | | INSERT INTO `energy_meter_sync_checkpoint` (`id`, `tenant_id`, `meter_id`, `source_api`, `granularity`, `last_complete_date`, `last_success_at`, `last_run_id`, `create_time`, `update_time`) VALUES (32, 208, 7, 'ElectricQuantity', 'D', '2026-11-03', '2026-11-04 18:48:54.324000', 8, '2026-11-04 18:48:51.713000', '2026-11-04 18:48:54.340000'); |
| | | |
| | | SET FOREIGN_KEY_CHECKS = 1; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | -- ============================================================ |
| | | -- æ°´çµè¡¨æ¥å
¥ ââ 宿´èæ¬ï¼MySQL 8 / InnoDB / utf8mb4ï¼ |
| | | -- æ§è¡é¡ºåºï¼å 餿§è¡¨ â 建表 â æ¸
çèå â åå§åè®¾å¤ |
| | | -- 注æï¼æ¬èæ¬ä¼æ¸
空 energy_meter_* å
¨é¨æ°æ®ï¼ä»
å¼å/æ¼ç¤ºåºç´æ¥æ§è¡ï¼ |
| | | -- ç产åºè¯·æ¹å为 ALTER TABLE å¢éèæ¬ï¼ä¸è¦ç´æ¥è·æ¬æä»¶ã |
| | | -- 说æï¼è®¾å¤è¡¨å·ä¸ç¬¬ä¸æ¹ ID æ¥èªé社äºç宿¡£æ¡ï¼çå®ç¨ééé
ç½®ç¯å¢åé NH_ENERGY_API_KEY åééã |
| | | -- ============================================================ |
| | | |
| | | -- ============================================================ |
| | | -- ä¸ãå 餿§è¡¨ï¼ä¼æ¸
空 energy_meter_* å
¨é¨æ°æ®ï¼ |
| | | -- ============================================================ |
| | | |
| | | -- ============================================================ |
| | | -- æ°´çµè¡¨æ¥å
¥ï¼è®¾å¤å°è´¦ + æå·¥æè¡¨ + æ°è¡¨ï¼ââ å 表 |
| | | -- æ§è¡ç¯å¢ï¼ä»
å¼å/æ¼ç¤ºåºï¼ä¼æ¸
空 energy_meter_* å
¨é¨æ°æ® |
| | | -- å 表顺åºï¼ä»»å¡ â è¿åº¦ â æ¹æ¬¡ â ééæ°æ® â è®¾å¤ |
| | | -- ============================================================ |
| | | |
| | | -- 1. å设å¤åæ¥ä»»å¡ |
| | | DROP TABLE IF EXISTS `energy_meter_sync_task`; |
| | | |
| | | -- 2. æ¯æ¥å£è¿ç»åæ¥è¿åº¦ |
| | | DROP TABLE IF EXISTS `energy_meter_sync_checkpoint`; |
| | | |
| | | -- 3. 忥æ§è¡æ¹æ¬¡ |
| | | DROP TABLE IF EXISTS `energy_meter_sync_run`; |
| | | |
| | | -- 4. ç¨éã示å¼ä¸è´¹ç¨ |
| | | DROP TABLE IF EXISTS `energy_meter_measurement`; |
| | | |
| | | -- 5. æ¬å°ç»å®æ¡£æ¡ |
| | | DROP TABLE IF EXISTS `energy_meter_device`; |
| | | |
| | | -- ============================================================ |
| | | -- äºã建表ï¼è®¾å¤å°è´¦ / ééæ°æ® / åæ¥æ¹æ¬¡ / ä»»å¡ / è¿åº¦ï¼ |
| | | -- ============================================================ |
| | | |
| | | -- ============================================================ |
| | | -- æ°´çµè¡¨æ¥å
¥ï¼è®¾å¤å°è´¦ + æå·¥æè¡¨ + æ°è¡¨ï¼ââ 建表 |
| | | -- 弿 InnoDB / å符é utf8mb4ï¼æ¶é´ç»ä¸ Asia/Shanghai |
| | | -- äºå¼ 表ï¼è®¾å¤å°è´¦ãééæ°æ®ãåæ¥æ¹æ¬¡ã忥任å¡ã忥è¿åº¦ |
| | | -- 䏿§çå·®å¼ï¼è®¾å¤è¡¨å¢å æ¥æº/åå§åæ è®°/èµ·å§è¡¨ç ï¼éé表å¢å remarkï¼ |
| | | -- è½æºç±»åå¢å æ°è¡¨ï¼GASï¼ |
| | | -- ============================================================ |
| | | |
| | | -- ------------------------------------------------------------ |
| | | -- 1. 设å¤å°è´¦ï¼æ°´è¡¨ / çµè¡¨ / æ°è¡¨ï¼ |
| | | -- ------------------------------------------------------------ |
| | | CREATE TABLE IF NOT EXISTS `energy_meter_device` ( |
| | | `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT 'æ¬å°è®¾å¤ID', |
| | | `tenant_id` BIGINT NOT NULL COMMENT 'ç§æ·ID', |
| | | `meter_type` VARCHAR(16) NOT NULL COMMENT 'è½æºç±»åï¼WATER水表 / ELECTRICçµè¡¨ / GASæ°è¡¨', |
| | | `source_type` VARCHAR(16) NOT NULL DEFAULT 'PROVIDER' COMMENT 'æ°æ®æ¥æºï¼PROVIDERç¬¬ä¸æ¹æ¥å
¥ / MANUALæå·¥æè¡¨', |
| | | `meter_address` VARCHAR(64) NOT NULL COMMENT 'éä¿¡å°åæè¡¨å·ï¼æå符串ä¿åï¼ä¿çå导é¶', |
| | | `provider_meter_id` VARCHAR(64) DEFAULT NULL COMMENT 'ç¬¬ä¸æ¹è®¾å¤ID', |
| | | `provider_name` VARCHAR(128) DEFAULT NULL COMMENT 'ç¬¬ä¸æ¹è®¾å¤åç§°', |
| | | `display_name` VARCHAR(128) NOT NULL COMMENT 'æ¬ç³»ç»æ¾ç¤ºåç§°', |
| | | `provider_area_id` BIGINT DEFAULT NULL COMMENT 'ç¬¬ä¸æ¹åºåID', |
| | | `provider_area_name` VARCHAR(128) DEFAULT NULL COMMENT 'ç¬¬ä¸æ¹åºååç§°', |
| | | `parent_provider_id` VARCHAR(64) DEFAULT NULL COMMENT 'ç¬¬ä¸æ¹æ»è¡¨ID', |
| | | `parent_meter_id` BIGINT DEFAULT NULL COMMENT 'æ¬å°æ»è¡¨IDï¼ç¡®è®¤æ å°åç»´æ¤', |
| | | `location` VARCHAR(255) DEFAULT NULL COMMENT 'å®è£
ä½ç½®', |
| | | `online_status` TINYINT DEFAULT NULL COMMENT '1å¨çº¿ 0离线 NULLæªç¥', |
| | | `bind_status` VARCHAR(16) NOT NULL DEFAULT 'VERIFIED' COMMENT 'VERIFIED/INVALID', |
| | | `enabled` TINYINT NOT NULL DEFAULT 1 COMMENT '1å¯ç¨ 0åç¨', |
| | | `is_seed` TINYINT NOT NULL DEFAULT 0 COMMENT '1åå§å设å¤ï¼ç¦æ¢å é¤ï¼0ç¨æ·æ°å¢', |
| | | `simulated` TINYINT NOT NULL DEFAULT 0 COMMENT '1æ¼ç¤ºæ°æ®ï¼æ¯æ¥æ¨¡æçæï¼0çå®è®¾å¤', |
| | | `initial_reading` DECIMAL(20,6) DEFAULT NULL COMMENT 'æå·¥æè¡¨èµ·å§è¡¨ç ', |
| | | `initial_reading_date` DATE DEFAULT NULL COMMENT 'èµ·å§è¡¨ç 对åºä¸å¡æ¥æ', |
| | | `sync_start_date` DATE NOT NULL COMMENT 'æ¬è®¾å¤ææ©éè¦åæ¥çä¸å¡æ¥æ', |
| | | `last_success_at` DATETIME(3) DEFAULT NULL COMMENT 'æè¿æåéé/æè¡¨æ¶é´', |
| | | `last_error_code` VARCHAR(64) DEFAULT NULL COMMENT 'æè¿ééé误类å«', |
| | | `last_error_message` VARCHAR(255) DEFAULT NULL COMMENT 'è±æé误æè¦', |
| | | `create_user` BIGINT DEFAULT NULL COMMENT 'å建人', |
| | | `create_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'å建æ¶é´', |
| | | `update_user` BIGINT DEFAULT NULL COMMENT 'ä¿®æ¹äºº', |
| | | `update_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT 'ä¿®æ¹æ¶é´', |
| | | PRIMARY KEY (`id`), |
| | | UNIQUE KEY `uk_em_device_tenant_type_address` (`tenant_id`, `meter_type`, `meter_address`), |
| | | KEY `idx_em_device_scan` (`enabled`, `bind_status`, `meter_type`, `id`), |
| | | KEY `idx_em_device_parent` (`parent_meter_id`), |
| | | KEY `idx_em_device_source` (`tenant_id`, `source_type`, `meter_type`, `enabled`) |
| | | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='设å¤å°è´¦ï¼æ°´è¡¨/çµè¡¨/æ°è¡¨'; |
| | | |
| | | -- ------------------------------------------------------------ |
| | | -- 2. ç¨éã示å¼ä¸è´¹ç¨ |
| | | -- ------------------------------------------------------------ |
| | | CREATE TABLE IF NOT EXISTS `energy_meter_measurement` ( |
| | | `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT 'ééæ°æ®ID', |
| | | `tenant_id` BIGINT NOT NULL COMMENT 'ç§æ·ID', |
| | | `meter_id` BIGINT NOT NULL COMMENT 'æ¬å°è®¾å¤ID', |
| | | `metric_code` VARCHAR(32) NOT NULL COMMENT 'WATER_USAGE/WATER_READING/ELECTRIC_USAGE/ELECTRIC_READING/ELECTRIC_COST/GAS_USAGE/GAS_READING', |
| | | `granularity` VARCHAR(8) NOT NULL COMMENT 'Dæ¥/Mæ/Yå¹´/POINTæ¶ç¹', |
| | | `measure_time` DATETIME NOT NULL COMMENT 'æé´èµ·ç¹æç¤ºå¼æ¶ç¹ï¼Asia/Shanghai', |
| | | `metric_value` DECIMAL(20,6) NOT NULL COMMENT 'å®é
æé´ç¨éãç¤ºå¼æè´¹ç¨', |
| | | `unit` VARCHAR(16) NOT NULL COMMENT 'm3/kWh/CNY', |
| | | `source_api` VARCHAR(64) NOT NULL COMMENT 'æ¥æºæ è¯ï¼ç¬¬ä¸æ¹æ¥å£åæ MANUAL', |
| | | `source_record_time` DATETIME DEFAULT NULL COMMENT 'ç¬¬ä¸æ¹åå§ReadingDateè§£æå¼ï¼æå·¥æè¡¨ä¸ºæè¡¨æ¥æ', |
| | | `collected_at` DATETIME(3) NOT NULL COMMENT 'æ¬ç³»ç»ééæ¶é´', |
| | | `remark` VARCHAR(255) DEFAULT NULL COMMENT '夿³¨ï¼æå·¥æè¡¨è¯´æ', |
| | | `create_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '馿¬¡å
¥åºæ¶é´', |
| | | `update_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT 'æåä¿®æ£æ¶é´', |
| | | PRIMARY KEY (`id`), |
| | | UNIQUE KEY `uk_em_measurement_point` (`meter_id`, `metric_code`, `granularity`, `measure_time`), |
| | | KEY `idx_em_measurement_query` (`tenant_id`, `meter_id`, `metric_code`, `granularity`, `measure_time`), |
| | | KEY `idx_em_measurement_time` (`tenant_id`, `metric_code`, `granularity`, `measure_time`), |
| | | KEY `idx_em_measurement_source` (`meter_id`, `source_api`, `granularity`, `measure_time`) |
| | | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='ç¨éã示å¼åå·²éªè¯è´¹ç¨'; |
| | | |
| | | -- ------------------------------------------------------------ |
| | | -- 3. 忥æ§è¡æ¹æ¬¡ |
| | | -- ------------------------------------------------------------ |
| | | CREATE TABLE IF NOT EXISTS `energy_meter_sync_run` ( |
| | | `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT 'åæ¥æ¹æ¬¡ID', |
| | | `run_key` VARCHAR(80) NOT NULL COMMENT 'èªå¨æ¹æ¬¡AUTO:yyyyMMddï¼æå¨æ¹æ¬¡ä½¿ç¨UUID', |
| | | `trigger_type` VARCHAR(16) NOT NULL COMMENT 'SCHEDULED/MANUAL/BACKFILL', |
| | | `schedule_date` DATE DEFAULT NULL COMMENT 'è®¡åæ§è¡æ¥ï¼å京æ¶é´ï¼é宿¶æ¹æ¬¡ä¸ºç©º', |
| | | `range_start` DATE NOT NULL COMMENT '忥å¼å§æ¥æï¼å«', |
| | | `range_end` DATE NOT NULL COMMENT 'åæ¥ç»ææ¥æï¼å«', |
| | | `status` VARCHAR(16) NOT NULL DEFAULT 'PENDING' COMMENT 'PENDING/RUNNING/SUCCESS/PARTIAL/FAILED', |
| | | `total_tasks` INT NOT NULL DEFAULT 0 COMMENT '任塿»æ°', |
| | | `success_tasks` INT NOT NULL DEFAULT 0 COMMENT 'æå任塿°', |
| | | `empty_tasks` INT NOT NULL DEFAULT 0 COMMENT 'ç¡®è®¤æ æ°æ®ä»»å¡æ°', |
| | | `failed_tasks` INT NOT NULL DEFAULT 0 COMMENT 'å¤±è´¥ä»»å¡æ°', |
| | | `started_at` DATETIME(3) DEFAULT NULL COMMENT 'å¼å§æ¶é´', |
| | | `finished_at` DATETIME(3) DEFAULT NULL COMMENT 'ç»ææ¶é´', |
| | | `error_summary` VARCHAR(500) DEFAULT NULL COMMENT 'è±æé误æè¦', |
| | | `create_user` BIGINT DEFAULT NULL COMMENT '触å人ï¼ç³»ç»ä»»å¡ä¸ºç©º', |
| | | `create_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'å建æ¶é´', |
| | | `update_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT 'ä¿®æ¹æ¶é´', |
| | | PRIMARY KEY (`id`), |
| | | UNIQUE KEY `uk_em_sync_run_key` (`run_key`), |
| | | KEY `idx_em_sync_run_schedule` (`trigger_type`, `schedule_date`, `status`), |
| | | KEY `idx_em_sync_run_created` (`create_time`) |
| | | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='忥æ§è¡æ¹æ¬¡'; |
| | | |
| | | -- ------------------------------------------------------------ |
| | | -- 4. å设å¤åæ¥ä»»å¡ |
| | | -- ------------------------------------------------------------ |
| | | CREATE TABLE IF NOT EXISTS `energy_meter_sync_task` ( |
| | | `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT 'å设å¤åæ¥å£åæ¥ä»»å¡ID', |
| | | `run_id` BIGINT NOT NULL COMMENT 'æå±æ¹æ¬¡ID', |
| | | `tenant_id` BIGINT NOT NULL COMMENT 'ç§æ·ID', |
| | | `meter_id` BIGINT NOT NULL COMMENT 'æ¬å°è®¾å¤ID', |
| | | `source_api` VARCHAR(64) NOT NULL COMMENT 'ç¬¬ä¸æ¹æ¥å£æ è¯', |
| | | `granularity` VARCHAR(8) NOT NULL COMMENT 'D/M/Y/POINT', |
| | | `range_start` DATE NOT NULL COMMENT '请æ±å¼å§æ¥æï¼å«', |
| | | `range_end` DATE NOT NULL COMMENT '请æ±ç»ææ¥æï¼å«', |
| | | `status` VARCHAR(16) NOT NULL DEFAULT 'PENDING' COMMENT 'PENDING/RUNNING/SUCCESS/EMPTY/RETRY/FAILED', |
| | | `attempt_count` INT NOT NULL DEFAULT 0 COMMENT 'å·²å°è¯æ¬¡æ°', |
| | | `next_retry_at` DATETIME(3) DEFAULT NULL COMMENT '䏿¬¡éè¯æ¶é´', |
| | | `fetched_count` INT NOT NULL DEFAULT 0 COMMENT '䏿¸¸è¿åæ¡æ°', |
| | | `inserted_count` INT NOT NULL DEFAULT 0 COMMENT 'æ°å¢æ¡æ°', |
| | | `updated_count` INT NOT NULL DEFAULT 0 COMMENT 'ä¿®æ£æ¡æ°', |
| | | `error_code` VARCHAR(64) DEFAULT NULL COMMENT 'è±æé误类å«', |
| | | `error_message` VARCHAR(500) DEFAULT NULL COMMENT 'è±æé误信æ¯', |
| | | `started_at` DATETIME(3) DEFAULT NULL COMMENT 'å¼å§æ¶é´', |
| | | `finished_at` DATETIME(3) DEFAULT NULL COMMENT '宿æ¶é´', |
| | | `create_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'å建æ¶é´', |
| | | `update_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT 'ä¿®æ¹æ¶é´', |
| | | PRIMARY KEY (`id`), |
| | | UNIQUE KEY `uk_em_sync_task_unit` (`run_id`, `meter_id`, `source_api`, `granularity`, `range_start`, `range_end`), |
| | | KEY `idx_em_sync_task_retry` (`status`, `next_retry_at`), |
| | | KEY `idx_em_sync_task_meter` (`tenant_id`, `meter_id`, `create_time`), |
| | | KEY `idx_em_sync_task_run` (`run_id`, `status`) |
| | | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='å设å¤åæ¥ä»»å¡åéè¯ç¶æ'; |
| | | |
| | | -- ------------------------------------------------------------ |
| | | -- 5. æ¯æ¥å£è¿ç»åæ¥è¿åº¦ |
| | | -- ------------------------------------------------------------ |
| | | CREATE TABLE IF NOT EXISTS `energy_meter_sync_checkpoint` ( |
| | | `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT 'è¡¥éè¿åº¦ID', |
| | | `tenant_id` BIGINT NOT NULL COMMENT 'ç§æ·ID', |
| | | `meter_id` BIGINT NOT NULL COMMENT 'æ¬å°è®¾å¤ID', |
| | | `source_api` VARCHAR(64) NOT NULL COMMENT 'ç¬¬ä¸æ¹æ¥å£æ è¯', |
| | | `granularity` VARCHAR(8) NOT NULL COMMENT 'D/M/Y/POINT', |
| | | `last_complete_date` DATE DEFAULT NULL COMMENT 'è¿ç»å®æå°çä¸å¡æ¥æï¼å«ï¼ä¸å¯è·¨è¿å¤±è´¥æ¥æ', |
| | | `last_success_at` DATETIME(3) DEFAULT NULL COMMENT 'æè¿æå确认æ¶é´', |
| | | `last_run_id` BIGINT DEFAULT NULL COMMENT 'æè¿æ¨è¿è¿åº¦çæ¹æ¬¡ID', |
| | | `create_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'å建æ¶é´', |
| | | `update_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT 'ä¿®æ¹æ¶é´', |
| | | PRIMARY KEY (`id`), |
| | | UNIQUE KEY `uk_em_sync_checkpoint_unit` (`meter_id`, `source_api`, `granularity`), |
| | | KEY `idx_em_sync_checkpoint_tenant` (`tenant_id`, `meter_id`) |
| | | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='æ¯æ¥å£è¿ç»åæ¥è¿åº¦'; |
| | | |
| | | -- ============================================================ |
| | | -- ä¸ãæ¸
çæ°æ®åºä¸çè½èèåï¼èåæ¹ä¸ºå端åºå®è·¯ç±ï¼ä¸å¨æ¤ç»´æ¤ï¼ |
| | | -- ============================================================ |
| | | |
| | | -- ============================================================ |
| | | -- æ°´çµè¡¨æ¥å
¥ ââ è忏
ç |
| | | -- 说æï¼è½è管çï¼è®¾å¤å°è´¦ã水表/çµè¡¨/æ°è¡¨æ°æ®ï¼ä»¥ååæç设å¤è½èãè½æºè¶å¿ã |
| | | -- ç¨çµåºåãç¨çµæ¶æ®µï¼å·²æ¹ä¸ºå端åºå®è·¯ç±ï¼è§ |
| | | -- product-inventory-management/src/router/index.js ä¸ç EnergyManagementï¼ |
| | | -- ä¸åä¾èµ sys_menu ä¸è§è²ææï¼ææç»å½ç¨æ·é½è½çå°ã |
| | | -- æ¬èæ¬å 餿°æ®åºä¸éççè½èèå䏿æï¼é¿å
ä¾§è¾¹æ åºç°éå¤åç»ã |
| | | -- å¯é夿§è¡ã |
| | | -- ============================================================ |
| | | |
| | | DELETE FROM `sys_role_menu` |
| | | WHERE `menu_id` IN (2064, 2065, 2066, 2076, 2080, 2081, |
| | | 2333, 2334, 2335, 2336, |
| | | 2400, 2401, 2402, 2403, 2404, 2405, 2406, 2407, 2408, 2409); |
| | | |
| | | DELETE FROM `sys_menu` |
| | | WHERE `menu_id` IN (2064, 2065, 2066, 2076, 2080, 2081, |
| | | 2333, 2334, 2335, 2336, |
| | | 2400, 2401, 2402, 2403, 2404, 2405, 2406, 2407, 2408, 2409); |
| | | |
| | | -- ============================================================ |
| | | -- åãåå§å设å¤ï¼7 å°æ°´è¡¨ + 3 å°çµè¡¨ï¼çå®è¡¨å·ï¼ä¸åæ¨¡ææ°æ®ï¼ |
| | | -- ============================================================ |
| | | |
| | | -- ============================================================ |
| | | -- æ°´çµè¡¨æ¥å
¥ ââ åå§åè®¾å¤ |
| | | -- è®¾å¤æ¥èª æ°æ®/设å¤å°å.md ççå®è¡¨å·ï¼ç¬¬ä¸æ¹ ID/åºå/å
¥ç½æ¥æå·²æéç¤¾äºæ¡£æ¡åå¡«ï¼ |
| | | -- 水表 7 å°ï¼ç¬¬ä¸æ¹ ID 32123~32134ã32758ï¼6 å°å
¥ç½ 2026-10-12ï¼ééèµ·ç¹ 2026-10-13ï¼ |
| | | -- äºæ¥¼åæç
®é
çº¯åæ°´å
¥ç½ 2026-11-04ï¼ééèµ·ç¹ 2026-11-04ï¼ |
| | | -- çµè¡¨ 3 å°ï¼ç¬¬ä¸æ¹ ID 270946 / 270949 / 270951ï¼2026-11-04 éæ°æ³¨åï¼ééèµ·ç¹ 2026-11-04ï¼åºåå为âçµè¡¨âï¼ |
| | | -- 说æï¼ |
| | | -- 1. å
¨é¨ is_seed=1ï¼å端ä¸å端é½ä¸å
许å é¤ï¼åªè½åç¨ï¼ |
| | | -- 2. åæ¥èµ·ç¹åå
¥ç½æ¬¡æ¥ç宿´èªç¶æ¥ï¼ä¹åçæ¥æä¾åºåæ²¡ææ°æ®ï¼ä¸å¿
è¡¥éï¼ |
| | | -- 3. çå®ç¨ééè¦é
ç½®ç¯å¢åé NH_ENERGY_API_KEYï¼æ¬èæ¬ä¸å任使¨¡ææ°æ®ï¼ |
| | | -- 4. å¯é夿§è¡ï¼æ§è¡å伿¸
空 5 å¼ è¡¨ã |
| | | -- ============================================================ |
| | | |
| | | SET @tenant := 208; |
| | | |
| | | -- æ¸
空ï¼é¡ºåºï¼ä»»å¡ â è¿åº¦ â æ¹æ¬¡ â éé â 设å¤ï¼ |
| | | DELETE FROM `energy_meter_sync_task`; |
| | | DELETE FROM `energy_meter_sync_checkpoint`; |
| | | DELETE FROM `energy_meter_sync_run`; |
| | | DELETE FROM `energy_meter_measurement`; |
| | | DELETE FROM `energy_meter_device`; |
| | | |
| | | INSERT INTO `energy_meter_device` |
| | | (`id`, `tenant_id`, `meter_type`, `source_type`, `meter_address`, |
| | | `provider_meter_id`, `provider_name`, `display_name`, `provider_area_name`, |
| | | `location`, `online_status`, `bind_status`, `enabled`, |
| | | `is_seed`, `initial_reading`, `initial_reading_date`, `sync_start_date`, |
| | | `last_success_at`, `create_user`, `create_time`, `update_time`) |
| | | VALUES |
| | | -- ---------------- 水表 7 å° ---------------- |
| | | (1, @tenant, 'WATER', 'PROVIDER', '12541588057907', |
| | | '32134', 'äºæ¥¼çè西å', 'äºæ¥¼çè西å', 'å
´çæºæµ·', |
| | | 'äºæ¥¼çè西å', 1, 'VERIFIED', 1, |
| | | 1, NULL, NULL, '2026-10-13', NULL, 1, NOW(3), NOW(3)), |
| | | (2, @tenant, 'WATER', 'PROVIDER', '12541588045261', |
| | | '32133', 'äºæ¥¼çäº§ç¨æ°´æ»æ°´è¡¨', 'äºæ¥¼çäº§ç¨æ°´æ»æ°´è¡¨', 'å
´çæºæµ·', |
| | | 'äºæ¥¼çäº§ç¨æ°´æ»æ°´è¡¨', 1, 'VERIFIED', 1, |
| | | 1, NULL, NULL, '2026-10-13', NULL, 1, NOW(3), NOW(3)), |
| | | (3, @tenant, 'WATER', 'PROVIDER', '12541588057898', |
| | | '32132', 'ç
®æ¯è水表', 'ç
®æ¯è水表', 'å
´çæºæµ·', |
| | | 'ç
®æ¯è水表', 1, 'VERIFIED', 1, |
| | | 1, NULL, NULL, '2026-10-13', NULL, 1, NOW(3), NOW(3)), |
| | | (4, @tenant, 'WATER', 'PROVIDER', '12541588057901', |
| | | '32131', 'æåæºæ´æ¯èå¤', 'æåæºæ´æ¯èå¤', 'å
´çæºæµ·', |
| | | 'æåæºæ´æ¯èå¤', 1, 'VERIFIED', 1, |
| | | 1, NULL, NULL, '2026-10-13', NULL, 1, NOW(3), NOW(3)), |
| | | (5, @tenant, 'WATER', 'PROVIDER', '12541588057897', |
| | | '32130', 'å忝è', 'å忝è', 'å
´çæºæµ·', |
| | | 'å忝è', 1, 'VERIFIED', 1, |
| | | 1, NULL, NULL, '2026-10-13', NULL, 1, NOW(3), NOW(3)), |
| | | (6, @tenant, 'WATER', 'PROVIDER', '12541588057908', |
| | | '32123', '䏿¥¼çº¯åæ°´æ»è¡¨', '䏿¥¼çº¯åæ°´æ»è¡¨', 'å
´çæºæµ·', |
| | | '䏿¥¼çº¯åæ°´æ»è¡¨', 1, 'VERIFIED', 1, |
| | | 1, NULL, NULL, '2026-10-13', NULL, 1, NOW(3), NOW(3)), |
| | | (10, @tenant, 'WATER', 'PROVIDER', '12541588057808', |
| | | '32758', 'äºæ¥¼åæç
®é
çº¯åæ°´', 'äºæ¥¼åæç
®é
çº¯åæ°´', '水表', |
| | | 'äºæ¥¼åæç
®é
çº¯åæ°´', 0, 'VERIFIED', 1, |
| | | 1, NULL, NULL, '2026-11-04', NULL, 1, NOW(3), NOW(3)), |
| | | -- ---------------- çµè¡¨ 3 å° ---------------- |
| | | (7, @tenant, 'ELECTRIC', 'PROVIDER', '712606021272', |
| | | '270946', 'äºæ¥¼æ»çµè¡¨', 'äºæ¥¼æ»çµè¡¨', 'çµè¡¨', |
| | | 'äºæ¥¼æ»çµè¡¨', 0, 'VERIFIED', 1, |
| | | 1, NULL, NULL, '2026-11-04', NULL, 1, NOW(3), NOW(3)), |
| | | (8, @tenant, 'ELECTRIC', 'PROVIDER', '712606021277', |
| | | '270949', '污水çµè¡¨', '污水çµè¡¨', 'çµè¡¨', |
| | | '污水çµè¡¨', 0, 'VERIFIED', 1, |
| | | 1, NULL, NULL, '2026-11-04', NULL, 1, NOW(3), NOW(3)), |
| | | (9, @tenant, 'ELECTRIC', 'PROVIDER', '712606021273', |
| | | '270951', '䏿¥¼æ»çµè¡¨', '䏿¥¼æ»çµè¡¨', 'çµè¡¨', |
| | | '䏿¥¼æ»çµè¡¨', 0, 'VERIFIED', 1, |
| | | 1, NULL, NULL, '2026-11-04', NULL, 1, NOW(3), NOW(3)); |
| | | |
| | | -- ============================================================ |
| | | -- äºãæ°è¡¨æ¼ç¤ºè®¾å¤ï¼å¯éï¼ |
| | | -- 说æï¼è¿ 5 å°æ°è¡¨æªå¨é社äºç»è®°ï¼æâæå·¥æè¡¨â建档并æ è®° simulated=1ï¼ |
| | | -- æ¯å¤© 08:00 ç忥ä½ä¸ä¼ä¸ºå®ä»¬çæå½å¤©ç模æè¡¨ç ä¸ç¨éï¼ä¸å䏿¬¡æ§çå岿°æ®ã |
| | | -- æ¥å
¥ç宿°è¡¨åï¼å 餿¬æ®µçæç设å¤ä¸æ°æ®å³å¯ï¼è§ææ«è¯´æï¼ã |
| | | -- 表å·åèªç°åºè¡¨èº«æ¡ç ï¼is_seed=0ï¼å
许å é¤ï¼ã |
| | | -- ============================================================ |
| | | |
| | | -- 5.1 设å¤ï¼é夿§è¡å
æ¸
çï¼ |
| | | SET @tenant := 208; |
| | | |
| | | DELETE FROM `energy_meter_measurement` WHERE `meter_id` IN (11, 12, 13, 14, 15); |
| | | DELETE FROM `energy_meter_device` WHERE `id` IN (11, 12, 13, 14, 15); |
| | | |
| | | INSERT INTO `energy_meter_device` |
| | | (`id`, `tenant_id`, `meter_type`, `source_type`, `meter_address`, `provider_meter_id`, |
| | | `provider_name`, `display_name`, `provider_area_name`, `location`, `online_status`, `bind_status`, |
| | | `enabled`, `is_seed`, `initial_reading`, `initial_reading_date`, `sync_start_date`, `last_success_at`, |
| | | `create_user`, `create_time`, `update_time`) |
| | | VALUES |
| | | (11, @tenant, 'GAS', 'MANUAL', '862873080705632', NULL, |
| | | NULL, 'çè夿°è¡¨', NULL, 'çèå¤', NULL, 'VERIFIED', |
| | | 1, 0, 0.000, '2026-11-04', '2026-11-04', NULL, |
| | | 1, NOW(3), NOW(3)), |
| | | (12, @tenant, 'GAS', 'MANUAL', '865619085854645', NULL, |
| | | NULL, 'ç
®é
䏿°è¡¨', NULL, 'ç
®é
ä¸', NULL, 'VERIFIED', |
| | | 1, 0, 0.000, '2026-11-04', '2026-11-04', NULL, |
| | | 1, NOW(3), NOW(3)), |
| | | (13, @tenant, 'GAS', 'MANUAL', '862873080702613', NULL, |
| | | NULL, 'ç
®é
åæ°è¡¨', NULL, 'ç
®é
å', NULL, 'VERIFIED', |
| | | 1, 0, 0.000, '2026-11-04', '2026-11-04', NULL, |
| | | 1, NOW(3), NOW(3)), |
| | | (14, @tenant, 'GAS', 'MANUAL', '866960071744294', NULL, |
| | | NULL, 'ç
®é
åæ°è¡¨', NULL, 'ç
®é
å', NULL, 'VERIFIED', |
| | | 1, 0, 0.000, '2026-11-04', '2026-11-04', NULL, |
| | | 1, NOW(3), NOW(3)), |
| | | (15, @tenant, 'GAS', 'MANUAL', '862873080704353', NULL, |
| | | NULL, '䏿¥¼ç
®æ¯èæ°è¡¨', NULL, '䏿¥¼ç
®æ¯è', NULL, 'VERIFIED', |
| | | 1, 0, 0.000, '2026-11-04', '2026-11-04', NULL, |
| | | 1, NOW(3), NOW(3)); |
| | | |
| | | -- 5.2 æ 记为æ¼ç¤ºæ°æ®ï¼æ¯å¤© 08:00 ç忥ä½ä¸ä¼ä¸º simulated=1 ç设å¤çæå½å¤©ç模æè¡¨ç ä¸ç¨éï¼ |
| | | -- ä¸å䏿¬¡æ§çå岿°æ®ï¼éè¦è¡¥æä¸å¤©æ¶è°ç¨ POST /energyMeter/sync/gasSimulate?date=yyyy-MM-dd |
| | | UPDATE `energy_meter_device` SET `simulated` = 1 WHERE `id` IN (11, 12, 13, 14, 15); |
| | | -- 说æï¼æ¥å
¥ç宿°è¡¨åï¼æ§è¡ä¸é¢ä¸¤å¥å³å¯æ¸
æè¿ 5 å°æ¼ç¤ºè®¾å¤åå
¶æ°æ®ï¼ |
| | | -- DELETE FROM `energy_meter_measurement` WHERE `meter_id` IN (11, 12, 13, 14, 15); |
| | | -- DELETE FROM `energy_meter_device` WHERE `id` IN (11, 12, 13, 14, 15); |
| | |
| | | IGNORE_TABLES.add("product_model"); |
| | | IGNORE_TABLES.add("ai_chat_session"); |
| | | IGNORE_TABLES.add("product"); |
| | | IGNORE_TABLES.add("energy_meter_device"); |
| | | IGNORE_TABLES.add("energy_meter_measurement"); |
| | | IGNORE_TABLES.add("energy_meter_sync_run"); |
| | | IGNORE_TABLES.add("energy_meter_sync_task"); |
| | | IGNORE_TABLES.add("energy_meter_sync_checkpoint"); |
| | | |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.config; |
| | | |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; |
| | | |
| | | import java.util.concurrent.ThreadPoolExecutor; |
| | | |
| | | /** |
| | | * æ°´çµè¡¨åæ¥çº¿ç¨æ± ï¼ä»»å¡æ± éå¶ç¬¬ä¸æ¹å¹¶åï¼ç¼ææ± é¿å
å䏿¹æ¬¡é»å¡ä»»å¡æ§è¡ã |
| | | */ |
| | | @Configuration |
| | | public class EnergyMeterExecutorConfig { |
| | | |
| | | @Bean(name = "energyMeterSyncExecutor") |
| | | public ThreadPoolTaskExecutor energyMeterSyncExecutor(EnergyMeterProperties properties) { |
| | | int concurrency = Math.max(1, properties.getConcurrency()); |
| | | ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); |
| | | executor.setCorePoolSize(concurrency); |
| | | executor.setMaxPoolSize(concurrency); |
| | | executor.setQueueCapacity(5000); |
| | | executor.setKeepAliveSeconds(60); |
| | | executor.setThreadNamePrefix("energy-meter-task-"); |
| | | executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); |
| | | executor.setWaitForTasksToCompleteOnShutdown(true); |
| | | executor.setAwaitTerminationSeconds(30); |
| | | return executor; |
| | | } |
| | | |
| | | @Bean(name = "energyMeterRunExecutor") |
| | | public ThreadPoolTaskExecutor energyMeterRunExecutor() { |
| | | ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); |
| | | executor.setCorePoolSize(2); |
| | | executor.setMaxPoolSize(4); |
| | | executor.setQueueCapacity(500); |
| | | executor.setKeepAliveSeconds(60); |
| | | executor.setThreadNamePrefix("energy-meter-run-"); |
| | | executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); |
| | | executor.setWaitForTasksToCompleteOnShutdown(true); |
| | | executor.setAwaitTerminationSeconds(30); |
| | | return executor; |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.config; |
| | | |
| | | import lombok.Data; |
| | | import org.springframework.boot.context.properties.ConfigurationProperties; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | /** |
| | | * æ°´çµè¡¨æ¥å
¥é
ç½®ã |
| | | * |
| | | * <p>ææç åªä»ç¯å¢åéæå®å
¨é
置读åï¼ç¦æ¢åå
¥æºç ãåç«¯ä¸æ°æ®åºä¸å¡è¡¨ã</p> |
| | | */ |
| | | @Data |
| | | @Component |
| | | @ConfigurationProperties(prefix = "energy-meter") |
| | | public class EnergyMeterProperties { |
| | | |
| | | /** ç¬¬ä¸æ¹ä¾åºåé
ç½®ã */ |
| | | private Provider provider = new Provider(); |
| | | |
| | | /** æ¯å¤©èªå¨åæ¥æ¶åæ¥ç天æ°ï¼å«æ¨å¤©ï¼ã */ |
| | | private int lookbackDays = 3; |
| | | |
| | | /** åå²è¡¥éå个åççæå¤§èªç¶æ¥ã */ |
| | | private int maxShardDays = 30; |
| | | |
| | | /** ç¤ºå¼æ¥å£å个åççæå¤§èªç¶æ¥ï¼éç¤¾äº GetWaterRawData éå¶æ¥è¯¢è·¨åº¦ä¸è¶
è¿ 15 天ã */ |
| | | private int maxReadingShardDays = 15; |
| | | |
| | | /** ç¬¬ä¸æ¹è¯·æ±æå¤§å¹¶åæ°ã */ |
| | | private int concurrency = 3; |
| | | |
| | | /** å¤±è´¥ä»»å¡æå¤§å°è¯æ¬¡æ°ã */ |
| | | private int maxAttempts = 3; |
| | | |
| | | /** RUNNING ä»»å¡è¶
æ¶éå¼ï¼åéï¼ï¼è¶
æ¶åè¿å
¥éè¯ã */ |
| | | private int runningTimeoutMinutes = 30; |
| | | |
| | | /** æ¯å¦å¯ç¨åå§ç¤ºå¼ä»»å¡ï¼æ°´è¡¨å页è½åæªç¡®è®¤æ¶å¯å
³éï¼ã */ |
| | | private boolean rawReadingEnabled = true; |
| | | |
| | | /** æ¯å¦æ³¨å Quartz ä½ä¸ã */ |
| | | private boolean schedulerEnabled = true; |
| | | |
| | | /** æ¯å¤©åæ¥ Cronï¼åºå®å京æ¶é´ 08:00ã */ |
| | | private String syncCron = "0 0 8 * * ?"; |
| | | |
| | | /** æ¢å¤ä»»å¡ Cronï¼æ¯ 10 åéã */ |
| | | private String recoveryCron = "0 0/10 * * * ?"; |
| | | |
| | | /** ç»å®æ¶é»è®¤è¡¥éèµ·ç¹ï¼ä¸ä¸èªç¶å¹´ 1 æ 1 æ¥ã */ |
| | | private boolean backfillFromLastYear = true; |
| | | |
| | | @Data |
| | | public static class Provider { |
| | | |
| | | /** æ£å¼ç¯å¢åºç¡å°åï¼é¨ç½²å须确认 HTTPS æå®å
¨ä»£çæ¹æ¡ã */ |
| | | private String baseUrl = "http://nhapi.yunjichaobiao.com/WebApi"; |
| | | |
| | | /** ç¬¬ä¸æ¹ææç ï¼åªå
许éè¿ç¯å¢åéæ³¨å
¥ã */ |
| | | private String apiKey = ""; |
| | | |
| | | /** æ¼ç¤ºæ°æ®æ¨¡å¼ï¼æªé
ç½®ææç æ¶èªå¨å¼å¯ï¼ä»
卿¬å°èè°ä½¿ç¨ã */ |
| | | private boolean mockEnabled = false; |
| | | |
| | | /** ä¸¤æ¬¡ç¬¬ä¸æ¹è¯·æ±ä¹é´çæå°é´éï¼æ¯«ç§ï¼ï¼ç¨äºè§é¿ä¾åºåéæµï¼429ï¼ã */ |
| | | private long minIntervalMs = 500; |
| | | |
| | | private int connectTimeoutSeconds = 5; |
| | | |
| | | private int readTimeoutSeconds = 30; |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.constant; |
| | | |
| | | import java.time.ZoneId; |
| | | |
| | | /** |
| | | * è½èè¡¨ï¼æ°´è¡¨/çµè¡¨/æ°è¡¨ï¼æ¥å
¥æ¨¡å常éã |
| | | * |
| | | * <p>ææä¸å¡æ¥æåæ Asia/Shanghai 计ç®ï¼ä¸æå¡å¨é»è®¤æ¶åºæ å
³ã</p> |
| | | */ |
| | | public final class EnergyMeterConstants { |
| | | |
| | | private EnergyMeterConstants() { |
| | | } |
| | | |
| | | public static final ZoneId ZONE = ZoneId.of("Asia/Shanghai"); |
| | | |
| | | /* ---------------- è½æºç±»å ---------------- */ |
| | | public static final String TYPE_WATER = "WATER"; |
| | | public static final String TYPE_ELECTRIC = "ELECTRIC"; |
| | | public static final String TYPE_GAS = "GAS"; |
| | | |
| | | /* ---------------- æ°æ®æ¥æº ---------------- */ |
| | | /** ç¬¬ä¸æ¹æ¥å£æ¥å
¥ï¼ç±å®æ¶ä»»å¡/æå¨æ¥è¡¨è½åºã */ |
| | | public static final String SOURCE_TYPE_PROVIDER = "PROVIDER"; |
| | | /** æå·¥æè¡¨ï¼ç±ç¨æ·å¨è¡¨å
·å°è´¦ä¸å½å
¥è¡¨ç ï¼ç¨éææå·®è®¡ç®ã */ |
| | | public static final String SOURCE_TYPE_MANUAL = "MANUAL"; |
| | | /** æå·¥æè¡¨æ°æ®å¨éé表ä¸çæ¥æºæ è¯ã */ |
| | | public static final String SOURCE_MANUAL = "MANUAL"; |
| | | |
| | | /* ---------------- ææ ç¼ç ---------------- */ |
| | | public static final String METRIC_WATER_USAGE = "WATER_USAGE"; |
| | | public static final String METRIC_WATER_READING = "WATER_READING"; |
| | | public static final String METRIC_ELECTRIC_USAGE = "ELECTRIC_USAGE"; |
| | | public static final String METRIC_ELECTRIC_READING = "ELECTRIC_READING"; |
| | | public static final String METRIC_ELECTRIC_COST = "ELECTRIC_COST"; |
| | | public static final String METRIC_GAS_USAGE = "GAS_USAGE"; |
| | | public static final String METRIC_GAS_READING = "GAS_READING"; |
| | | |
| | | /* ---------------- ç²åº¦ ---------------- */ |
| | | public static final String GRANULARITY_DAY = "D"; |
| | | public static final String GRANULARITY_MONTH = "M"; |
| | | public static final String GRANULARITY_YEAR = "Y"; |
| | | public static final String GRANULARITY_POINT = "POINT"; |
| | | |
| | | /* ---------------- åä½ ---------------- */ |
| | | public static final String UNIT_WATER = "m3"; |
| | | public static final String UNIT_ELECTRIC = "kWh"; |
| | | public static final String UNIT_GAS = "m3"; |
| | | public static final String UNIT_COST = "CNY"; |
| | | |
| | | /* ---------------- ç¬¬ä¸æ¹æ¥å£æ è¯ ---------------- */ |
| | | public static final String SOURCE_GET_USE_WATER = "GetUseWater"; |
| | | public static final String SOURCE_GET_WATER_RAW = "GetWaterRawData"; |
| | | public static final String SOURCE_FROZEN_ELECTRICITY = "FrozenElectricity"; |
| | | public static final String SOURCE_ELECTRIC_QUANTITY = "ElectricQuantity"; |
| | | public static final String SOURCE_GAS_USE = "GetGasUseData"; |
| | | public static final String SOURCE_GAS_RAW = "GetGasRawData"; |
| | | |
| | | /* ---------------- ç»å®ä¸å¯ç¨ ---------------- */ |
| | | public static final String BIND_VERIFIED = "VERIFIED"; |
| | | public static final String BIND_INVALID = "INVALID"; |
| | | |
| | | /* ---------------- æ¹æ¬¡ç±»å ---------------- */ |
| | | public static final String RUN_SCHEDULED = "SCHEDULED"; |
| | | public static final String RUN_MANUAL = "MANUAL"; |
| | | public static final String RUN_BACKFILL = "BACKFILL"; |
| | | |
| | | /* ---------------- æ¹æ¬¡ç¶æ ---------------- */ |
| | | public static final String RUN_PENDING = "PENDING"; |
| | | public static final String RUN_RUNNING = "RUNNING"; |
| | | public static final String RUN_SUCCESS = "SUCCESS"; |
| | | public static final String RUN_PARTIAL = "PARTIAL"; |
| | | public static final String RUN_FAILED = "FAILED"; |
| | | |
| | | /* ---------------- ä»»å¡ç¶æ ---------------- */ |
| | | public static final String TASK_PENDING = "PENDING"; |
| | | public static final String TASK_RUNNING = "RUNNING"; |
| | | public static final String TASK_SUCCESS = "SUCCESS"; |
| | | public static final String TASK_EMPTY = "EMPTY"; |
| | | public static final String TASK_RETRY = "RETRY"; |
| | | public static final String TASK_FAILED = "FAILED"; |
| | | |
| | | /* ---------------- éè¯¯ç±»å« ---------------- */ |
| | | public static final String ERROR_UPSTREAM = "UPSTREAM_ERROR"; |
| | | public static final String ERROR_TIMEOUT = "UPSTREAM_TIMEOUT"; |
| | | public static final String ERROR_PARSE = "PARSE_ERROR"; |
| | | public static final String ERROR_PAGE_INCOMPLETE = "PAGE_INCOMPLETE"; |
| | | public static final String ERROR_ADDRESS_MISMATCH = "ADDRESS_MISMATCH"; |
| | | |
| | | /** èªå¨æ¹æ¬¡ run_key åç¼ã */ |
| | | public static final String AUTO_RUN_KEY_PREFIX = "AUTO:"; |
| | | |
| | | /** éè¯é´éï¼åéï¼ï¼ä¸æ 对åºç¬¬å 次失败ã */ |
| | | public static final int[] RETRY_DELAY_MINUTES = {1, 5, 15}; |
| | | |
| | | /** ä¸ä¸ªè®¾å¤æå¤æ¯æçè¡¥é跨度ï¼èªç¶æ¥ï¼ï¼è¶
åºæ¶æåçæåã */ |
| | | public static final int MAX_RANGE_DAYS = 366 * 3; |
| | | |
| | | public static boolean isWater(String meterType) { |
| | | return TYPE_WATER.equalsIgnoreCase(meterType); |
| | | } |
| | | |
| | | public static boolean isElectric(String meterType) { |
| | | return TYPE_ELECTRIC.equalsIgnoreCase(meterType); |
| | | } |
| | | |
| | | public static boolean isGas(String meterType) { |
| | | return TYPE_GAS.equalsIgnoreCase(meterType); |
| | | } |
| | | |
| | | public static boolean isManual(String sourceType) { |
| | | return SOURCE_TYPE_MANUAL.equalsIgnoreCase(sourceType); |
| | | } |
| | | |
| | | /** |
| | | * æ¯å¦å±äºèªå¨ééï¼ç¬¬ä¸æ¹æ¥å
¥ï¼æç±ç³»ç»æ¯æ¥èªå¨çææ°æ®ç模æè¡¨ï¼å¦è¸æ±½è¡¨æ¼ç¤ºè®¾å¤ï¼ã |
| | | * |
| | | * <p>模æè¡¨ç source_type 仿¯ MANUALï¼ä¸åä¸ç¬¬ä¸æ¹æ¥è¡¨ï¼ï¼ä½ä¸å¡ä¸æèªå¨ééå±ç¤ºä¸ç»è®¡ã</p> |
| | | */ |
| | | public static boolean isAutoCollect(String sourceType, Integer simulated) { |
| | | return SOURCE_TYPE_PROVIDER.equalsIgnoreCase(sourceType) || Integer.valueOf(1).equals(simulated); |
| | | } |
| | | |
| | | public static boolean isSimulated(Integer simulated) { |
| | | return Integer.valueOf(1).equals(simulated); |
| | | } |
| | | |
| | | /** è§èåè½æºç±»åï¼æªç¥ç±»åè¿å nullï¼ç±è°ç¨æ¹æåºä¸å¡å¼å¸¸ã */ |
| | | public static String canonicalType(String meterType) { |
| | | String type = meterType == null ? null : meterType.trim(); |
| | | if (TYPE_WATER.equalsIgnoreCase(type)) { |
| | | return TYPE_WATER; |
| | | } |
| | | if (TYPE_ELECTRIC.equalsIgnoreCase(type)) { |
| | | return TYPE_ELECTRIC; |
| | | } |
| | | if (TYPE_GAS.equalsIgnoreCase(type)) { |
| | | return TYPE_GAS; |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | public static String typeName(String meterType) { |
| | | if (isWater(meterType)) { |
| | | return "水表"; |
| | | } |
| | | if (isGas(meterType)) { |
| | | return "æ°è¡¨"; |
| | | } |
| | | if (isElectric(meterType)) { |
| | | return "çµè¡¨"; |
| | | } |
| | | return meterType; |
| | | } |
| | | |
| | | public static String usageMetric(String meterType) { |
| | | if (isWater(meterType)) { |
| | | return METRIC_WATER_USAGE; |
| | | } |
| | | if (isGas(meterType)) { |
| | | return METRIC_GAS_USAGE; |
| | | } |
| | | return METRIC_ELECTRIC_USAGE; |
| | | } |
| | | |
| | | public static String readingMetric(String meterType) { |
| | | if (isWater(meterType)) { |
| | | return METRIC_WATER_READING; |
| | | } |
| | | if (isGas(meterType)) { |
| | | return METRIC_GAS_READING; |
| | | } |
| | | return METRIC_ELECTRIC_READING; |
| | | } |
| | | |
| | | public static String unit(String meterType) { |
| | | if (isWater(meterType)) { |
| | | return UNIT_WATER; |
| | | } |
| | | if (isGas(meterType)) { |
| | | return UNIT_GAS; |
| | | } |
| | | return UNIT_ELECTRIC; |
| | | } |
| | | |
| | | /** æé´ç¨éçæ¥æºæ è¯ã */ |
| | | public static String usageSource(String meterType) { |
| | | if (isWater(meterType)) { |
| | | return SOURCE_GET_USE_WATER; |
| | | } |
| | | if (isGas(meterType)) { |
| | | return SOURCE_GAS_USE; |
| | | } |
| | | // çµè¡¨ç¨éå ElectricQuantity çæ£åæåçµéï¼FrozenElectricity ç TotalKwh å¯è½æä¸º null |
| | | return SOURCE_ELECTRIC_QUANTITY; |
| | | } |
| | | |
| | | /** æ¶ç¹ç¤ºå¼çæ¥æºæ è¯ã */ |
| | | public static String readingSource(String meterType) { |
| | | if (isWater(meterType)) { |
| | | return SOURCE_GET_WATER_RAW; |
| | | } |
| | | if (isGas(meterType)) { |
| | | return SOURCE_GAS_RAW; |
| | | } |
| | | return SOURCE_FROZEN_ELECTRICITY; |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.controller; |
| | | |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.ruoyi.common.exception.ServiceException; |
| | | import com.ruoyi.common.utils.StringUtils; |
| | | import com.ruoyi.energymeter.dto.EnergyMeterDeviceQuery; |
| | | import com.ruoyi.energymeter.dto.MeterBindRequest; |
| | | import com.ruoyi.energymeter.dto.MeterCollectRequest; |
| | | import com.ruoyi.energymeter.dto.MeterManualBindRequest; |
| | | import com.ruoyi.energymeter.dto.MeterReadingRequest; |
| | | import com.ruoyi.energymeter.dto.MeterUpdateRequest; |
| | | import com.ruoyi.energymeter.dto.MeterVerifyRequest; |
| | | import com.ruoyi.energymeter.pojo.EnergyMeterDevice; |
| | | import com.ruoyi.energymeter.pojo.EnergyMeterMeasurement; |
| | | import com.ruoyi.energymeter.service.EnergyMeterDeviceService; |
| | | import com.ruoyi.energymeter.service.EnergyMeterDemoService; |
| | | import com.ruoyi.energymeter.service.EnergyMeterStatService; |
| | | import com.ruoyi.energymeter.service.EnergyMeterSyncService; |
| | | import com.ruoyi.energymeter.service.ElectricMeterDashboardService; |
| | | import com.ruoyi.energymeter.util.EnergyMeterSupport; |
| | | import com.ruoyi.framework.aspectj.lang.annotation.Log; |
| | | import com.ruoyi.framework.aspectj.lang.enums.BusinessType; |
| | | import com.ruoyi.framework.web.controller.BaseController; |
| | | import com.ruoyi.framework.web.domain.AjaxResult; |
| | | import io.swagger.v3.oas.annotations.Operation; |
| | | import io.swagger.v3.oas.annotations.tags.Tag; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.PathVariable; |
| | | import org.springframework.web.bind.annotation.PostMapping; |
| | | import org.springframework.web.bind.annotation.PutMapping; |
| | | import org.springframework.web.bind.annotation.RequestBody; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RequestParam; |
| | | import org.springframework.web.bind.annotation.DeleteMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | import java.time.LocalDate; |
| | | import java.util.ArrayList; |
| | | import java.util.LinkedHashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * æ°´çµè¡¨æ¥å
¥ä¸æ¥è¡¨æ¥å£ã |
| | | * |
| | | * <p>å端åªè°ç¨æ¬ç³»ç»å端ï¼ç¬¬ä¸æ¹ææç ä¸ä¼ä¸åå°æµè§å¨ã</p> |
| | | */ |
| | | @RestController |
| | | @Tag(name = "æ°´çµè¡¨çæµ") |
| | | @RequestMapping("/energyMeter") |
| | | @RequiredArgsConstructor |
| | | public class EnergyMeterController extends BaseController { |
| | | |
| | | private final EnergyMeterDeviceService deviceService; |
| | | private final EnergyMeterSyncService syncService; |
| | | private final EnergyMeterStatService statService; |
| | | private final EnergyMeterDemoService demoService; |
| | | private final ElectricMeterDashboardService electricDashboardService; |
| | | |
| | | @GetMapping("/devices") |
| | | @Operation(summary = "设å¤å表-å页æ¥è¯¢") |
| | | @Log(title = "æ°´çµè¡¨çæµ-设å¤å表", businessType = BusinessType.OTHER) |
| | | public AjaxResult devices(Page<EnergyMeterDevice> page, EnergyMeterDeviceQuery query) { |
| | | IPage<EnergyMeterDevice> result = deviceService.pageDevices(page, query); |
| | | return AjaxResult.success(result); |
| | | } |
| | | |
| | | @GetMapping("/devices/options") |
| | | @Operation(summary = "设å¤ä¸æé项") |
| | | public AjaxResult deviceOptions(@RequestParam(required = false) String meterType) { |
| | | return AjaxResult.success(deviceService.listDeviceOptions(meterType)); |
| | | } |
| | | |
| | | @PostMapping("/devices/verify") |
| | | @Operation(summary = "éªè¯å¹¶è¯»åç¬¬ä¸æ¹æ¡£æ¡") |
| | | @Log(title = "æ°´çµè¡¨çæµ-æ¡£æ¡éªè¯", businessType = BusinessType.OTHER) |
| | | public AjaxResult verify(@RequestBody MeterVerifyRequest request) { |
| | | return AjaxResult.success(deviceService.verifyArchive(request.getMeterType(), request.getMeterAddress())); |
| | | } |
| | | |
| | | @PostMapping("/devices") |
| | | @Operation(summary = "æ°å¢æ¬å°ç»å®") |
| | | @Log(title = "æ°´çµè¡¨çæµ-æ°å¢ç»å®", businessType = BusinessType.INSERT) |
| | | public AjaxResult add(@RequestBody MeterBindRequest request) { |
| | | return AjaxResult.success(deviceService.bind(request)); |
| | | } |
| | | |
| | | @PutMapping("/devices/{id}") |
| | | @Operation(summary = "ä¿®æ¹è®¾å¤æ¬å°å段/å¯åç¨") |
| | | @Log(title = "表å
·å°è´¦-ä¿®æ¹è®¾å¤", businessType = BusinessType.UPDATE) |
| | | public AjaxResult update(@PathVariable Long id, @RequestBody MeterUpdateRequest request) { |
| | | return AjaxResult.success(deviceService.updateLocal(id, request)); |
| | | } |
| | | |
| | | @PostMapping("/devices/manual") |
| | | @Operation(summary = "æ°å¢æå·¥æè¡¨è®¾å¤ï¼æ°´è¡¨/çµè¡¨/æ°è¡¨ï¼") |
| | | @Log(title = "表å
·å°è´¦-æ°å¢æå·¥æè¡¨è®¾å¤", businessType = BusinessType.INSERT) |
| | | public AjaxResult addManual(@RequestBody MeterManualBindRequest request) { |
| | | return AjaxResult.success(deviceService.addManual(request)); |
| | | } |
| | | |
| | | @DeleteMapping("/devices/{id}") |
| | | @Operation(summary = "å é¤è®¾å¤ï¼åå§å设å¤ä¸ç¬¬ä¸æ¹æ¥å
¥è®¾å¤ä¸å
许å é¤ï¼") |
| | | @Log(title = "表å
·å°è´¦-å é¤è®¾å¤", businessType = BusinessType.DELETE) |
| | | public AjaxResult remove(@PathVariable Long id) { |
| | | deviceService.removeDevice(id); |
| | | return AjaxResult.success(); |
| | | } |
| | | |
| | | @GetMapping("/devices/{id}/readings") |
| | | @Operation(summary = "æå·¥æè¡¨è®°å½å页") |
| | | public AjaxResult readings(@PathVariable Long id, |
| | | @RequestParam(defaultValue = "1") long current, |
| | | @RequestParam(defaultValue = "20") long size) { |
| | | return AjaxResult.success(deviceService.pageReadings(id, current, size)); |
| | | } |
| | | |
| | | @PostMapping("/devices/{id}/readings") |
| | | @Operation(summary = "å½å
¥æå·¥æè¡¨è¡¨ç ") |
| | | @Log(title = "表å
·å°è´¦-æå·¥å½è¡¨", businessType = BusinessType.INSERT) |
| | | public AjaxResult addReading(@PathVariable Long id, @RequestBody MeterReadingRequest request) { |
| | | return AjaxResult.success(deviceService.addReading(id, request)); |
| | | } |
| | | |
| | | @DeleteMapping("/devices/{id}/readings/{readingId}") |
| | | @Operation(summary = "å 餿工æè¡¨è®°å½") |
| | | @Log(title = "表å
·å°è´¦-å é¤æè¡¨è®°å½", businessType = BusinessType.DELETE) |
| | | public AjaxResult removeReading(@PathVariable Long id, @PathVariable Long readingId) { |
| | | deviceService.removeReading(id, readingId); |
| | | return AjaxResult.success(); |
| | | } |
| | | |
| | | @PostMapping("/devices/{id}/collect") |
| | | @Operation(summary = "åå°è®¾å¤æå¨æ¥è¡¨") |
| | | @Log(title = "æ°´çµè¡¨çæµ-æå¨æ¥è¡¨", businessType = BusinessType.OTHER) |
| | | public AjaxResult collect(@PathVariable Long id, |
| | | @RequestBody(required = false) MeterCollectRequest request) { |
| | | LocalDate start = request == null ? null : request.getStartDate(); |
| | | LocalDate end = request == null ? null : request.getEndDate(); |
| | | Boolean includeReadings = request == null ? null : request.getIncludeReadings(); |
| | | Long runId = syncService.triggerManual(List.of(id), start, end, includeReadings); |
| | | return AjaxResult.success(runResult(runId)); |
| | | } |
| | | |
| | | @PostMapping("/devices/collect") |
| | | @Operation(summary = "æ¹éæå¨æ¥è¡¨") |
| | | @Log(title = "æ°´çµè¡¨çæµ-æ¹éæ¥è¡¨", businessType = BusinessType.OTHER) |
| | | public AjaxResult collectBatch(@RequestBody MeterCollectRequest request) { |
| | | List<Long> meterIds = new ArrayList<>(); |
| | | if (request.getMeterIds() != null) { |
| | | meterIds.addAll(request.getMeterIds()); |
| | | } |
| | | if (request.getMeterId() != null && !meterIds.contains(request.getMeterId())) { |
| | | meterIds.add(request.getMeterId()); |
| | | } |
| | | Long runId = syncService.triggerManual(meterIds, request.getStartDate(), request.getEndDate(), |
| | | request.getIncludeReadings()); |
| | | return AjaxResult.success(runResult(runId)); |
| | | } |
| | | |
| | | @GetMapping("/devices/{id}/measurements") |
| | | @Operation(summary = "设å¤è¯»æ°/ç¨éæç»") |
| | | public AjaxResult measurements(@PathVariable Long id, |
| | | @RequestParam(required = false) String metricCode, |
| | | @RequestParam(required = false) String granularity, |
| | | @RequestParam(required = false) String start, |
| | | @RequestParam(required = false) String end, |
| | | @RequestParam(defaultValue = "1") long current, |
| | | @RequestParam(defaultValue = "20") long size) { |
| | | IPage<EnergyMeterMeasurement> page = statService.pageMeasurements(id, metricCode, granularity, |
| | | parseDate(start), parseDate(end), current, size); |
| | | return AjaxResult.success(page); |
| | | } |
| | | |
| | | @GetMapping("/overview") |
| | | @Operation(summary = "ç¨è½æ¦è§") |
| | | public AjaxResult overview(@RequestParam(defaultValue = "WATER") String meterType, |
| | | @RequestParam(required = false) Long meterId, |
| | | @RequestParam(required = false) String month, |
| | | @RequestParam(required = false) Integer year) { |
| | | return AjaxResult.success(statService.overview(meterType, meterId, month, year)); |
| | | } |
| | | |
| | | @GetMapping("/electric/dashboard") |
| | | @Operation(summary = "çµè¡¨å®æ¶çæ¿ï¼ä»æ¥15åéæ²çº¿ä¸çµè½è´¨é") |
| | | public AjaxResult electricDashboard(@RequestParam(required = false) Long meterId, |
| | | @RequestParam(defaultValue = "0") Integer weekOffset) { |
| | | return AjaxResult.success(electricDashboardService.dashboard(meterId, weekOffset)); |
| | | } |
| | | |
| | | @PostMapping("/sync/trigger") |
| | | @Operation(summary = "æå¨è§¦å䏿¬¡æ¯æ¥åæ¥ï¼æéç¨ï¼") |
| | | @Log(title = "æ°´çµè¡¨çæµ-触å忥", businessType = BusinessType.OTHER) |
| | | public AjaxResult triggerDailySync() { |
| | | return AjaxResult.success(runResult(syncService.triggerScheduledSync())); |
| | | } |
| | | |
| | | @PostMapping("/sync/recover") |
| | | @Operation(summary = "æå¨è§¦å䏿¬¡éè¯/è¶
æ¶æ¢å¤ï¼æéç¨ï¼") |
| | | @Log(title = "æ°´çµè¡¨çæµ-è§¦åæ¢å¤", businessType = BusinessType.OTHER) |
| | | public AjaxResult recoverSync() { |
| | | Map<String, Object> data = new LinkedHashMap<>(); |
| | | data.put("handled", syncService.recoverDueTasks()); |
| | | return AjaxResult.success(data); |
| | | } |
| | | |
| | | @GetMapping("/providerStatus") |
| | | @Operation(summary = "ç¬¬ä¸æ¹æ¥å
¥æ¨¡å¼") |
| | | public AjaxResult providerStatus() { |
| | | Map<String, Object> data = new LinkedHashMap<>(); |
| | | data.put("mockMode", deviceService.mockMode()); |
| | | return AjaxResult.success(data); |
| | | } |
| | | |
| | | @PostMapping("/sync/gasSimulate") |
| | | @Operation(summary = "çææ°è¡¨æ¼ç¤ºæ°æ®ï¼æå¤©ï¼é»è®¤ä»å¤©ï¼åä¸å¤©é夿§è¡ä¸ä¼éå¤åå
¥ï¼") |
| | | @Log(title = "表å
·å°è´¦-æ°è¡¨æ¼ç¤ºæ°æ®", businessType = BusinessType.OTHER) |
| | | public AjaxResult gasSimulate(@RequestParam(required = false) String date) { |
| | | LocalDate day = StringUtils.isBlank(date) ? EnergyMeterSupport.today() : parseDate(date); |
| | | Map<String, Object> data = new LinkedHashMap<>(); |
| | | data.put("date", day.toString()); |
| | | data.put("generated", demoService.generateGasDemo(day)); |
| | | return AjaxResult.success(data); |
| | | } |
| | | |
| | | private Map<String, Object> runResult(Long runId) { |
| | | Map<String, Object> data = new LinkedHashMap<>(); |
| | | data.put("runId", runId); |
| | | return data; |
| | | } |
| | | |
| | | private LocalDate parseDate(String value) { |
| | | if (StringUtils.isBlank(value)) { |
| | | return null; |
| | | } |
| | | try { |
| | | return LocalDate.parse(value.trim()); |
| | | } catch (Exception e) { |
| | | throw new ServiceException("æ¥ææ ¼å¼åºä¸º yyyy-MM-dd"); |
| | | } |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.controller; |
| | | |
| | | import com.ruoyi.framework.web.domain.AjaxResult; |
| | | import com.ruoyi.energymeter.service.EnergyMonitorService; |
| | | import com.ruoyi.energymeter.vo.EnergyCollectionVO; |
| | | import com.ruoyi.energymeter.vo.EnergyRealtimeVO; |
| | | import com.ruoyi.energymeter.vo.EnergyReportVO; |
| | | import io.swagger.v3.oas.annotations.Operation; |
| | | import io.swagger.v3.oas.annotations.tags.Tag; |
| | | import jakarta.servlet.http.HttpServletResponse; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.apache.poi.ss.usermodel.BorderStyle; |
| | | import org.apache.poi.ss.usermodel.Cell; |
| | | import org.apache.poi.ss.usermodel.CellStyle; |
| | | import org.apache.poi.ss.usermodel.FillPatternType; |
| | | import org.apache.poi.ss.usermodel.Font; |
| | | import org.apache.poi.ss.usermodel.HorizontalAlignment; |
| | | import org.apache.poi.ss.usermodel.IndexedColors; |
| | | import org.apache.poi.ss.usermodel.Row; |
| | | import org.apache.poi.ss.usermodel.Sheet; |
| | | import org.apache.poi.ss.usermodel.VerticalAlignment; |
| | | import org.apache.poi.ss.usermodel.Workbook; |
| | | import org.apache.poi.xssf.usermodel.XSSFWorkbook; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RequestMethod; |
| | | import org.springframework.web.bind.annotation.RequestParam; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | import java.io.IOException; |
| | | import java.math.BigDecimal; |
| | | import java.net.URLEncoder; |
| | | import java.nio.charset.StandardCharsets; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * è½èæ°æ®ééã宿¶çæ§ä¸ç»è®¡æ¥è¡¨æ¥å£ã |
| | | * |
| | | * <p>èååºå®å¨å端路ç±ï¼ä¸åæ°æ®åºèåãä¸é
è§è²æéï¼ææç»å½ç¨æ·å¯è§ã</p> |
| | | */ |
| | | @RestController |
| | | @Tag(name = "è½èçæ§ä¸ç»è®¡") |
| | | @RequestMapping("/energyMeter") |
| | | @RequiredArgsConstructor |
| | | public class EnergyMonitorController { |
| | | |
| | | private final EnergyMonitorService monitorService; |
| | | |
| | | @GetMapping("/collection/overview") |
| | | @Operation(summary = "è½èæ°æ®é鿦è§ï¼ä¸ç±»ä»è´¨æ¥å
¥è®¾å¤ãå½éè¿åº¦ä¸æè¿æ¹æ¬¡") |
| | | public AjaxResult collectionOverview() { |
| | | EnergyCollectionVO vo = monitorService.collection(); |
| | | return AjaxResult.success(vo); |
| | | } |
| | | |
| | | @GetMapping("/realtime/overview") |
| | | @Operation(summary = "è½è宿¶çæ§ï¼ä¸ç±»ä»è´¨ææ°ç¨éãè¶å¿ä¸çµè¡¨å®æ¶æ²çº¿") |
| | | public AjaxResult realtimeOverview( |
| | | @RequestParam(required = false) Long meterId) { |
| | | EnergyRealtimeVO vo = monitorService.realtime(meterId); |
| | | return AjaxResult.success(vo); |
| | | } |
| | | |
| | | @GetMapping("/report/summary") |
| | | @Operation(summary = "è½èç»è®¡åæï¼ææ¥/æãæä»è´¨/è®¾å¤æ±æ»") |
| | | public AjaxResult reportSummary( |
| | | @RequestParam(required = false) String startDate, |
| | | @RequestParam(required = false) String endDate, |
| | | @RequestParam(defaultValue = "DAY") String granularity, |
| | | @RequestParam(defaultValue = "ALL") String meterType, |
| | | @RequestParam(defaultValue = "MEDIUM") String dimension) { |
| | | EnergyReportVO vo = monitorService.report(startDate, endDate, granularity, meterType, dimension); |
| | | return AjaxResult.success(vo); |
| | | } |
| | | |
| | | @RequestMapping(value = "/report/export", method = {RequestMethod.GET, RequestMethod.POST}) |
| | | @Operation(summary = "è½èç»è®¡æ¥è¡¨å¯¼åº Excel") |
| | | public void reportExport(@RequestParam(required = false) String startDate, |
| | | @RequestParam(required = false) String endDate, |
| | | @RequestParam(defaultValue = "DAY") String granularity, |
| | | @RequestParam(defaultValue = "ALL") String meterType, |
| | | HttpServletResponse response) throws IOException { |
| | | EnergyReportVO report = monitorService.report(startDate, endDate, granularity, meterType, "MEDIUM"); |
| | | String fileName = URLEncoder.encode("è½èç»è®¡æ¥è¡¨_" + report.getStart() + "_" + report.getEnd() + ".xlsx", |
| | | StandardCharsets.UTF_8).replace("+", "%20"); |
| | | response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); |
| | | response.setCharacterEncoding("utf-8"); |
| | | response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\""); |
| | | response.setHeader("Access-Control-Expose-Headers", "Content-Disposition"); |
| | | try (Workbook workbook = new XSSFWorkbook()) { |
| | | writeMediumSheet(workbook, report); |
| | | writeDeviceSheet(workbook, report); |
| | | workbook.write(response.getOutputStream()); |
| | | } |
| | | } |
| | | |
| | | /* ------------------------------------------------------------------ */ |
| | | /* Excel */ |
| | | /* ------------------------------------------------------------------ */ |
| | | |
| | | private void writeMediumSheet(Workbook workbook, EnergyReportVO report) { |
| | | Sheet sheet = workbook.createSheet("ä»è´¨æ±æ»"); |
| | | CellStyle headStyle = headStyle(workbook); |
| | | CellStyle numberStyle = numberStyle(workbook); |
| | | CellStyle textStyle = textStyle(workbook); |
| | | |
| | | String[] headers = {"ç»è®¡å¨æ", "水表ç¨é(m³)", "çµè¡¨ç¨é(度)", "è¸æ±½è¡¨ç¨é(m³)"}; |
| | | Row head = sheet.createRow(0); |
| | | for (int i = 0; i < headers.length; i++) { |
| | | Cell cell = head.createCell(i); |
| | | cell.setCellValue(headers[i]); |
| | | cell.setCellStyle(headStyle); |
| | | } |
| | | |
| | | int rowIndex = 1; |
| | | for (EnergyReportVO.PeriodRow row : report.getRows()) { |
| | | Row dataRow = sheet.createRow(rowIndex++); |
| | | dataRow.createCell(0).setCellValue(row.getPeriod()); |
| | | dataRow.getCell(0).setCellStyle(textStyle); |
| | | writeNumber(dataRow, 1, row.getWater(), numberStyle); |
| | | writeNumber(dataRow, 2, row.getElectric(), numberStyle); |
| | | writeNumber(dataRow, 3, row.getGas(), numberStyle); |
| | | } |
| | | Row totalRow = sheet.createRow(rowIndex); |
| | | Cell totalLabel = totalRow.createCell(0); |
| | | totalLabel.setCellValue("å计"); |
| | | totalLabel.setCellStyle(headStyle); |
| | | for (EnergyReportVO.MediumTotal total : report.getTotals()) { |
| | | int column = columnOf(total.getMeterType()); |
| | | if (column > 0) { |
| | | writeNumber(totalRow, column, total.getTotal(), numberStyle); |
| | | } |
| | | } |
| | | sheet.setColumnWidth(0, 18 * 256); |
| | | for (int i = 1; i <= 3; i++) { |
| | | sheet.setColumnWidth(i, 20 * 256); |
| | | } |
| | | sheet.createFreezePane(0, 1); |
| | | sheet.setAutoFilter(new org.apache.poi.ss.util.CellRangeAddress(0, Math.max(0, rowIndex - 1), 0, 3)); |
| | | } |
| | | |
| | | private void writeDeviceSheet(Workbook workbook, EnergyReportVO report) { |
| | | Sheet sheet = workbook.createSheet("è®¾å¤æç»"); |
| | | CellStyle headStyle = headStyle(workbook); |
| | | CellStyle numberStyle = numberStyle(workbook); |
| | | CellStyle textStyle = textStyle(workbook); |
| | | |
| | | String[] headers = {"设å¤åç§°", "表å·", "ä»è´¨", "ééæ¹å¼", "æé´ç¨é", "åä½", "å ä»è´¨æ¯ä¾(%)"}; |
| | | Row head = sheet.createRow(0); |
| | | for (int i = 0; i < headers.length; i++) { |
| | | Cell cell = head.createCell(i); |
| | | cell.setCellValue(headers[i]); |
| | | cell.setCellStyle(headStyle); |
| | | } |
| | | |
| | | int rowIndex = 1; |
| | | for (EnergyReportVO.DeviceRow row : report.getDevices()) { |
| | | Row dataRow = sheet.createRow(rowIndex++); |
| | | createText(dataRow, 0, row.getMeterName(), textStyle); |
| | | createText(dataRow, 1, row.getMeterAddress(), textStyle); |
| | | createText(dataRow, 2, row.getMeterTypeName(), textStyle); |
| | | createText(dataRow, 3, row.getSourceTypeName(), textStyle); |
| | | writeNumber(dataRow, 4, row.getTotal(), numberStyle); |
| | | createText(dataRow, 5, excelUnit(row.getUnit()), textStyle); |
| | | writeNumber(dataRow, 6, row.getShare(), numberStyle); |
| | | } |
| | | sheet.setColumnWidth(0, 24 * 256); |
| | | sheet.setColumnWidth(1, 22 * 256); |
| | | for (int i = 2; i <= 6; i++) { |
| | | sheet.setColumnWidth(i, 14 * 256); |
| | | } |
| | | sheet.createFreezePane(0, 1); |
| | | sheet.setAutoFilter(new org.apache.poi.ss.util.CellRangeAddress(0, Math.max(0, rowIndex - 1), 0, 6)); |
| | | } |
| | | |
| | | private int columnOf(String meterType) { |
| | | if ("WATER".equals(meterType)) { |
| | | return 1; |
| | | } |
| | | if ("ELECTRIC".equals(meterType)) { |
| | | return 2; |
| | | } |
| | | if ("GAS".equals(meterType)) { |
| | | return 3; |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | /** çé¢ä¸æ¥è¡¨ç»ä¸ç¨ã度ãï¼åºå±ä»æ kWh åå¨ã */ |
| | | private String excelUnit(String unit) { |
| | | if ("kWh".equals(unit)) { |
| | | return "度"; |
| | | } |
| | | if ("m3".equals(unit)) { |
| | | return "m³"; |
| | | } |
| | | return unit; |
| | | } |
| | | |
| | | private void createText(Row row, int column, String value, CellStyle style) { |
| | | Cell cell = row.createCell(column); |
| | | cell.setCellValue(value == null ? "" : value); |
| | | cell.setCellStyle(style); |
| | | } |
| | | |
| | | private void writeNumber(Row row, int column, BigDecimal value, CellStyle style) { |
| | | Cell cell = row.createCell(column); |
| | | if (value != null) { |
| | | cell.setCellValue(value.doubleValue()); |
| | | } |
| | | cell.setCellStyle(style); |
| | | } |
| | | |
| | | private CellStyle headStyle(Workbook workbook) { |
| | | CellStyle style = baseStyle(workbook); |
| | | style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); |
| | | style.setFillPattern(FillPatternType.SOLID_FOREGROUND); |
| | | style.setAlignment(HorizontalAlignment.CENTER); |
| | | Font font = workbook.createFont(); |
| | | font.setBold(true); |
| | | style.setFont(font); |
| | | return style; |
| | | } |
| | | |
| | | private CellStyle textStyle(Workbook workbook) { |
| | | CellStyle style = baseStyle(workbook); |
| | | style.setAlignment(HorizontalAlignment.LEFT); |
| | | return style; |
| | | } |
| | | |
| | | private CellStyle numberStyle(Workbook workbook) { |
| | | CellStyle style = baseStyle(workbook); |
| | | style.setAlignment(HorizontalAlignment.RIGHT); |
| | | style.setDataFormat(workbook.createDataFormat().getFormat("#,##0.000")); |
| | | return style; |
| | | } |
| | | |
| | | private CellStyle baseStyle(Workbook workbook) { |
| | | CellStyle style = workbook.createCellStyle(); |
| | | style.setBorderTop(BorderStyle.THIN); |
| | | style.setBorderBottom(BorderStyle.THIN); |
| | | style.setBorderLeft(BorderStyle.THIN); |
| | | style.setBorderRight(BorderStyle.THIN); |
| | | style.setVerticalAlignment(VerticalAlignment.CENTER); |
| | | return style; |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.dto; |
| | | |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serializable; |
| | | import java.math.BigDecimal; |
| | | |
| | | /** |
| | | * èåæ¥è¯¢ï¼ææ¥ç¨éã |
| | | */ |
| | | @Data |
| | | public class DailyUsageRow implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | private String day; |
| | | |
| | | private BigDecimal total; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.dto; |
| | | |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serializable; |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * å·²ééæ°æ®çæ¶é´èå´ã |
| | | */ |
| | | @Data |
| | | public class DataRangeRow implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | private LocalDateTime minTime; |
| | | |
| | | private LocalDateTime maxTime; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.dto; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serializable; |
| | | |
| | | /** |
| | | * 设å¤å表ç鿡件ã |
| | | */ |
| | | @Data |
| | | @Schema(description = "设å¤å表çé") |
| | | public class EnergyMeterDeviceQuery implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | @Schema(description = "è½æºç±»å WATER/ELECTRIC/GAS") |
| | | private String meterType; |
| | | |
| | | @Schema(description = "æ°æ®æ¥æº PROVIDERç¬¬ä¸æ¹æ¥å
¥/MANUALæå·¥æè¡¨") |
| | | private String sourceType; |
| | | |
| | | @Schema(description = "æ¯å¦æ¼ç¤ºèªå¨çæ 1æ¯ 0å¦") |
| | | private Integer simulated; |
| | | |
| | | @Schema(description = "ééæ¹å¼ AUTOèªå¨éé / MANUALæå¨æè¡¨") |
| | | private String collectionMode; |
| | | |
| | | @Schema(description = "åç§°æéä¿¡å°åå
³é®å") |
| | | private String keyword; |
| | | |
| | | @Schema(description = "éä¿¡å°å精确å¹é
") |
| | | private String meterAddress; |
| | | |
| | | @Schema(description = "å¯åç¨ 1/0") |
| | | private Integer enabled; |
| | | |
| | | @Schema(description = "ç»å®ç¶æ VERIFIED/INVALID") |
| | | private String bindStatus; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.dto; |
| | | |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serializable; |
| | | |
| | | /** |
| | | * ç¬¬ä¸æ¹è¡¨è®¡æ¡£æ¡ï¼åªä¿çæ¬ç³»ç»éè¦çåæ®µï¼ç»ä¸å
å«ç¬¬ä¸æ¹ Passwordï¼ã |
| | | */ |
| | | @Data |
| | | public class MeterArchive implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | /** è½æºç±»åã */ |
| | | private String meterType; |
| | | |
| | | /** éä¿¡å°åï¼ç¬¬ä¸æ¹è¿ååå¼ã */ |
| | | private String meterAddress; |
| | | |
| | | /** ç¬¬ä¸æ¹è®¾å¤IDã */ |
| | | private String providerMeterId; |
| | | |
| | | /** ç¬¬ä¸æ¹è®¾å¤åç§°ã */ |
| | | private String providerName; |
| | | |
| | | /** ç¬¬ä¸æ¹åºåIDã */ |
| | | private Long areaId; |
| | | |
| | | /** ç¬¬ä¸æ¹åºååç§°ã */ |
| | | private String areaName; |
| | | |
| | | /** å¨çº¿ç¶æï¼1å¨çº¿ 0离线 nullæªç¥ã */ |
| | | private Integer onlineStatus; |
| | | |
| | | /** ç¬¬ä¸æ¹æ»è¡¨IDã */ |
| | | private String parentProviderId; |
| | | |
| | | /** ç¬¬ä¸æ¹åå§ç¶æææ¬ï¼ä»
ç¨äºå±ç¤ºã */ |
| | | private String stateText; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.dto; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serializable; |
| | | |
| | | /** |
| | | * æ°å¢æ¬å°ç»å®è¯·æ±ã |
| | | */ |
| | | @Data |
| | | @Schema(description = "æ°å¢ç»å®è¯·æ±") |
| | | public class MeterBindRequest implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | @Schema(description = "è½æºç±»å WATER/ELECTRIC", requiredMode = Schema.RequiredMode.REQUIRED) |
| | | private String meterType; |
| | | |
| | | @Schema(description = "ç¬¬ä¸æ¹éä¿¡å°å", requiredMode = Schema.RequiredMode.REQUIRED) |
| | | private String meterAddress; |
| | | |
| | | @Schema(description = "æ¬ç³»ç»æ¾ç¤ºåç§°ï¼ä¸ºç©ºæ¶ä½¿ç¨ç¬¬ä¸æ¹åç§°") |
| | | private String displayName; |
| | | |
| | | @Schema(description = "å®è£
ä½ç½®") |
| | | private String location; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.dto; |
| | | |
| | | import com.fasterxml.jackson.annotation.JsonFormat; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serializable; |
| | | import java.time.LocalDate; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * æå¨æ¥è¡¨è¯·æ±ï¼å¯æå®åå°ææ¹é设å¤ï¼èµ·æ¢æ¥æåå
å«ã |
| | | */ |
| | | @Data |
| | | @Schema(description = "æå¨æ¥è¡¨è¯·æ±") |
| | | public class MeterCollectRequest implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | @Schema(description = "åå°è®¾å¤ID") |
| | | private Long meterId; |
| | | |
| | | @Schema(description = "æ¹é设å¤IDå表") |
| | | private List<Long> meterIds; |
| | | |
| | | @Schema(description = "å¼å§æ¥æï¼å«ï¼") |
| | | @JsonFormat(pattern = "yyyy-MM-dd") |
| | | private LocalDate startDate; |
| | | |
| | | @Schema(description = "ç»ææ¥æï¼å«ï¼") |
| | | @JsonFormat(pattern = "yyyy-MM-dd") |
| | | private LocalDate endDate; |
| | | |
| | | @Schema(description = "æ¯å¦å
嫿¶ç¹ç¤ºå¼ä»»å¡ï¼é»è®¤ true") |
| | | private Boolean includeReadings; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.dto; |
| | | |
| | | import com.fasterxml.jackson.annotation.JsonFormat; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serializable; |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDate; |
| | | |
| | | /** |
| | | * æ°å¢æå·¥æè¡¨è®¾å¤è¯·æ±ï¼æ°´è¡¨/çµè¡¨/æ°è¡¨åå¯ï¼ã |
| | | */ |
| | | @Data |
| | | @Schema(description = "æ°å¢æå·¥æè¡¨è®¾å¤è¯·æ±") |
| | | public class MeterManualBindRequest implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | @Schema(description = "è½æºç±»å WATER/ELECTRIC/GAS", requiredMode = Schema.RequiredMode.REQUIRED) |
| | | private String meterType; |
| | | |
| | | @Schema(description = "表å·ï¼éä¿¡å°åï¼ï¼æå符串ä¿åï¼ä¿çå导é¶", requiredMode = Schema.RequiredMode.REQUIRED) |
| | | private String meterAddress; |
| | | |
| | | @Schema(description = "æ¬ç³»ç»æ¾ç¤ºåç§°") |
| | | private String displayName; |
| | | |
| | | @Schema(description = "å®è£
ä½ç½®") |
| | | private String location; |
| | | |
| | | @Schema(description = "èµ·å§è¡¨ç ", requiredMode = Schema.RequiredMode.REQUIRED) |
| | | private BigDecimal initialReading; |
| | | |
| | | @Schema(description = "èµ·å§è¡¨ç æ¥æï¼é»è®¤ä»å¤©") |
| | | @JsonFormat(pattern = "yyyy-MM-dd") |
| | | private LocalDate initialReadingDate; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.dto; |
| | | |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serializable; |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * ç¬¬ä¸æ¹ 15 åéç²åº¦çµéæ°æ®ç¹ã |
| | | * |
| | | * <p>active / reactive æ¯è¿ä¸æ¶é´çå
ççµéï¼kWh / kvarhï¼ï¼ç¨äºç»å¶ 15 åéæ±ç¶å¾ï¼ |
| | | * activeReading / reactiveReading æ¯æ¶ç¹ç´¯è®¡è¡¨ç ï¼åªç¨äºææ¥ï¼ä¸å䏿±åã</p> |
| | | */ |
| | | @Data |
| | | public class MeterQuarterPoint implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | /** æ¶é´çç»ææ¶é´ï¼ä¾å¦ 2026-11-04 17:45ã */ |
| | | private LocalDateTime time; |
| | | |
| | | /** æ£åæåçµéï¼æ¬æ¶é´çï¼ã */ |
| | | private BigDecimal active; |
| | | |
| | | /** æ£åæ åçµéï¼æ¬æ¶é´çï¼ã */ |
| | | private BigDecimal reactive; |
| | | |
| | | /** æ£åæåæ»è¡¨ç ã */ |
| | | private BigDecimal activeReading; |
| | | |
| | | /** æ£åæ åæ»è¡¨ç ã */ |
| | | private BigDecimal reactiveReading; |
| | | |
| | | /** ç¬¬ä¸æ¹è¿åçéä¿¡å°åã */ |
| | | private String address; |
| | | |
| | | /** åå§æ¶é´ææ¬ï¼ä¾¿äºææ¥ã */ |
| | | private String rawTime; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.dto; |
| | | |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serializable; |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * ç¬¬ä¸æ¹æ¶ç¹ç¤ºå¼æ°æ®ç¹ã |
| | | */ |
| | | @Data |
| | | public class MeterReadingPoint implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | /** ç¤ºå¼æ¶ç¹ã */ |
| | | private LocalDateTime time; |
| | | |
| | | /** 累计表ç ã */ |
| | | private BigDecimal reading; |
| | | |
| | | /** ç¬¬ä¸æ¹åæ¶è¿åçæé´ç¨éï¼ä»
ç¨äºå£å¾æ ¸å¯¹ã */ |
| | | private BigDecimal usage; |
| | | |
| | | /** ç¬¬ä¸æ¹è¿åçéä¿¡å°åã */ |
| | | private String address; |
| | | |
| | | /** åå§æ¶é´ææ¬ã */ |
| | | private String rawTime; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.dto; |
| | | |
| | | import com.fasterxml.jackson.annotation.JsonFormat; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serializable; |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDate; |
| | | |
| | | /** |
| | | * æå·¥å½è¡¨è¯·æ±ã |
| | | */ |
| | | @Data |
| | | @Schema(description = "æå·¥å½è¡¨è¯·æ±") |
| | | public class MeterReadingRequest implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | @Schema(description = "æè¡¨æ¥æï¼ä¸å¡æ¥æï¼", requiredMode = Schema.RequiredMode.REQUIRED) |
| | | @JsonFormat(pattern = "yyyy-MM-dd") |
| | | private LocalDate readingDate; |
| | | |
| | | @Schema(description = "æ¬æ¬¡è¡¨ç ", requiredMode = Schema.RequiredMode.REQUIRED) |
| | | private BigDecimal readingValue; |
| | | |
| | | @Schema(description = "æè¡¨å¤æ³¨") |
| | | private String remark; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.dto; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serializable; |
| | | |
| | | /** |
| | | * ä¿®æ¹æ¬å°å±ç¤ºå段请æ±ï¼ä¸ä¿®æ¹éä¿¡å°åä¸ç¬¬ä¸æ¹æ¡£æ¡å段ã |
| | | */ |
| | | @Data |
| | | @Schema(description = "ä¿®æ¹è®¾å¤æ¬å°å段请æ±") |
| | | public class MeterUpdateRequest implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | private String displayName; |
| | | |
| | | private String location; |
| | | |
| | | @Schema(description = "å¯åç¨ï¼1å¯ç¨ 0åç¨ï¼ä¸ºç©ºè¡¨ç¤ºä¸ä¿®æ¹") |
| | | private Integer enabled; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.dto; |
| | | |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serializable; |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * ç¬¬ä¸æ¹æé´ç¨éæ°æ®ç¹ã |
| | | */ |
| | | @Data |
| | | public class MeterUsagePoint implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | /** ä¸å¡æ¶é´ï¼æ¥ç¨éå½ä¸ä¸ºå½å¤© 00:00ï¼ã */ |
| | | private LocalDateTime time; |
| | | |
| | | /** æé´ç¨éã */ |
| | | private BigDecimal value; |
| | | |
| | | /** ç¬¬ä¸æ¹è¿åçéä¿¡å°åã */ |
| | | private String address; |
| | | |
| | | /** åå§æ¶é´ææ¬ï¼ä¾¿äºææ¥ã */ |
| | | private String rawTime; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.dto; |
| | | |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serializable; |
| | | import java.math.BigDecimal; |
| | | |
| | | /** |
| | | * èåæ¥è¯¢ï¼æè®¾å¤æ±æ»ç¨éã |
| | | */ |
| | | @Data |
| | | public class MeterUsageRow implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | private Long meterId; |
| | | |
| | | private BigDecimal total; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.dto; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serializable; |
| | | |
| | | /** |
| | | * éªè¯å¹¶è¯»åç¬¬ä¸æ¹æ¡£æ¡ç请æ±ã |
| | | */ |
| | | @Data |
| | | @Schema(description = "æ¡£æ¡éªè¯è¯·æ±") |
| | | public class MeterVerifyRequest implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | @Schema(description = "è½æºç±»å WATER/ELECTRIC", requiredMode = Schema.RequiredMode.REQUIRED) |
| | | private String meterType; |
| | | |
| | | @Schema(description = "ç¬¬ä¸æ¹éä¿¡å°å", requiredMode = Schema.RequiredMode.REQUIRED) |
| | | private String meterAddress; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.dto; |
| | | |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serializable; |
| | | import java.math.BigDecimal; |
| | | |
| | | /** |
| | | * èåæ¥è¯¢ï¼ææç¨éã |
| | | */ |
| | | @Data |
| | | public class MonthlyUsageRow implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | private String month; |
| | | |
| | | private BigDecimal total; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.dto; |
| | | |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serializable; |
| | | |
| | | /** |
| | | * æ¹æ¬¡å
ä»»å¡ç¶æç»è®¡ã |
| | | */ |
| | | @Data |
| | | public class TaskStatusCount implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | private Integer total; |
| | | |
| | | private Integer success; |
| | | |
| | | private Integer empty; |
| | | |
| | | private Integer failed; |
| | | |
| | | private Integer retry; |
| | | |
| | | private Integer pending; |
| | | |
| | | private Integer running; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.job; |
| | | |
| | | import com.ruoyi.common.utils.spring.SpringUtils; |
| | | import com.ruoyi.energymeter.service.EnergyMeterDemoService; |
| | | import com.ruoyi.energymeter.service.EnergyMeterSyncService; |
| | | import com.ruoyi.energymeter.util.EnergyMeterSupport; |
| | | import org.quartz.DisallowConcurrentExecution; |
| | | import org.quartz.Job; |
| | | import org.quartz.JobExecutionContext; |
| | | import org.quartz.JobExecutionException; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | |
| | | /** |
| | | * æ¯å¤© 08:00ï¼Asia/Shanghaiï¼èªå¨åæ¥ä½ä¸ã |
| | | * |
| | | * <p>ç¦æ¢å¹¶åæ§è¡ï¼éè¿è§¦åæ¶æ FireAndProceed 补触å䏿¬¡ï¼ç¼ºå£ç±è¿åº¦è¡¨éæ¥è¡¥é½ã</p> |
| | | */ |
| | | @DisallowConcurrentExecution |
| | | public class EnergyMeterDailySyncJob implements Job { |
| | | |
| | | private static final Logger log = LoggerFactory.getLogger(EnergyMeterDailySyncJob.class); |
| | | |
| | | @Override |
| | | public void execute(JobExecutionContext context) throws JobExecutionException { |
| | | Exception syncError = null; |
| | | try { |
| | | EnergyMeterSyncService syncService = SpringUtils.getBean(EnergyMeterSyncService.class); |
| | | Long runId = syncService.triggerScheduledSync(); |
| | | log.info("æ°´çµè¡¨ 08:00 èªå¨åæ¥å®æ runId={}", runId); |
| | | } catch (Exception e) { |
| | | syncError = e; |
| | | log.error("æ°´çµè¡¨ 08:00 èªå¨åæ¥å¤±è´¥", e); |
| | | } |
| | | // æ°è¡¨æ¼ç¤ºè®¾å¤ä¸çå®åæ¥äºä¸å½±åï¼å³ä½¿ç¬¬ä¸æ¹åæ¥å¤±è´¥ï¼ä¹ç
§å¸¸çæåä¸å¤©çæ°æ® |
| | | try { |
| | | EnergyMeterDemoService demoService = SpringUtils.getBean(EnergyMeterDemoService.class); |
| | | int generated = demoService.generateGasDemo(EnergyMeterSupport.today().minusDays(1)); |
| | | log.info("æ°è¡¨æ¼ç¤ºæ°æ®çæå®æ è®¾å¤æ°={}", generated); |
| | | } catch (Exception e) { |
| | | log.error("æ°è¡¨æ¼ç¤ºæ°æ®çæå¤±è´¥", e); |
| | | } |
| | | if (syncError != null) { |
| | | throw new JobExecutionException(syncError, false); |
| | | } |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.job; |
| | | |
| | | import com.ruoyi.common.utils.spring.SpringUtils; |
| | | import com.ruoyi.energymeter.service.EnergyMeterSyncService; |
| | | import org.quartz.DisallowConcurrentExecution; |
| | | import org.quartz.Job; |
| | | import org.quartz.JobExecutionContext; |
| | | import org.quartz.JobExecutionException; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | |
| | | /** |
| | | * æ¯ 10 åéæ§è¡ä¸æ¬¡ï¼å¤çå°æéè¯ä»»å¡ä¸è¶
æ¶ RUNNING ä»»å¡ã |
| | | */ |
| | | @DisallowConcurrentExecution |
| | | public class EnergyMeterRecoveryJob implements Job { |
| | | |
| | | private static final Logger log = LoggerFactory.getLogger(EnergyMeterRecoveryJob.class); |
| | | |
| | | @Override |
| | | public void execute(JobExecutionContext context) throws JobExecutionException { |
| | | try { |
| | | EnergyMeterSyncService syncService = SpringUtils.getBean(EnergyMeterSyncService.class); |
| | | int handled = syncService.recoverDueTasks(); |
| | | if (handled > 0) { |
| | | log.info("æ°´çµè¡¨åæ¥æ¢å¤ä½ä¸å®æï¼å¤ç任塿°={}", handled); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("æ°´çµè¡¨åæ¥æ¢å¤ä½ä¸å¤±è´¥", e); |
| | | throw new JobExecutionException(e, false); |
| | | } |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.job; |
| | | |
| | | import com.ruoyi.energymeter.config.EnergyMeterProperties; |
| | | import lombok.RequiredArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.quartz.CronScheduleBuilder; |
| | | import org.quartz.CronTrigger; |
| | | import org.quartz.Job; |
| | | import org.quartz.JobBuilder; |
| | | import org.quartz.JobDetail; |
| | | import org.quartz.JobKey; |
| | | import org.quartz.Scheduler; |
| | | import org.quartz.SchedulerException; |
| | | import org.quartz.Trigger; |
| | | import org.quartz.TriggerBuilder; |
| | | import org.quartz.TriggerKey; |
| | | import org.springframework.boot.ApplicationArguments; |
| | | import org.springframework.boot.ApplicationRunner; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | import java.util.TimeZone; |
| | | |
| | | /** |
| | | * å¯å¨æ¶ä»¥åºå® JobKey/TriggerKey æ³¨åææ´æ°ä¸¤ä¸ª Quartz ä½ä¸ï¼éå¤å¯å¨ä¸ä¼äº§çéå¤è§¦åå¨ã |
| | | */ |
| | | @Slf4j |
| | | @Component |
| | | @RequiredArgsConstructor |
| | | public class EnergyMeterSchedulerRegistrar implements ApplicationRunner { |
| | | |
| | | private static final String GROUP = "energyMeter"; |
| | | private static final String TIME_ZONE = "Asia/Shanghai"; |
| | | |
| | | private final Scheduler scheduler; |
| | | private final EnergyMeterProperties properties; |
| | | |
| | | @Override |
| | | public void run(ApplicationArguments args) { |
| | | if (!properties.isSchedulerEnabled()) { |
| | | log.info("æ°´çµè¡¨å®æ¶ä»»å¡å·²å
³éï¼energy-meter.scheduler-enabled=falseï¼"); |
| | | return; |
| | | } |
| | | try { |
| | | // æ¸
çå·²ä¸çº¿ççµè¡¨æ´ç¹åæ¥ä½ä¸ï¼é¿å
æä¹
å Quartz åå¨éçæ§è§¦åå¨ç»§ç»æå°æ¶è§¦å |
| | | removeIfExists("energyMeterElectricHourlySync", "energyMeterElectricHourlySyncTrigger"); |
| | | register("energyMeterDailySync", "energyMeterDailySyncTrigger", |
| | | EnergyMeterDailySyncJob.class, properties.getSyncCron(), "æ°´çµè¡¨æ¯å¤©08:00èªå¨åæ¥"); |
| | | register("energyMeterRecovery", "energyMeterRecoveryTrigger", |
| | | EnergyMeterRecoveryJob.class, properties.getRecoveryCron(), "æ°´çµè¡¨æ¯10å鿢å¤éè¯"); |
| | | } catch (Exception e) { |
| | | log.error("æ³¨åæ°´çµè¡¨å®æ¶ä»»å¡å¤±è´¥", e); |
| | | } |
| | | } |
| | | |
| | | private void removeIfExists(String jobName, String triggerName) throws SchedulerException { |
| | | TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, GROUP); |
| | | if (scheduler.checkExists(triggerKey)) { |
| | | scheduler.unscheduleJob(triggerKey); |
| | | log.info("已移é¤ä¸çº¿çæ°´çµè¡¨å®æ¶ä»»å¡è§¦åå¨ {}", triggerName); |
| | | } |
| | | JobKey jobKey = JobKey.jobKey(jobName, GROUP); |
| | | if (scheduler.checkExists(jobKey)) { |
| | | scheduler.deleteJob(jobKey); |
| | | log.info("已移é¤ä¸çº¿çæ°´çµè¡¨å®æ¶ä»»å¡ {}", jobName); |
| | | } |
| | | } |
| | | |
| | | private void register(String jobName, String triggerName, Class<? extends Job> jobClass, |
| | | String cron, String description) throws SchedulerException { |
| | | JobKey jobKey = JobKey.jobKey(jobName, GROUP); |
| | | TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, GROUP); |
| | | if (!scheduler.checkExists(jobKey)) { |
| | | JobDetail jobDetail = JobBuilder.newJob(jobClass) |
| | | .withIdentity(jobKey) |
| | | .withDescription(description) |
| | | .storeDurably() |
| | | .requestRecovery() |
| | | .build(); |
| | | Trigger trigger = buildTrigger(triggerKey, jobKey, cron, description); |
| | | scheduler.scheduleJob(jobDetail, trigger); |
| | | log.info("å·²æ³¨åæ°´çµè¡¨å®æ¶ä»»å¡ {}ï¼{}ï¼{}ï¼", jobName, cron, TIME_ZONE); |
| | | return; |
| | | } |
| | | Trigger existing = scheduler.getTrigger(triggerKey); |
| | | boolean sameCron = existing instanceof CronTrigger cronTrigger |
| | | && cron.equals(cronTrigger.getCronExpression()); |
| | | Trigger.TriggerState state = existing == null |
| | | ? Trigger.TriggerState.NONE : scheduler.getTriggerState(triggerKey); |
| | | // çæ¬åçº§åæ§å®ä¾å¯è½ä¸è®¤è¯æ° Job ç±»èæè§¦åå¨ç½®ä¸º ERRORï¼è¿éé建触åå¨ä½¿å
¶æ¢å¤è°åº¦ |
| | | if (!sameCron || state == Trigger.TriggerState.ERROR) { |
| | | Trigger trigger = buildTrigger(triggerKey, jobKey, cron, description); |
| | | if (existing != null) { |
| | | scheduler.unscheduleJob(triggerKey); |
| | | } |
| | | scheduler.scheduleJob(trigger); |
| | | log.info("å·²é建水çµè¡¨å®æ¶ä»»å¡ {} ç触åå¨ï¼cron={}ï¼åç¶æ={}ï¼", jobName, cron, state); |
| | | } else { |
| | | log.info("æ°´çµè¡¨å®æ¶ä»»å¡ {} å·²åå¨ä¸è§åä¸è´ï¼è·³è¿é夿³¨å", jobName); |
| | | } |
| | | } |
| | | |
| | | private Trigger buildTrigger(TriggerKey triggerKey, JobKey jobKey, String cron, String description) { |
| | | return TriggerBuilder.newTrigger() |
| | | .withIdentity(triggerKey) |
| | | .withDescription(description) |
| | | .forJob(jobKey) |
| | | .withSchedule(CronScheduleBuilder.cronSchedule(cron) |
| | | .inTimeZone(TimeZone.getTimeZone(TIME_ZONE)) |
| | | .withMisfireHandlingInstructionFireAndProceed()) |
| | | .build(); |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.mapper; |
| | | |
| | | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
| | | import com.ruoyi.energymeter.pojo.EnergyMeterDevice; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | import org.apache.ibatis.annotations.Param; |
| | | import org.apache.ibatis.annotations.Select; |
| | | import org.apache.ibatis.annotations.Update; |
| | | |
| | | import java.time.LocalDateTime; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * æ°´çµè¡¨ç»å®è®¾å¤ Mapperã |
| | | */ |
| | | @Mapper |
| | | public interface EnergyMeterDeviceMapper extends BaseMapper<EnergyMeterDevice> { |
| | | |
| | | /** |
| | | * æ«æå
¨é¨ç§æ·ä¸å·²å¯ç¨ãå·²éªè¯ãä¸ä¸ºç¬¬ä¸æ¹æ¥å
¥ç设å¤ï¼ç¨äºç³»ç»çº§èªå¨åæ¥ã |
| | | * æå·¥æè¡¨è®¾å¤ç±ç¨æ·å½è¡¨ï¼ä¸åä¸å®æ¶ééã |
| | | */ |
| | | @Select("SELECT * FROM energy_meter_device WHERE enabled = 1 AND bind_status = 'VERIFIED' " |
| | | + "AND source_type = 'PROVIDER' ORDER BY id") |
| | | List<EnergyMeterDevice> selectScannableDevices(); |
| | | |
| | | /** |
| | | * è®°å½ééæåå¹¶æ¸
ç©ºä¸æ¬¡é误ã |
| | | */ |
| | | @Update("UPDATE energy_meter_device SET last_success_at = #{now}, last_error_code = NULL, " |
| | | + "last_error_message = NULL WHERE id = #{id}") |
| | | int markCollectSuccess(@Param("id") Long id, @Param("now") LocalDateTime now); |
| | | |
| | | /** |
| | | * è®°å½éé失败çè±æé误类å«ä¸æè¦ã |
| | | */ |
| | | @Update("UPDATE energy_meter_device SET last_error_code = #{code}, last_error_message = #{message} WHERE id = #{id}") |
| | | int markCollectFailure(@Param("id") Long id, @Param("code") String code, @Param("message") String message); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.mapper; |
| | | |
| | | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
| | | import com.ruoyi.energymeter.dto.DailyUsageRow; |
| | | import com.ruoyi.energymeter.dto.DataRangeRow; |
| | | import com.ruoyi.energymeter.dto.MeterUsageRow; |
| | | import com.ruoyi.energymeter.dto.MonthlyUsageRow; |
| | | import com.ruoyi.energymeter.pojo.EnergyMeterMeasurement; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | import org.apache.ibatis.annotations.Param; |
| | | import org.apache.ibatis.annotations.Select; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | import java.util.Collection; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * æ°´çµè¡¨ééæ°æ® Mapperã |
| | | */ |
| | | @Mapper |
| | | public interface EnergyMeterMeasurementMapper extends BaseMapper<EnergyMeterMeasurement> { |
| | | |
| | | /** |
| | | * ææ¥æ±æ»æé´ç¨éãåªç»è®¡ D ç²åº¦çç¨éææ ï¼ç»ä¸ç´¯å POINT 表ç ã |
| | | */ |
| | | List<DailyUsageRow> sumDailyUsage(@Param("meterIds") Collection<Long> meterIds, |
| | | @Param("metricCode") String metricCode, |
| | | @Param("start") LocalDateTime start, |
| | | @Param("end") LocalDateTime end); |
| | | |
| | | /** |
| | | * æè®¾å¤æ±æ»ä¸æ®µæ¶é´å
çç¨éï¼ç¨äºè®¾å¤å表å±ç¤ºæè¿ä¸å¤©ç¨éã |
| | | */ |
| | | List<MeterUsageRow> sumUsageByMeter(@Param("meterIds") Collection<Long> meterIds, |
| | | @Param("metricCode") String metricCode, |
| | | @Param("start") LocalDateTime start, |
| | | @Param("end") LocalDateTime end); |
| | | |
| | | /** |
| | | * æææ±æ»æé´ç¨éã |
| | | */ |
| | | List<MonthlyUsageRow> sumMonthlyUsage(@Param("meterIds") Collection<Long> meterIds, |
| | | @Param("metricCode") String metricCode, |
| | | @Param("start") LocalDateTime start, |
| | | @Param("end") LocalDateTime end); |
| | | |
| | | /** |
| | | * æ¥è¯¢æå®è®¾å¤ãææ ãç²åº¦å¨æ¶é´åºé´å
å·²åå¨çééç¹ï¼ç¨äºå¹çæ¯å¯¹ã |
| | | */ |
| | | List<EnergyMeterMeasurement> selectExistingPoints(@Param("meterId") Long meterId, |
| | | @Param("metricCode") String metricCode, |
| | | @Param("granularity") String granularity, |
| | | @Param("start") LocalDateTime start, |
| | | @Param("end") LocalDateTime end); |
| | | |
| | | /** |
| | | * æ¹éå¹çåå
¥ï¼å¯ä¸é®å²çªæ¶æ´æ°ææ å¼ä¸ééæ¶é´ã |
| | | */ |
| | | int upsertBatch(@Param("list") List<EnergyMeterMeasurement> list); |
| | | |
| | | /** |
| | | * æ¥è¯¢å·²ééæ°æ®çæ¶é´èå´ã |
| | | */ |
| | | DataRangeRow selectDataRange(@Param("meterIds") Collection<Long> meterIds, |
| | | @Param("metricCode") String metricCode); |
| | | |
| | | /** |
| | | * åºé´å计ã |
| | | */ |
| | | BigDecimal sumTotal(@Param("meterIds") Collection<Long> meterIds, |
| | | @Param("metricCode") String metricCode, |
| | | @Param("start") LocalDateTime start, |
| | | @Param("end") LocalDateTime end); |
| | | |
| | | @Select("SELECT * FROM energy_meter_measurement WHERE meter_id = #{meterId} AND metric_code = #{metricCode} " |
| | | + "ORDER BY measure_time DESC LIMIT 1") |
| | | EnergyMeterMeasurement selectLatestPoint(@Param("meterId") Long meterId, |
| | | @Param("metricCode") String metricCode); |
| | | |
| | | /** |
| | | * æ¥è¯¢æå®æ¶é´ç¹ä¹åæè¿ç䏿¡æ¶ç¹ç¤ºå¼ï¼æå·¥æè¡¨ç¨äºè®¡ç®æå·®ï¼ã |
| | | */ |
| | | @Select("SELECT * FROM energy_meter_measurement WHERE meter_id = #{meterId} AND metric_code = #{metricCode} " |
| | | + "AND granularity = 'POINT' AND measure_time < #{time} ORDER BY measure_time DESC LIMIT 1") |
| | | EnergyMeterMeasurement selectPreviousPoint(@Param("meterId") Long meterId, |
| | | @Param("metricCode") String metricCode, |
| | | @Param("time") LocalDateTime time); |
| | | |
| | | /** |
| | | * æ¥è¯¢æå®æ¶é´ç¹ä¹åæè¿ç䏿¡æ¶ç¹ç¤ºå¼ï¼è¡¥å½/å é¤åéç®ä¸ä¸æç¨éï¼ã |
| | | */ |
| | | @Select("SELECT * FROM energy_meter_measurement WHERE meter_id = #{meterId} AND metric_code = #{metricCode} " |
| | | + "AND granularity = 'POINT' AND measure_time > #{time} ORDER BY measure_time ASC LIMIT 1") |
| | | EnergyMeterMeasurement selectNextPoint(@Param("meterId") Long meterId, |
| | | @Param("metricCode") String metricCode, |
| | | @Param("time") LocalDateTime time); |
| | | |
| | | @Select("SELECT COUNT(DISTINCT DATE(measure_time)) FROM energy_meter_measurement " |
| | | + "WHERE meter_id = #{meterId} AND metric_code = #{metricCode} AND granularity = 'D' " |
| | | + "AND measure_time >= #{start} AND measure_time < #{end}") |
| | | Integer countCollectedDays(@Param("meterId") Long meterId, |
| | | @Param("metricCode") String metricCode, |
| | | @Param("start") LocalDateTime start, |
| | | @Param("end") LocalDateTime end); |
| | | |
| | | /** |
| | | * æå®æé´å
å·²ææ¥ç¨éæ°æ®ç设å¤å°æ°ï¼ç¨äºéé页å±ç¤ºâ仿¥å·²å½éâã |
| | | */ |
| | | Integer countMetersWithUsage(@Param("meterIds") Collection<Long> meterIds, |
| | | @Param("metricCode") String metricCode, |
| | | @Param("start") LocalDateTime start, |
| | | @Param("end") LocalDateTime end); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.mapper; |
| | | |
| | | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
| | | import com.ruoyi.energymeter.pojo.EnergyMeterSyncCheckpoint; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | import org.apache.ibatis.annotations.Param; |
| | | import org.apache.ibatis.annotations.Select; |
| | | |
| | | /** |
| | | * 忥è¿åº¦ Mapperã |
| | | */ |
| | | @Mapper |
| | | public interface EnergyMeterSyncCheckpointMapper extends BaseMapper<EnergyMeterSyncCheckpoint> { |
| | | |
| | | @Select("SELECT * FROM energy_meter_sync_checkpoint WHERE meter_id = #{meterId} " |
| | | + "AND source_api = #{sourceApi} AND granularity = #{granularity} LIMIT 1") |
| | | EnergyMeterSyncCheckpoint selectUnit(@Param("meterId") Long meterId, |
| | | @Param("sourceApi") String sourceApi, |
| | | @Param("granularity") String granularity); |
| | | |
| | | /** |
| | | * å¹çåå
¥è¿åº¦ï¼åªå
许åè¿ï¼ä¸å æè¿å 天忥èåéã |
| | | */ |
| | | int upsert(@Param("cp") EnergyMeterSyncCheckpoint cp); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.mapper; |
| | | |
| | | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
| | | import com.ruoyi.energymeter.pojo.EnergyMeterSyncRun; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | import org.apache.ibatis.annotations.Param; |
| | | import org.apache.ibatis.annotations.Select; |
| | | |
| | | import java.time.LocalDateTime; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * åæ¥æ¹æ¬¡ Mapperã |
| | | */ |
| | | @Mapper |
| | | public interface EnergyMeterSyncRunMapper extends BaseMapper<EnergyMeterSyncRun> { |
| | | |
| | | @Select("SELECT * FROM energy_meter_sync_run WHERE run_key = #{runKey} LIMIT 1") |
| | | EnergyMeterSyncRun selectByRunKey(@Param("runKey") String runKey); |
| | | |
| | | /** |
| | | * æ±æ»æ¹æ¬¡ä»»å¡ç¶æå¹¶ååç»è®¡å段ã |
| | | */ |
| | | int refreshTotals(@Param("runId") Long runId); |
| | | |
| | | /** |
| | | * æ¥è¯¢é¿æ¶é´åå¨ RUNNINGãä½å·²æ²¡æå¾
æ§è¡ä»»å¡çæ¹æ¬¡ï¼ç¨äºå´©æºåå
åºæ±æ»ã |
| | | */ |
| | | @Select("SELECT r.* FROM energy_meter_sync_run r WHERE r.status = 'RUNNING' AND r.create_time < #{deadline} " |
| | | + "AND NOT EXISTS (SELECT 1 FROM energy_meter_sync_task t WHERE t.run_id = r.id " |
| | | + "AND t.status IN ('PENDING', 'RUNNING', 'RETRY')) ORDER BY r.id LIMIT #{limit}") |
| | | List<EnergyMeterSyncRun> selectStuckRuns(@Param("deadline") LocalDateTime deadline, |
| | | @Param("limit") int limit); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.mapper; |
| | | |
| | | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
| | | import com.ruoyi.energymeter.dto.TaskStatusCount; |
| | | import com.ruoyi.energymeter.pojo.EnergyMeterSyncTask; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | import org.apache.ibatis.annotations.Param; |
| | | import org.apache.ibatis.annotations.Update; |
| | | |
| | | import java.time.LocalDateTime; |
| | | import java.util.Collection; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * å设å¤åæ¥ä»»å¡ Mapperã |
| | | */ |
| | | @Mapper |
| | | public interface EnergyMeterSyncTaskMapper extends BaseMapper<EnergyMeterSyncTask> { |
| | | |
| | | /** |
| | | * æå¯ä¸é®å¹çæå
¥ä»»å¡ã |
| | | */ |
| | | int insertIgnore(@Param("task") EnergyMeterSyncTask task); |
| | | |
| | | /** |
| | | * æ¡ä»¶é¢åä»»å¡ï¼åªææç¶æä» PENDING/RETRY æ´æ°ä¸º RUNNING æåçæ§è¡è
æå请æ±ã |
| | | */ |
| | | int claim(@Param("id") Long id, @Param("now") LocalDateTime now); |
| | | |
| | | /** |
| | | * å°æå¾
éè¯ä»»å¡ã |
| | | */ |
| | | List<EnergyMeterSyncTask> selectDueRetry(@Param("now") LocalDateTime now, @Param("limit") int limit); |
| | | |
| | | /** |
| | | * è¶
æ¶ä»å¤äº RUNNING çä»»å¡ã |
| | | */ |
| | | List<EnergyMeterSyncTask> selectStaleRunning(@Param("deadline") LocalDateTime deadline, @Param("limit") int limit); |
| | | |
| | | /** |
| | | * æè¶
æ¶ä»»å¡é置为å¾
éè¯ã |
| | | */ |
| | | int resetToRetry(@Param("id") Long id, |
| | | @Param("now") LocalDateTime now, |
| | | @Param("nextRetryAt") LocalDateTime nextRetryAt, |
| | | @Param("reason") String reason); |
| | | |
| | | List<EnergyMeterSyncTask> selectByRunId(@Param("runId") Long runId); |
| | | |
| | | List<EnergyMeterSyncTask> selectLatestByMeterIds(@Param("meterIds") Collection<Long> meterIds); |
| | | |
| | | TaskStatusCount countByRunId(@Param("runId") Long runId); |
| | | |
| | | /** |
| | | * æ è®°ä»»å¡æå/ç©ºç»æï¼å¹¶æ¸
空é误ä¸éè¯ä¿¡æ¯ã |
| | | */ |
| | | @Update("UPDATE energy_meter_sync_task SET status = #{status}, fetched_count = #{fetched}, " |
| | | + "inserted_count = #{inserted}, updated_count = #{updated}, finished_at = #{now}, " |
| | | + "error_code = NULL, error_message = NULL, next_retry_at = NULL WHERE id = #{id}") |
| | | int markFinished(@Param("id") Long id, |
| | | @Param("status") String status, |
| | | @Param("fetched") int fetched, |
| | | @Param("inserted") int inserted, |
| | | @Param("updated") int updated, |
| | | @Param("now") LocalDateTime now); |
| | | |
| | | /** |
| | | * æ è®°ä»»å¡å¤±è´¥æè½¬å
¥éè¯ã |
| | | */ |
| | | @Update("UPDATE energy_meter_sync_task SET status = #{status}, error_code = #{code}, " |
| | | + "error_message = #{message}, next_retry_at = #{nextRetryAt}, finished_at = #{now} WHERE id = #{id}") |
| | | int markFailed(@Param("id") Long id, |
| | | @Param("status") String status, |
| | | @Param("code") String code, |
| | | @Param("message") String message, |
| | | @Param("nextRetryAt") LocalDateTime nextRetryAt, |
| | | @Param("now") LocalDateTime now); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.pojo; |
| | | |
| | | import com.baomidou.mybatisplus.annotation.FieldFill; |
| | | import com.baomidou.mybatisplus.annotation.IdType; |
| | | import com.baomidou.mybatisplus.annotation.TableField; |
| | | import com.baomidou.mybatisplus.annotation.TableId; |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import com.fasterxml.jackson.annotation.JsonFormat; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serializable; |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * æ°´çµè¡¨æ¬å°ç»å®æ¡£æ¡ã |
| | | */ |
| | | @Data |
| | | @TableName("energy_meter_device") |
| | | @Schema(description = "æ°´çµè¡¨ç»å®è®¾å¤") |
| | | public class EnergyMeterDevice implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | @TableId(value = "id", type = IdType.AUTO) |
| | | private Long id; |
| | | |
| | | @Schema(description = "ç§æ·ID") |
| | | @TableField(fill = FieldFill.INSERT) |
| | | private Long tenantId; |
| | | |
| | | @Schema(description = "è½æºç±»å WATER/ELECTRIC/GAS") |
| | | private String meterType; |
| | | |
| | | @Schema(description = "æ°æ®æ¥æº PROVIDERç¬¬ä¸æ¹æ¥å
¥/MANUALæå·¥æè¡¨") |
| | | private String sourceType; |
| | | |
| | | @Schema(description = "ç¬¬ä¸æ¹éä¿¡å°åæè¡¨å·ï¼ä¿çå导é¶") |
| | | private String meterAddress; |
| | | |
| | | @Schema(description = "ç¬¬ä¸æ¹è®¾å¤ID") |
| | | private String providerMeterId; |
| | | |
| | | @Schema(description = "ç¬¬ä¸æ¹è®¾å¤åç§°") |
| | | private String providerName; |
| | | |
| | | @Schema(description = "æ¬ç³»ç»æ¾ç¤ºåç§°") |
| | | private String displayName; |
| | | |
| | | @Schema(description = "ç¬¬ä¸æ¹åºåID") |
| | | private Long providerAreaId; |
| | | |
| | | @Schema(description = "ç¬¬ä¸æ¹åºååç§°") |
| | | private String providerAreaName; |
| | | |
| | | @Schema(description = "ç¬¬ä¸æ¹æ»è¡¨ID") |
| | | private String parentProviderId; |
| | | |
| | | @Schema(description = "æ¬å°æ»è¡¨ID") |
| | | private Long parentMeterId; |
| | | |
| | | @Schema(description = "å®è£
ä½ç½®") |
| | | private String location; |
| | | |
| | | @Schema(description = "å¨çº¿ç¶æ 1å¨çº¿ 0离线") |
| | | private Integer onlineStatus; |
| | | |
| | | @Schema(description = "ç»å®ç¶æ VERIFIED/INVALID") |
| | | private String bindStatus; |
| | | |
| | | @Schema(description = "æ¯å¦å¯ç¨ 1å¯ç¨ 0åç¨") |
| | | private Integer enabled; |
| | | |
| | | @Schema(description = "æ¯å¦åå§åè®¾å¤ 1æ¯ï¼ç¦æ¢å é¤ï¼0å¦") |
| | | private Integer isSeed; |
| | | |
| | | @Schema(description = "æ¯å¦æ¼ç¤ºæ°æ® 1æ¯ï¼æ¯æ¥åæ¥æ¶çææ¨¡æç¨éï¼0å¦") |
| | | private Integer simulated; |
| | | |
| | | @Schema(description = "æå·¥æè¡¨èµ·å§è¡¨ç ") |
| | | private BigDecimal initialReading; |
| | | |
| | | @Schema(description = "æå·¥æè¡¨èµ·å§è¡¨ç æ¥æ") |
| | | @JsonFormat(pattern = "yyyy-MM-dd") |
| | | private LocalDate initialReadingDate; |
| | | |
| | | @Schema(description = "ææ©éè¦åæ¥çä¸å¡æ¥æ") |
| | | @JsonFormat(pattern = "yyyy-MM-dd") |
| | | private LocalDate syncStartDate; |
| | | |
| | | @Schema(description = "æè¿æåééæ¶é´") |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private LocalDateTime lastSuccessAt; |
| | | |
| | | @Schema(description = "æè¿ééé误类å«") |
| | | private String lastErrorCode; |
| | | |
| | | @Schema(description = "æè¿ééé误æè¦") |
| | | private String lastErrorMessage; |
| | | |
| | | @TableField(fill = FieldFill.INSERT) |
| | | private Long createUser; |
| | | |
| | | @TableField(fill = FieldFill.INSERT) |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private LocalDateTime createTime; |
| | | |
| | | @TableField(fill = FieldFill.INSERT_UPDATE) |
| | | private Long updateUser; |
| | | |
| | | @TableField(fill = FieldFill.INSERT_UPDATE) |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private LocalDateTime updateTime; |
| | | |
| | | /* ---------------- å表å±ç¤ºç¨éæä¹
ååæ®µ ---------------- */ |
| | | |
| | | @Schema(description = "æè¿ä¸æ¬¡ä»»å¡ç¶æ") |
| | | @TableField(exist = false) |
| | | private String lastTaskStatus; |
| | | |
| | | @Schema(description = "æè¿ä¸æ¬¡ä»»å¡æ¶é´") |
| | | @TableField(exist = false) |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private LocalDateTime lastTaskTime; |
| | | |
| | | @Schema(description = "æè¿ä¸å¤©ç¨é") |
| | | @TableField(exist = false) |
| | | private BigDecimal lastDayUsage; |
| | | |
| | | @Schema(description = "ææ°è¡¨ç 读æ°") |
| | | @TableField(exist = false) |
| | | private BigDecimal latestReading; |
| | | |
| | | @Schema(description = "ä¸æè¡¨ç 读æ°") |
| | | @TableField(exist = false) |
| | | private BigDecimal previousReading; |
| | | |
| | | @Schema(description = "æè¿ä¸å¤©ç¨éçä¸å¡æ¥æ") |
| | | @TableField(exist = false) |
| | | @JsonFormat(pattern = "yyyy-MM-dd") |
| | | private LocalDate lastDayUsageDate; |
| | | |
| | | @Schema(description = "ééç¶æè¯´æ") |
| | | @TableField(exist = false) |
| | | private String collectStateText; |
| | | |
| | | @Schema(description = "è½æºç±»å䏿å") |
| | | @TableField(exist = false) |
| | | private String meterTypeName; |
| | | |
| | | @Schema(description = "æ°æ®æ¥æºä¸æå") |
| | | @TableField(exist = false) |
| | | private String sourceTypeName; |
| | | |
| | | @Schema(description = "ææ åä½") |
| | | @TableField(exist = false) |
| | | private String unit; |
| | | |
| | | @Schema(description = "æ¯å¦å
许å é¤") |
| | | @TableField(exist = false) |
| | | private Boolean deletable; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.pojo; |
| | | |
| | | import com.baomidou.mybatisplus.annotation.FieldFill; |
| | | import com.baomidou.mybatisplus.annotation.IdType; |
| | | import com.baomidou.mybatisplus.annotation.TableField; |
| | | import com.baomidou.mybatisplus.annotation.TableId; |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import com.fasterxml.jackson.annotation.JsonFormat; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serializable; |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * æ°´çµè¡¨ç¨éã示å¼ä¸å·²éªè¯è´¹ç¨ã |
| | | */ |
| | | @Data |
| | | @TableName("energy_meter_measurement") |
| | | @Schema(description = "æ°´çµè¡¨ééæ°æ®") |
| | | public class EnergyMeterMeasurement implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | @TableId(value = "id", type = IdType.AUTO) |
| | | private Long id; |
| | | |
| | | @Schema(description = "ç§æ·ID") |
| | | private Long tenantId; |
| | | |
| | | @Schema(description = "æ¬å°è®¾å¤ID") |
| | | private Long meterId; |
| | | |
| | | @Schema(description = "ææ ç¼ç ") |
| | | private String metricCode; |
| | | |
| | | @Schema(description = "ç²åº¦ D/POINT") |
| | | private String granularity; |
| | | |
| | | @Schema(description = "æé´èµ·ç¹æç¤ºå¼æ¶ç¹") |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private LocalDateTime measureTime; |
| | | |
| | | @Schema(description = "ææ å¼") |
| | | private BigDecimal metricValue; |
| | | |
| | | @Schema(description = "åä½") |
| | | private String unit; |
| | | |
| | | @Schema(description = "ç¬¬ä¸æ¹æ¥æºæ¥å£æ è¯") |
| | | private String sourceApi; |
| | | |
| | | @Schema(description = "ç¬¬ä¸æ¹åå§æ¶é´") |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private LocalDateTime sourceRecordTime; |
| | | |
| | | @Schema(description = "ééæ¶é´") |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private LocalDateTime collectedAt; |
| | | |
| | | @Schema(description = "夿³¨ï¼æå·¥æè¡¨è¯´æ") |
| | | private String remark; |
| | | |
| | | @TableField(fill = FieldFill.INSERT) |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private LocalDateTime createTime; |
| | | |
| | | @TableField(fill = FieldFill.INSERT_UPDATE) |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private LocalDateTime updateTime; |
| | | |
| | | /* ---------------- æç»å±ç¤ºç¨éæä¹
ååæ®µ ---------------- */ |
| | | |
| | | @Schema(description = "设å¤åç§°") |
| | | @TableField(exist = false) |
| | | private String meterName; |
| | | |
| | | @Schema(description = "è½æºç±»å") |
| | | @TableField(exist = false) |
| | | private String meterType; |
| | | |
| | | @Schema(description = "éä¿¡å°å") |
| | | @TableField(exist = false) |
| | | private String meterAddress; |
| | | |
| | | @Schema(description = "æ¬æ¡æè¡¨å¯¹åºçæé´ç¨éï¼ä»
æè¡¨è®°å½è¿åï¼") |
| | | @TableField(exist = false) |
| | | private BigDecimal usageValue; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.pojo; |
| | | |
| | | import com.baomidou.mybatisplus.annotation.IdType; |
| | | import com.baomidou.mybatisplus.annotation.TableId; |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import com.fasterxml.jackson.annotation.JsonFormat; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serializable; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * æè®¾å¤ãç¬¬ä¸æ¹æ¥å£ãç²åº¦è®°å½è¿ç»å®æå°çæ¥æã |
| | | */ |
| | | @Data |
| | | @TableName("energy_meter_sync_checkpoint") |
| | | @Schema(description = "æ°´çµè¡¨åæ¥è¿åº¦") |
| | | public class EnergyMeterSyncCheckpoint implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | @TableId(value = "id", type = IdType.AUTO) |
| | | private Long id; |
| | | |
| | | private Long tenantId; |
| | | |
| | | private Long meterId; |
| | | |
| | | private String sourceApi; |
| | | |
| | | private String granularity; |
| | | |
| | | @Schema(description = "è¿ç»å®æå°çä¸å¡æ¥æ") |
| | | @JsonFormat(pattern = "yyyy-MM-dd") |
| | | private LocalDate lastCompleteDate; |
| | | |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private LocalDateTime lastSuccessAt; |
| | | |
| | | private Long lastRunId; |
| | | |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private LocalDateTime createTime; |
| | | |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private LocalDateTime updateTime; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.pojo; |
| | | |
| | | import com.baomidou.mybatisplus.annotation.IdType; |
| | | import com.baomidou.mybatisplus.annotation.TableId; |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import com.fasterxml.jackson.annotation.JsonFormat; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serializable; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * 䏿¬¡èªå¨ãæå¨æåå²è¡¥éçåæ¥æ¹æ¬¡ã |
| | | */ |
| | | @Data |
| | | @TableName("energy_meter_sync_run") |
| | | @Schema(description = "æ°´çµè¡¨åæ¥æ¹æ¬¡") |
| | | public class EnergyMeterSyncRun implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | @TableId(value = "id", type = IdType.AUTO) |
| | | private Long id; |
| | | |
| | | @Schema(description = "æ¹æ¬¡å¯ä¸é®") |
| | | private String runKey; |
| | | |
| | | @Schema(description = "SCHEDULED/MANUAL/BACKFILL") |
| | | private String triggerType; |
| | | |
| | | @Schema(description = "è®¡åæ§è¡æ¥") |
| | | @JsonFormat(pattern = "yyyy-MM-dd") |
| | | private LocalDate scheduleDate; |
| | | |
| | | @Schema(description = "忥å¼å§æ¥æ") |
| | | @JsonFormat(pattern = "yyyy-MM-dd") |
| | | private LocalDate rangeStart; |
| | | |
| | | @Schema(description = "åæ¥ç»ææ¥æ") |
| | | @JsonFormat(pattern = "yyyy-MM-dd") |
| | | private LocalDate rangeEnd; |
| | | |
| | | @Schema(description = "æ¹æ¬¡ç¶æ") |
| | | private String status; |
| | | |
| | | private Integer totalTasks; |
| | | |
| | | private Integer successTasks; |
| | | |
| | | private Integer emptyTasks; |
| | | |
| | | private Integer failedTasks; |
| | | |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private LocalDateTime startedAt; |
| | | |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private LocalDateTime finishedAt; |
| | | |
| | | @Schema(description = "è±æé误æè¦") |
| | | private String errorSummary; |
| | | |
| | | private Long createUser; |
| | | |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private LocalDateTime createTime; |
| | | |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private LocalDateTime updateTime; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.pojo; |
| | | |
| | | import com.baomidou.mybatisplus.annotation.FieldFill; |
| | | import com.baomidou.mybatisplus.annotation.IdType; |
| | | import com.baomidou.mybatisplus.annotation.TableField; |
| | | import com.baomidou.mybatisplus.annotation.TableId; |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import com.fasterxml.jackson.annotation.JsonFormat; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serializable; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * ä¸å°è®¾å¤ãä¸ä¸ªç¬¬ä¸æ¹æ¥å£ãä¸ä¸ªæ¶é´åççæ§è¡ç¶æã |
| | | */ |
| | | @Data |
| | | @TableName("energy_meter_sync_task") |
| | | @Schema(description = "æ°´çµè¡¨åæ¥ä»»å¡") |
| | | public class EnergyMeterSyncTask implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | @TableId(value = "id", type = IdType.AUTO) |
| | | private Long id; |
| | | |
| | | private Long runId; |
| | | |
| | | private Long tenantId; |
| | | |
| | | private Long meterId; |
| | | |
| | | @Schema(description = "ç¬¬ä¸æ¹æ¥å£æ è¯") |
| | | private String sourceApi; |
| | | |
| | | @Schema(description = "ç²åº¦ D/POINT") |
| | | private String granularity; |
| | | |
| | | @JsonFormat(pattern = "yyyy-MM-dd") |
| | | private LocalDate rangeStart; |
| | | |
| | | @JsonFormat(pattern = "yyyy-MM-dd") |
| | | private LocalDate rangeEnd; |
| | | |
| | | @Schema(description = "ä»»å¡ç¶æ") |
| | | private String status; |
| | | |
| | | private Integer attemptCount; |
| | | |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private LocalDateTime nextRetryAt; |
| | | |
| | | private Integer fetchedCount; |
| | | |
| | | private Integer insertedCount; |
| | | |
| | | private Integer updatedCount; |
| | | |
| | | @Schema(description = "è±æé误类å«") |
| | | private String errorCode; |
| | | |
| | | @Schema(description = "è±æé误信æ¯") |
| | | private String errorMessage; |
| | | |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private LocalDateTime startedAt; |
| | | |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private LocalDateTime finishedAt; |
| | | |
| | | @TableField(fill = FieldFill.INSERT) |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private LocalDateTime createTime; |
| | | |
| | | @TableField(fill = FieldFill.INSERT_UPDATE) |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private LocalDateTime updateTime; |
| | | |
| | | /* ---------------- å±ç¤ºç¨éæä¹
ååæ®µ ---------------- */ |
| | | |
| | | @TableField(exist = false) |
| | | private String meterName; |
| | | |
| | | @TableField(exist = false) |
| | | private String meterType; |
| | | |
| | | @TableField(exist = false) |
| | | private String meterAddress; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.provider; |
| | | |
| | | import com.ruoyi.energymeter.dto.MeterArchive; |
| | | import com.ruoyi.energymeter.dto.MeterQuarterPoint; |
| | | import com.ruoyi.energymeter.dto.MeterReadingPoint; |
| | | import com.ruoyi.energymeter.dto.MeterUsagePoint; |
| | | |
| | | import java.time.LocalDate; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * ç¬¬ä¸æ¹è¡¨è®¡æ°æ®æºã |
| | | */ |
| | | public interface MeterProviderClient { |
| | | |
| | | /** |
| | | * æ¥è¯¢å¹¶ä¸¥æ ¼å¹é
䏿¡è¡¨è®¡æ¡£æ¡ï¼å¹é
ä¸å°æ¶æåº NOT_FOUNDã |
| | | */ |
| | | MeterArchive queryArchive(String meterType, String address); |
| | | |
| | | /** |
| | | * æ¥è¯¢æé´æ¥ç¨éã |
| | | * |
| | | * @param providerMeterId ç¬¬ä¸æ¹è®¾å¤IDï¼æ°è¡¨ç¨éæ¥å£è¦æ±ä¼ ID è䏿¯éä¿¡å°å |
| | | */ |
| | | List<MeterUsagePoint> queryDailyUsage(String meterType, String address, String providerMeterId, |
| | | LocalDate start, LocalDate end); |
| | | |
| | | /** |
| | | * æ¥è¯¢æ¶ç¹ç¤ºå¼ã |
| | | */ |
| | | List<MeterReadingPoint> queryReadings(String meterType, String address, String providerMeterId, |
| | | LocalDate start, LocalDate end); |
| | | |
| | | /** |
| | | * æ¥è¯¢ 15 åéç²åº¦çµéï¼å½åä»
çµè¡¨æ¯æï¼æ¥èª ElectricQuantity ç mi15 æ°æ®ï¼ã |
| | | * |
| | | * <p>è¿åçæ¶é´æ¯æ¶é´çç»ææ¶é´ï¼active / reactive 为该æ¶é´çå
ççµéã</p> |
| | | */ |
| | | List<MeterQuarterPoint> queryQuarterUsage(String meterType, String address, String providerMeterId, |
| | | LocalDate start, LocalDate end); |
| | | |
| | | /** |
| | | * æ¯å¦å¤äºæ¼ç¤ºæ°æ®æ¨¡å¼ã |
| | | */ |
| | | boolean mockMode(); |
| | | |
| | | /** |
| | | * æ¯å¦å·²é
ç½®ç¬¬ä¸æ¹ææç ï¼æªé
ç½®ä¸éæ¼ç¤ºæ¨¡å¼æ¶ä¸å
许å建ééä»»å¡ã |
| | | */ |
| | | boolean hasApiKey(); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.provider; |
| | | |
| | | /** |
| | | * ç¬¬ä¸æ¹æ¥å£è°ç¨å¼å¸¸ï¼æºå¸¦å¯å
¥åºçè±æé误类å«ã |
| | | */ |
| | | public class MeterProviderException extends RuntimeException { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | private final String code; |
| | | |
| | | public MeterProviderException(String code, String message) { |
| | | super(message); |
| | | this.code = code; |
| | | } |
| | | |
| | | public MeterProviderException(String code, String message, Throwable cause) { |
| | | super(message, cause); |
| | | this.code = code; |
| | | } |
| | | |
| | | public String getCode() { |
| | | return code; |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.provider; |
| | | |
| | | import cn.hutool.http.HttpException; |
| | | import cn.hutool.http.HttpRequest; |
| | | import cn.hutool.http.HttpResponse; |
| | | import com.alibaba.fastjson2.JSON; |
| | | import com.alibaba.fastjson2.JSONArray; |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import com.ruoyi.common.utils.StringUtils; |
| | | import com.ruoyi.energymeter.config.EnergyMeterProperties; |
| | | import com.ruoyi.energymeter.constant.EnergyMeterConstants; |
| | | import com.ruoyi.energymeter.dto.MeterArchive; |
| | | import com.ruoyi.energymeter.dto.MeterQuarterPoint; |
| | | import com.ruoyi.energymeter.dto.MeterReadingPoint; |
| | | import com.ruoyi.energymeter.dto.MeterUsagePoint; |
| | | import lombok.RequiredArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.math.RoundingMode; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.time.format.DateTimeParseException; |
| | | import java.util.ArrayList; |
| | | import java.util.HashSet; |
| | | import java.util.List; |
| | | import java.util.Objects; |
| | | import java.util.Set; |
| | | |
| | | /** |
| | | * é社äºè½æºçæ§ API 客æ·ç«¯ã |
| | | * |
| | | * <p>çå®è°ç¨ï¼POST application/jsonï¼è¯·æ±å¤´ä¼ API_KEYãææç åªä»é
置读åï¼æ¥å¿ä¸è¾åºææç ä¸ååºåæã</p> |
| | | * <p>æ¼ç¤ºæ¨¡å¼ï¼æªé
ç½®ææç ææ¾å¼å¼å¯ mock æ¶ï¼çæå¯éå¤çæ¬å°æ°æ®ï¼ä»
ç¨äºæ¬å°èè°ä¸é¡µé¢æ¼ç¤ºã</p> |
| | | */ |
| | | @Slf4j |
| | | @Component |
| | | @RequiredArgsConstructor |
| | | public class YunJiChaoBiaoProviderClient implements MeterProviderClient { |
| | | |
| | | private static final String PATH_ELECTRIC_ARCHIVE = "/NH2/AmmeterBasicInfo"; |
| | | private static final String PATH_WATER_ARCHIVE = "/NH2/WatermeterBasicInfo"; |
| | | private static final String PATH_WATER_USAGE = "/NH2/GetUseWater"; |
| | | private static final String PATH_WATER_RAW = "/NH2/GetWaterRawData"; |
| | | private static final String PATH_FROZEN_ELECTRICITY = "/NH2/FrozenElectricity"; |
| | | private static final String PATH_GAS_ARCHIVE = "/NH2/GasmeterBasicInfo"; |
| | | private static final String PATH_GAS_USAGE = "/NH2/GetGasUseData"; |
| | | private static final String PATH_GAS_RAW = "/NH2/GetGasRawData"; |
| | | private static final String PATH_ELECTRIC_QUANTITY = "/NH2/ElectricQuantity"; |
| | | |
| | | /** æ¼ç¤ºè¯»æ°åºåæ¥æä¸åºå表ç ï¼ä¿è¯é夿¥è¯¢ç»æä¸è´ã */ |
| | | private static final LocalDate MOCK_READING_EPOCH = LocalDate.of(2025, 9, 1); |
| | | private static final BigDecimal MOCK_WATER_BASE = BigDecimal.valueOf(1000); |
| | | private static final BigDecimal MOCK_ELECTRIC_BASE = BigDecimal.valueOf(50000); |
| | | |
| | | private static final DateTimeFormatter[] DATE_TIME_FORMATS = new DateTimeFormatter[]{ |
| | | DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"), |
| | | DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"), |
| | | DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"), |
| | | DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss"), |
| | | DateTimeFormatter.ofPattern("yyyy-MM-dd"), |
| | | DateTimeFormatter.ofPattern("yyyy/MM/dd") |
| | | }; |
| | | |
| | | private final EnergyMeterProperties properties; |
| | | |
| | | /** ä¸ä¸æ¬¡è¯·æ±æ¶é´ï¼ç¨äºæ§å¶æå°è¯·æ±é´éï¼è§é¿ä¾åºåéæµã */ |
| | | private long lastRequestAt = 0L; |
| | | |
| | | /** |
| | | * å
¨å±æå°è¯·æ±é´éï¼ä¾åºåå¯¹çæ¶é´å
çè¿ç»è°ç¨ä¼è¿å 429ï¼è¿éä¸²è¡æ§éã |
| | | */ |
| | | private synchronized void throttle(long minIntervalMs) { |
| | | if (minIntervalMs <= 0) { |
| | | return; |
| | | } |
| | | long wait = minIntervalMs - (System.currentTimeMillis() - lastRequestAt); |
| | | if (wait > 0) { |
| | | try { |
| | | Thread.sleep(wait); |
| | | } catch (InterruptedException e) { |
| | | Thread.currentThread().interrupt(); |
| | | } |
| | | } |
| | | lastRequestAt = System.currentTimeMillis(); |
| | | } |
| | | |
| | | @Override |
| | | public boolean mockMode() { |
| | | // åªææ¾å¼å¼å¯ mock æä½¿ç¨æ¼ç¤ºæ°æ®ï¼æªé
ç½®ææç æ¶ç´æ¥æ¥éï¼é¿å
ææ¨¡æå¼å½æçå®ç¨é |
| | | return properties.getProvider().isMockEnabled(); |
| | | } |
| | | |
| | | @Override |
| | | public boolean hasApiKey() { |
| | | return StringUtils.isNotBlank(properties.getProvider().getApiKey()); |
| | | } |
| | | |
| | | @Override |
| | | public MeterArchive queryArchive(String meterType, String address) { |
| | | String trimmed = StringUtils.trim(address); |
| | | if (StringUtils.isBlank(trimmed)) { |
| | | throw new MeterProviderException("INVALID_ADDRESS", "éä¿¡å°åä¸è½ä¸ºç©º"); |
| | | } |
| | | if (mockMode()) { |
| | | return mockArchive(meterType, trimmed); |
| | | } |
| | | boolean water = EnergyMeterConstants.isWater(meterType); |
| | | boolean gas = EnergyMeterConstants.isGas(meterType); |
| | | JSONObject payload = new JSONObject(); |
| | | if (water || gas) { |
| | | payload.put("address", trimmed); |
| | | } else { |
| | | payload.put("meterAddress", trimmed); |
| | | } |
| | | String archivePath = gas ? PATH_GAS_ARCHIVE |
| | | : (water ? PATH_WATER_ARCHIVE : PATH_ELECTRIC_ARCHIVE); |
| | | List<JSONObject> items = callList(archivePath, payload); |
| | | |
| | | JSONObject matched = items.stream() |
| | | .filter(item -> trimmed.equals(StringUtils.trim(firstString(item, "Address", "address")))) |
| | | .findFirst() |
| | | .orElse(null); |
| | | if (matched == null) { |
| | | throw new MeterProviderException("NOT_FOUND", "ç¬¬ä¸æ¹æªæ¾å°è¯¥è¡¨è®¡"); |
| | | } |
| | | MeterArchive archive = new MeterArchive(); |
| | | archive.setMeterType(EnergyMeterConstants.canonicalType(meterType)); |
| | | archive.setMeterAddress(trimmed); |
| | | archive.setProviderMeterId(firstString(matched, "ID", "Id", "id")); |
| | | archive.setProviderName(water || gas |
| | | ? firstString(matched, "Name", "name") |
| | | : firstString(matched, "AmmeterName", "Name", "name")); |
| | | archive.setAreaName(firstString(matched, "AreaName", "areaName")); |
| | | archive.setParentProviderId(firstString(matched, "ParentID", "ParentId", "parentId")); |
| | | archive.setStateText(firstString(matched, "State", "LineState", "OnlineState")); |
| | | archive.setOnlineStatus(parseOnline(water || gas |
| | | ? firstString(matched, "LineState", "State", "OnlineState") |
| | | : firstString(matched, "OnlineState", "State"))); |
| | | Long areaId = firstLong(matched, "AreaID", "AreaId", "areaId"); |
| | | archive.setAreaId(areaId); |
| | | return archive; |
| | | } |
| | | |
| | | @Override |
| | | public List<MeterUsagePoint> queryDailyUsage(String meterType, String address, String providerMeterId, |
| | | LocalDate start, LocalDate end) { |
| | | boolean water = EnergyMeterConstants.isWater(meterType); |
| | | boolean gas = EnergyMeterConstants.isGas(meterType); |
| | | if (mockMode()) { |
| | | return mockUsage(meterType, address, start, end); |
| | | } |
| | | JSONObject payload = new JSONObject(); |
| | | payload.put("dateType", "D"); |
| | | payload.put("startTime", start.toString()); |
| | | payload.put("endTime", end.toString()); |
| | | String path; |
| | | if (water) { |
| | | payload.put("address", address); |
| | | path = PATH_WATER_USAGE; |
| | | } else if (gas) { |
| | | // æ°è¡¨ç¨éæ¥å£æç¬¬ä¸æ¹è®¾å¤IDæ¥è¯¢ï¼ä¸è®¤éä¿¡å°å |
| | | payload.put("gasmeterID", requireMeterId(meterType, providerMeterId)); |
| | | path = PATH_GAS_USAGE; |
| | | } else { |
| | | // çµè¡¨æé´ç¨éç¨ ElectricQuantity ç ZYGDNï¼æ£åæåçµéï¼ï¼ |
| | | // FrozenElectricity ç TotalKwh å¨é¨åè¡¨ä¸æä¸º nullï¼ä¸è½ä½ä¸ºç¨éæ¥æº |
| | | payload.put("meterAddress", address); |
| | | payload.put("valueType", "SJZ"); |
| | | path = PATH_ELECTRIC_QUANTITY; |
| | | } |
| | | List<JSONObject> items = callList(path, payload); |
| | | List<MeterUsagePoint> points = new ArrayList<>(items.size()); |
| | | for (JSONObject item : items) { |
| | | String rawTime = firstString(item, "ReadingDate", "readingDate", "Time", "time", "Date"); |
| | | LocalDateTime time = parseDateTime(rawTime); |
| | | if (time == null) { |
| | | throw new MeterProviderException(EnergyMeterConstants.ERROR_PARSE, |
| | | "æ æ³è¯å«ç¨éæ¶é´ï¼" + rawTime); |
| | | } |
| | | BigDecimal value; |
| | | if (water) { |
| | | value = firstDecimal(item, "Value", "value", "UseNumber"); |
| | | } else if (gas) { |
| | | value = firstDecimal(item, "UseNumber", "useNumber"); |
| | | } else { |
| | | value = firstDecimal(item, "ZYGDN", "zygdn", "TotalKwh", "totalKwh"); |
| | | } |
| | | if (value == null) { |
| | | throw new MeterProviderException(EnergyMeterConstants.ERROR_PARSE, "ç¨éåæ®µç¼ºå¤±"); |
| | | } |
| | | MeterUsagePoint point = new MeterUsagePoint(); |
| | | point.setTime(time.toLocalDate().atStartOfDay()); |
| | | point.setValue(value); |
| | | point.setAddress(firstString(item, "Address", "address")); |
| | | point.setRawTime(rawTime); |
| | | points.add(point); |
| | | } |
| | | return points; |
| | | } |
| | | |
| | | @Override |
| | | public List<MeterQuarterPoint> queryQuarterUsage(String meterType, String address, String providerMeterId, |
| | | LocalDate start, LocalDate end) { |
| | | if (!EnergyMeterConstants.isElectric(meterType)) { |
| | | throw new MeterProviderException("UNSUPPORTED", |
| | | "15 åéçµéç®ååªæ¯æçµè¡¨"); |
| | | } |
| | | if (mockMode()) { |
| | | return mockQuarterUsage(address, start, end); |
| | | } |
| | | JSONObject payload = new JSONObject(); |
| | | payload.put("dateType", "mi15"); |
| | | payload.put("startTime", start.toString()); |
| | | payload.put("endTime", end.toString()); |
| | | payload.put("meterAddress", address); |
| | | payload.put("valueType", "SJZ"); |
| | | List<JSONObject> items = callList(PATH_ELECTRIC_QUANTITY, payload); |
| | | List<MeterQuarterPoint> points = new ArrayList<>(items.size()); |
| | | for (JSONObject item : items) { |
| | | String rawTime = firstString(item, "ReadingDate", "readingDate", "Time", "time", "Date"); |
| | | LocalDateTime time = parseDateTime(rawTime); |
| | | if (time == null) { |
| | | throw new MeterProviderException(EnergyMeterConstants.ERROR_PARSE, |
| | | "æ æ³è¯å« 15 åéçµéæ¶é´ï¼" + rawTime); |
| | | } |
| | | BigDecimal active = firstDecimal(item, "ZYGDN", "zygdn"); |
| | | // æåä¸ä¸ªæªéåæ¶é´çç ZYGDN 为空ï¼åªä¿çå·²ç»ç»ç®çæ¶é´ç |
| | | if (active == null) { |
| | | continue; |
| | | } |
| | | MeterQuarterPoint point = new MeterQuarterPoint(); |
| | | point.setTime(time); |
| | | point.setActive(active); |
| | | point.setReactive(firstDecimal(item, "ZWGDN", "zwgdn")); |
| | | point.setActiveReading(firstDecimal(item, "ZYGDNSZ", "zygdnsz")); |
| | | point.setReactiveReading(firstDecimal(item, "ZWGDNSZ", "zwgdnsz")); |
| | | point.setAddress(firstString(item, "Address", "address")); |
| | | point.setRawTime(rawTime); |
| | | points.add(point); |
| | | } |
| | | return points; |
| | | } |
| | | |
| | | @Override |
| | | public List<MeterReadingPoint> queryReadings(String meterType, String address, String providerMeterId, |
| | | LocalDate start, LocalDate end) { |
| | | boolean water = EnergyMeterConstants.isWater(meterType); |
| | | if (mockMode()) { |
| | | return mockReadings(meterType, address, start, end); |
| | | } |
| | | if (EnergyMeterConstants.isGas(meterType)) { |
| | | return queryGasReadings(address, providerMeterId, start, end); |
| | | } |
| | | JSONObject payload = new JSONObject(); |
| | | payload.put("startTime", start.toString()); |
| | | payload.put("endTime", end.toString()); |
| | | if (water) { |
| | | payload.put("address", address); |
| | | List<JSONObject> items = callList(PATH_WATER_RAW, payload); |
| | | List<MeterReadingPoint> points = new ArrayList<>(items.size()); |
| | | for (JSONObject item : items) { |
| | | String rawTime = firstString(item, "ReadingDate", "readingDate", "Time", "time", "Date"); |
| | | LocalDateTime time = parseDateTime(rawTime); |
| | | if (time == null) { |
| | | throw new MeterProviderException(EnergyMeterConstants.ERROR_PARSE, "æ æ³è¯å«ç¤ºå¼æ¶é´ï¼" + rawTime); |
| | | } |
| | | BigDecimal reading = firstDecimal(item, "ReadNumber", "readNumber"); |
| | | if (reading == null) { |
| | | throw new MeterProviderException(EnergyMeterConstants.ERROR_PARSE, "示å¼å段缺失"); |
| | | } |
| | | MeterReadingPoint point = new MeterReadingPoint(); |
| | | point.setTime(time); |
| | | point.setReading(reading); |
| | | point.setUsage(firstDecimal(item, "UseNumber", "useNumber")); |
| | | point.setAddress(firstString(item, "Address", "address")); |
| | | point.setRawTime(rawTime); |
| | | points.add(point); |
| | | } |
| | | return points; |
| | | } |
| | | |
| | | payload.put("meterAddress", address); |
| | | payload.put("dateType", "D"); |
| | | payload.put("valueType", "SJZ"); |
| | | List<JSONObject> items = callList(PATH_FROZEN_ELECTRICITY, payload); |
| | | List<MeterReadingPoint> points = new ArrayList<>(items.size()); |
| | | for (JSONObject item : items) { |
| | | // FrozenElectricity åä¸å¤©ä¼è¿å Type=Dï¼è¡¨ç ï¼ä¸ Type=DFï¼æ¥å»ç»çµéï¼ä¸¤è¡ï¼ |
| | | // åªæ Type=D ç TotalNowKwh ææ¯ç´¯è®¡è¡¨ç |
| | | String freezeType = firstString(item, "Type", "type"); |
| | | if (StringUtils.isNotBlank(freezeType) && !"D".equalsIgnoreCase(freezeType)) { |
| | | continue; |
| | | } |
| | | String rawTime = firstString(item, "ReadingDate", "readingDate", "Time", "time", "Date"); |
| | | LocalDateTime time = parseDateTime(rawTime); |
| | | if (time == null) { |
| | | throw new MeterProviderException(EnergyMeterConstants.ERROR_PARSE, "æ æ³è¯å«ç¤ºå¼æ¶é´ï¼" + rawTime); |
| | | } |
| | | BigDecimal reading = firstDecimal(item, "TotalNowKwh", "totalNowKwh", "ZYGDNSZ", "zygdnsz"); |
| | | if (reading == null) { |
| | | throw new MeterProviderException(EnergyMeterConstants.ERROR_PARSE, "示å¼å段缺失"); |
| | | } |
| | | MeterReadingPoint point = new MeterReadingPoint(); |
| | | point.setTime(time); |
| | | point.setReading(reading); |
| | | point.setUsage(firstDecimal(item, "TotalKwh", "totalKwh")); |
| | | point.setAddress(firstString(item, "Address", "address")); |
| | | point.setRawTime(rawTime); |
| | | points.add(point); |
| | | } |
| | | return points; |
| | | } |
| | | |
| | | /** |
| | | * æ°è¡¨ç¤ºå¼ï¼/NH2/GetGasRawDataï¼æç¬¬ä¸æ¹è®¾å¤IDæéä¿¡å°åæ¥è¯¢ã |
| | | */ |
| | | private List<MeterReadingPoint> queryGasReadings(String address, String providerMeterId, |
| | | LocalDate start, LocalDate end) { |
| | | JSONObject payload = new JSONObject(); |
| | | payload.put("pageIndex", "1"); |
| | | payload.put("pageSize", "100"); |
| | | payload.put("dateType", "D"); |
| | | payload.put("areaID", "0"); |
| | | payload.put("gasmeterID", requireMeterId(EnergyMeterConstants.TYPE_GAS, providerMeterId)); |
| | | payload.put("address", StringUtils.defaultString(address)); |
| | | payload.put("startTime", start.toString()); |
| | | payload.put("endTime", end.toString()); |
| | | List<JSONObject> items = callList(PATH_GAS_RAW, payload); |
| | | List<MeterReadingPoint> points = new ArrayList<>(items.size()); |
| | | for (JSONObject item : items) { |
| | | String rawTime = firstString(item, "ReadingDate", "readingDate", "RealReadingDate", "Time", "time"); |
| | | LocalDateTime time = parseDateTime(rawTime); |
| | | if (time == null) { |
| | | throw new MeterProviderException(EnergyMeterConstants.ERROR_PARSE, "æ æ³è¯å«æ°è¡¨ç¤ºå¼æ¶é´ï¼" + rawTime); |
| | | } |
| | | BigDecimal reading = firstDecimal(item, "ReadNumber", "readNumber"); |
| | | if (reading == null) { |
| | | throw new MeterProviderException(EnergyMeterConstants.ERROR_PARSE, "æ°è¡¨ç¤ºå¼å段缺失"); |
| | | } |
| | | MeterReadingPoint point = new MeterReadingPoint(); |
| | | point.setTime(time); |
| | | point.setReading(reading); |
| | | point.setUsage(firstDecimal(item, "UseNumber", "useNumber")); |
| | | point.setAddress(firstString(item, "Address", "address")); |
| | | point.setRawTime(rawTime); |
| | | points.add(point); |
| | | } |
| | | return points; |
| | | } |
| | | |
| | | /** |
| | | * æ°è¡¨æ¥å£è¦æ±ä¼ ç¬¬ä¸æ¹è®¾å¤IDï¼æ°åï¼ï¼è¿éç»ä¸æ ¡éªã |
| | | */ |
| | | private long requireMeterId(String meterType, String providerMeterId) { |
| | | if (StringUtils.isBlank(providerMeterId)) { |
| | | throw new MeterProviderException("MISSING_METER_ID", |
| | | EnergyMeterConstants.typeName(meterType) + "缺å°ç¬¬ä¸æ¹è®¾å¤IDï¼è¯·éæ°éªè¯æ¡£æ¡ååéé"); |
| | | } |
| | | try { |
| | | return Long.parseLong(providerMeterId.trim()); |
| | | } catch (NumberFormatException e) { |
| | | throw new MeterProviderException("MISSING_METER_ID", |
| | | "ç¬¬ä¸æ¹è®¾å¤IDæ ¼å¼ä¸æ£ç¡®ï¼" + providerMeterId); |
| | | } |
| | | } |
| | | |
| | | /* ------------------------------------------------------------------ */ |
| | | /* HTTP è°ç¨ä¸ååºè§£æ */ |
| | | /* ------------------------------------------------------------------ */ |
| | | |
| | | private List<JSONObject> callList(String path, JSONObject payload) { |
| | | JSONObject root = call(path, payload); |
| | | JSONArray array = findArray(root); |
| | | if (array == null) { |
| | | throw new MeterProviderException(EnergyMeterConstants.ERROR_PARSE, "ç¬¬ä¸æ¹ååºç¼ºå°æ°æ®å表"); |
| | | } |
| | | List<JSONObject> items = new ArrayList<>(array.size()); |
| | | for (int i = 0; i < array.size(); i++) { |
| | | JSONObject item = array.getJSONObject(i); |
| | | if (item != null) { |
| | | items.add(item); |
| | | } |
| | | } |
| | | |
| | | int pageCount = firstInt(root, 1, "pageCount", "pagecount", "pages", "totalPage", "totalPages"); |
| | | if (pageCount > 1) { |
| | | int pageSize = firstInt(root, Math.max(items.size(), 1), "pageSize", "pagesize", "size"); |
| | | int total = firstInt(root, -1, "total", "totalCount", "totalRows", "count"); |
| | | Set<String> fingerprints = new HashSet<>(); |
| | | items.forEach(item -> fingerprints.add(item.toJSONString())); |
| | | for (int page = 2; page <= pageCount; page++) { |
| | | JSONObject nextPayload = new JSONObject(payload); |
| | | nextPayload.put("pageIndex", page); |
| | | nextPayload.put("pageSize", pageSize); |
| | | nextPayload.put("pageNum", page); |
| | | JSONArray nextArray = findArray(call(path, nextPayload)); |
| | | if (nextArray == null || nextArray.isEmpty()) { |
| | | throw new MeterProviderException(EnergyMeterConstants.ERROR_PAGE_INCOMPLETE, |
| | | "ç¬¬ä¸æ¹å页第 " + page + " é¡µä¸ºç©ºï¼æ æ³ç¡®è®¤å
¨éæ°æ®"); |
| | | } |
| | | for (int i = 0; i < nextArray.size(); i++) { |
| | | JSONObject item = nextArray.getJSONObject(i); |
| | | if (item != null && fingerprints.add(item.toJSONString())) { |
| | | items.add(item); |
| | | } |
| | | } |
| | | } |
| | | if (total > 0 && items.size() < total) { |
| | | throw new MeterProviderException(EnergyMeterConstants.ERROR_PAGE_INCOMPLETE, |
| | | "ç¬¬ä¸æ¹åé¡µæ¡æ°ä¸å®æ´ï¼" + items.size() + "/" + total); |
| | | } |
| | | } |
| | | return items; |
| | | } |
| | | |
| | | private JSONObject call(String path, JSONObject payload) { |
| | | EnergyMeterProperties.Provider provider = properties.getProvider(); |
| | | if (StringUtils.isBlank(provider.getApiKey())) { |
| | | throw new MeterProviderException("NO_API_KEY", |
| | | "æªé
ç½®ç¬¬ä¸æ¹ææç ï¼ç¯å¢åé NH_ENERGY_API_KEYï¼ï¼æ æ³è·åçå®ç¨é"); |
| | | } |
| | | String url = joinUrl(provider.getBaseUrl(), path); |
| | | String body; |
| | | HttpResponse response = null; |
| | | try { |
| | | throttle(provider.getMinIntervalMs()); |
| | | response = HttpRequest.post(url) |
| | | .header("API_KEY", provider.getApiKey()) |
| | | .contentType("application/json") |
| | | .body(payload.toJSONString()) |
| | | .timeout(provider.getReadTimeoutSeconds() * 1000) |
| | | .setConnectionTimeout(provider.getConnectTimeoutSeconds() * 1000) |
| | | .execute(); |
| | | int status = response.getStatus(); |
| | | if (status == 429) { |
| | | throw new MeterProviderException("RATE_LIMITED", "ç¬¬ä¸æ¹æ¥å£éæµï¼429ï¼ï¼è¯·éä½ééé¢çåéè¯"); |
| | | } |
| | | if (status >= 400) { |
| | | throw new MeterProviderException(EnergyMeterConstants.ERROR_UPSTREAM, |
| | | "ç¬¬ä¸æ¹æ¥å£è¿åç¶æç ï¼" + status + "ï¼" + path + "ï¼"); |
| | | } |
| | | body = response.body(); |
| | | } catch (MeterProviderException e) { |
| | | throw e; |
| | | } catch (HttpException e) { |
| | | throw new MeterProviderException(EnergyMeterConstants.ERROR_TIMEOUT, |
| | | "ç¬¬ä¸æ¹æ¥å£è¯·æ±è¶
æ¶æç½ç»å¼å¸¸ï¼" + path, e); |
| | | } catch (Exception e) { |
| | | throw new MeterProviderException(EnergyMeterConstants.ERROR_UPSTREAM, |
| | | "ç¬¬ä¸æ¹æ¥å£è°ç¨å¤±è´¥ï¼" + path, e); |
| | | } finally { |
| | | if (response != null) { |
| | | response.close(); |
| | | } |
| | | } |
| | | if (StringUtils.isBlank(body)) { |
| | | throw new MeterProviderException(EnergyMeterConstants.ERROR_PARSE, "ç¬¬ä¸æ¹ååºä¸ºç©º"); |
| | | } |
| | | Object parsed; |
| | | try { |
| | | parsed = JSON.parse(body); |
| | | } catch (Exception e) { |
| | | throw new MeterProviderException(EnergyMeterConstants.ERROR_PARSE, "ç¬¬ä¸æ¹ååºä¸æ¯åæ³ JSON", e); |
| | | } |
| | | JSONObject root; |
| | | if (parsed instanceof JSONArray array) { |
| | | root = new JSONObject(); |
| | | root.put("list", array); |
| | | } else if (parsed instanceof JSONObject object) { |
| | | root = object; |
| | | } else { |
| | | throw new MeterProviderException(EnergyMeterConstants.ERROR_PARSE, "ç¬¬ä¸æ¹ååºç»ææ æ³è¯å«"); |
| | | } |
| | | checkBusinessError(root); |
| | | return root; |
| | | } |
| | | |
| | | private void checkBusinessError(JSONObject root) { |
| | | Boolean success = null; |
| | | for (String key : new String[]{"success", "Success"}) { |
| | | if (root.containsKey(key)) { |
| | | success = root.getBoolean(key); |
| | | break; |
| | | } |
| | | } |
| | | Integer code = null; |
| | | for (String key : new String[]{"code", "Code", "errcode", "errCode", "status"}) { |
| | | if (root.containsKey(key)) { |
| | | code = root.getInteger(key); |
| | | break; |
| | | } |
| | | } |
| | | String message = firstString(root, "msg", "message", "Message", "errmsg", "error", "Error"); |
| | | if (Boolean.FALSE.equals(success)) { |
| | | throw new MeterProviderException(EnergyMeterConstants.ERROR_UPSTREAM, |
| | | "ç¬¬ä¸æ¹è¿å失败ï¼" + StringUtils.defaultString(message, "æªç¥åå ")); |
| | | } |
| | | if (code != null && code != 0 && code != 200 && code != 1) { |
| | | throw new MeterProviderException(EnergyMeterConstants.ERROR_UPSTREAM, |
| | | "ç¬¬ä¸æ¹è¿åé误ç " + code + "ï¼" + StringUtils.defaultString(message, "æªç¥åå ")); |
| | | } |
| | | } |
| | | |
| | | private JSONArray findArray(JSONObject root) { |
| | | if (root == null) { |
| | | return null; |
| | | } |
| | | for (String key : new String[]{"list", "data", "result", "rows", "records", "items", "List", "Data"}) { |
| | | Object value = root.get(key); |
| | | if (value instanceof JSONArray array) { |
| | | return array; |
| | | } |
| | | if (value instanceof JSONObject object) { |
| | | JSONArray nested = findArray(object); |
| | | if (nested != null) { |
| | | return nested; |
| | | } |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | private String joinUrl(String baseUrl, String path) { |
| | | String base = StringUtils.trim(baseUrl); |
| | | if (StringUtils.isBlank(base)) { |
| | | throw new MeterProviderException("CONFIG_ERROR", "æªé
ç½®ç¬¬ä¸æ¹åºç¡å°å energy-meter.provider.base-url"); |
| | | } |
| | | while (base.endsWith("/")) { |
| | | base = base.substring(0, base.length() - 1); |
| | | } |
| | | return base + path; |
| | | } |
| | | |
| | | /* ------------------------------------------------------------------ */ |
| | | /* æ¼ç¤ºæ°æ® */ |
| | | /* ------------------------------------------------------------------ */ |
| | | |
| | | private MeterArchive mockArchive(String meterType, String address) { |
| | | boolean water = EnergyMeterConstants.isWater(meterType); |
| | | MeterArchive archive = new MeterArchive(); |
| | | archive.setMeterType(meterType); |
| | | archive.setMeterAddress(address); |
| | | archive.setProviderMeterId("MOCK-" + Integer.toHexString(Math.abs(address.hashCode())).toUpperCase()); |
| | | archive.setProviderName((water ? "æ¼ç¤ºæ°´è¡¨ " : "æ¼ç¤ºçµè¡¨ ") + address); |
| | | archive.setAreaName("æ¼ç¤ºåºå"); |
| | | archive.setOnlineStatus(1); |
| | | archive.setStateText("å¨çº¿"); |
| | | return archive; |
| | | } |
| | | |
| | | private List<MeterUsagePoint> mockUsage(String meterType, String address, LocalDate start, LocalDate end) { |
| | | List<MeterUsagePoint> points = new ArrayList<>(); |
| | | for (LocalDate date = start; !date.isAfter(end); date = date.plusDays(1)) { |
| | | MeterUsagePoint point = new MeterUsagePoint(); |
| | | point.setTime(date.atStartOfDay()); |
| | | point.setValue(mockDailyValue(meterType, address, date)); |
| | | point.setAddress(address); |
| | | point.setRawTime(date.toString()); |
| | | points.add(point); |
| | | } |
| | | return points; |
| | | } |
| | | |
| | | private List<MeterQuarterPoint> mockQuarterUsage(String address, LocalDate start, LocalDate end) { |
| | | List<MeterQuarterPoint> points = new ArrayList<>(); |
| | | for (LocalDate date = start; !date.isAfter(end); date = date.plusDays(1)) { |
| | | BigDecimal daily = mockDailyValue(EnergyMeterConstants.TYPE_ELECTRIC, address, date); |
| | | BigDecimal quarterBase = daily.divide(BigDecimal.valueOf(96), 6, RoundingMode.HALF_UP); |
| | | for (int index = 1; index <= 96; index++) { |
| | | LocalDateTime time = date.atStartOfDay().plusMinutes(index * 15L); |
| | | // ç½å¤©è´è·é«ãå¤é´è´è·ä½ï¼ä¿è¯æ²çº¿ç¨³å®ä¸å¯éå¤ |
| | | double hour = (index * 15.0) / 60.0; |
| | | double shape = 0.45 + 0.75 * Math.sin(Math.PI * Math.min(Math.max((hour - 6) / 16.0, 0), 1)); |
| | | BigDecimal active = quarterBase.multiply(BigDecimal.valueOf(shape)) |
| | | .setScale(3, RoundingMode.HALF_UP); |
| | | MeterQuarterPoint point = new MeterQuarterPoint(); |
| | | point.setTime(time); |
| | | point.setActive(active); |
| | | point.setReactive(active.multiply(BigDecimal.valueOf(0.18)).setScale(3, RoundingMode.HALF_UP)); |
| | | point.setActiveReading(BigDecimal.valueOf(MOCK_ELECTRIC_BASE.doubleValue()) |
| | | .add(daily.multiply(BigDecimal.valueOf(index / 96.0))).setScale(3, RoundingMode.HALF_UP)); |
| | | point.setReactiveReading(point.getActiveReading().multiply(BigDecimal.valueOf(0.18)) |
| | | .setScale(3, RoundingMode.HALF_UP)); |
| | | point.setAddress(address); |
| | | point.setRawTime(time.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"))); |
| | | points.add(point); |
| | | } |
| | | } |
| | | return points; |
| | | } |
| | | |
| | | private List<MeterReadingPoint> mockReadings(String meterType, String address, LocalDate start, LocalDate end) { |
| | | boolean water = EnergyMeterConstants.isWater(meterType); |
| | | BigDecimal base = water ? MOCK_WATER_BASE : MOCK_ELECTRIC_BASE; |
| | | List<MeterReadingPoint> points = new ArrayList<>(); |
| | | for (LocalDate date = start; !date.isAfter(end); date = date.plusDays(1)) { |
| | | BigDecimal cumulative = base; |
| | | for (LocalDate cursor = MOCK_READING_EPOCH; !cursor.isAfter(date); cursor = cursor.plusDays(1)) { |
| | | cumulative = cumulative.add(mockDailyValue(meterType, address, cursor)); |
| | | } |
| | | MeterReadingPoint point = new MeterReadingPoint(); |
| | | point.setTime(date.atStartOfDay()); |
| | | point.setReading(cumulative.setScale(3, RoundingMode.HALF_UP)); |
| | | point.setUsage(mockDailyValue(meterType, address, date)); |
| | | point.setAddress(address); |
| | | point.setRawTime(date.toString()); |
| | | points.add(point); |
| | | } |
| | | return points; |
| | | } |
| | | |
| | | /** |
| | | * æ¼ç¤ºç¨éï¼åä¸è®¾å¤å䏿¥ææå®ï¼ä¿è¯é夿¥è¡¨ç»æä¸è´ï¼ä¾¿äºéªè¯å¹çï¼ã |
| | | */ |
| | | private BigDecimal mockDailyValue(String meterType, String address, LocalDate date) { |
| | | boolean water = EnergyMeterConstants.isWater(meterType); |
| | | long seed = Math.abs(Objects.hash(address, date.toString())); |
| | | double seasonal = 1 + 0.16 * Math.sin((date.getDayOfYear() - 80) / 365.0 * 2 * Math.PI); |
| | | double base = water ? 3.2 : 55.0; |
| | | double variance = water ? 1.6 : 30.0; |
| | | double value = (base + (seed % 1000) / 1000.0 * variance) * seasonal; |
| | | return BigDecimal.valueOf(value).setScale(3, RoundingMode.HALF_UP); |
| | | } |
| | | |
| | | /* ------------------------------------------------------------------ */ |
| | | /* è§£æå·¥å
· */ |
| | | /* ------------------------------------------------------------------ */ |
| | | |
| | | private String firstString(JSONObject object, String... keys) { |
| | | if (object == null) { |
| | | return null; |
| | | } |
| | | for (String key : keys) { |
| | | Object value = object.get(key); |
| | | if (value != null && StringUtils.isNotBlank(String.valueOf(value))) { |
| | | return String.valueOf(value).trim(); |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | private BigDecimal firstDecimal(JSONObject object, String... keys) { |
| | | if (object == null) { |
| | | return null; |
| | | } |
| | | for (String key : keys) { |
| | | Object value = object.get(key); |
| | | if (value == null) { |
| | | continue; |
| | | } |
| | | try { |
| | | return new BigDecimal(String.valueOf(value).trim()); |
| | | } catch (NumberFormatException ignored) { |
| | | // ç»§ç»å°è¯ä¸ä¸ä¸ªåéåæ®µ |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | private Long firstLong(JSONObject object, String... keys) { |
| | | BigDecimal value = firstDecimal(object, keys); |
| | | return value == null ? null : value.longValue(); |
| | | } |
| | | |
| | | private int firstInt(JSONObject object, int defaultValue, String... keys) { |
| | | BigDecimal value = firstDecimal(object, keys); |
| | | return value == null ? defaultValue : value.intValue(); |
| | | } |
| | | |
| | | private Integer parseOnline(String state) { |
| | | if (StringUtils.isBlank(state)) { |
| | | return null; |
| | | } |
| | | String normalized = state.trim(); |
| | | if ("1".equals(normalized) || "true".equalsIgnoreCase(normalized) |
| | | || normalized.contains("å¨çº¿") || "on".equalsIgnoreCase(normalized)) { |
| | | return 1; |
| | | } |
| | | if ("0".equals(normalized) || "false".equalsIgnoreCase(normalized) |
| | | || normalized.contains("离线") || "off".equalsIgnoreCase(normalized)) { |
| | | return 0; |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | private LocalDateTime parseDateTime(String raw) { |
| | | if (StringUtils.isBlank(raw)) { |
| | | return null; |
| | | } |
| | | String text = raw.trim(); |
| | | for (DateTimeFormatter formatter : DATE_TIME_FORMATS) { |
| | | try { |
| | | if (text.length() <= 10) { |
| | | return LocalDate.parse(text, formatter).atStartOfDay(); |
| | | } |
| | | return LocalDateTime.parse(text, formatter); |
| | | } catch (DateTimeParseException ignored) { |
| | | // å°è¯ä¸ä¸ç§æ ¼å¼ |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.service; |
| | | |
| | | import com.ruoyi.energymeter.vo.ElectricMeterDashboardVO; |
| | | |
| | | /** |
| | | * çµè¡¨å®æ¶çæ¿æå¡ã |
| | | */ |
| | | public interface ElectricMeterDashboardService { |
| | | |
| | | /** |
| | | * 仿¥ 15 åéæ²çº¿ + è¿ä¸å¨/ä¸ä¸å¨çµè½è´¨éã |
| | | * |
| | | * @param meterId åå°è®¾å¤ï¼ç©ºè¡¨ç¤ºå
¨é¨å·²å¯ç¨çµè¡¨ |
| | | * @param weekOffset 0 è¿ä¸å¨ï¼1 ä¸ä¸å¨ |
| | | */ |
| | | ElectricMeterDashboardVO dashboard(Long meterId, Integer weekOffset); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.service; |
| | | |
| | | import java.time.LocalDate; |
| | | |
| | | /** |
| | | * æ¼ç¤ºæ°æ®æå¡ï¼æ°è¡¨æªæ¥å
¥ç¬¬ä¸æ¹æ¶ï¼æå¤©çææ¨¡æç¨éã |
| | | * |
| | | * <p>åªå¤ç `simulated=1` ç设å¤ï¼ä¸åä¸å¤©éå¤è°ç¨ä¸ä¼äº§çéå¤è®°å½ã</p> |
| | | */ |
| | | public interface EnergyMeterDemoService { |
| | | |
| | | /** |
| | | * 为æå®ä¸å¡æ¥æçææ¼ç¤ºè¡¨ç ä¸ç¨éï¼è¿åå®é
åå
¥çè®¾å¤æ°ã |
| | | */ |
| | | int generateGasDemo(LocalDate date); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.service; |
| | | |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.baomidou.mybatisplus.extension.service.IService; |
| | | import com.ruoyi.energymeter.dto.EnergyMeterDeviceQuery; |
| | | import com.ruoyi.energymeter.dto.MeterBindRequest; |
| | | import com.ruoyi.energymeter.dto.MeterManualBindRequest; |
| | | import com.ruoyi.energymeter.dto.MeterReadingRequest; |
| | | import com.ruoyi.energymeter.dto.MeterUpdateRequest; |
| | | import com.ruoyi.energymeter.pojo.EnergyMeterDevice; |
| | | import com.ruoyi.energymeter.pojo.EnergyMeterMeasurement; |
| | | import com.ruoyi.energymeter.vo.MeterArchiveVO; |
| | | import com.ruoyi.energymeter.vo.MeterReadingResultVO; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * æ°´çµè¡¨ç»å®è®¾å¤æå¡ã |
| | | */ |
| | | public interface EnergyMeterDeviceService extends IService<EnergyMeterDevice> { |
| | | |
| | | /** |
| | | * æç±»åãå
³é®åãç¶æå页æ¥è¯¢å½åç§æ·å¯è§è®¾å¤ï¼å¹¶è¡¥å
æè¿ééç»æã |
| | | */ |
| | | IPage<EnergyMeterDevice> pageDevices(Page<EnergyMeterDevice> page, EnergyMeterDeviceQuery query); |
| | | |
| | | /** |
| | | * 设å¤ä¸æé项ï¼ä»
å·²å¯ç¨è®¾å¤ï¼ã |
| | | */ |
| | | List<EnergyMeterDevice> listDeviceOptions(String meterType); |
| | | |
| | | /** |
| | | * è°ç¨ç¬¬ä¸æ¹æ¡£æ¡æ¥å£éªè¯å¹¶ä¸¥æ ¼å¹é
éä¿¡å°åã |
| | | */ |
| | | MeterArchiveVO verifyArchive(String meterType, String meterAddress); |
| | | |
| | | /** |
| | | * æ°å¢æ¬å°ç»å®ï¼æåå弿¥å建åå²è¡¥éæ¹æ¬¡ã |
| | | */ |
| | | EnergyMeterDevice bind(MeterBindRequest request); |
| | | |
| | | /** |
| | | * æ°å¢æå·¥æè¡¨è®¾å¤ï¼æ°´è¡¨/çµè¡¨/æ°è¡¨ï¼ï¼åå
¥èµ·å§è¡¨ç ï¼ä¸è°ç¨ç¬¬ä¸æ¹æ¥å£ã |
| | | */ |
| | | EnergyMeterDevice addManual(MeterManualBindRequest request); |
| | | |
| | | /** |
| | | * å é¤è®¾å¤ï¼ä»
å
许å é¤ç¨æ·æ°å¢çæå·¥æè¡¨è®¾å¤ï¼åå§å设å¤ç¦æ¢å é¤ã |
| | | */ |
| | | void removeDevice(Long id); |
| | | |
| | | /** |
| | | * æå·¥æè¡¨è®°å½å页ï¼è¡¨ç + æ¬æç¨éï¼ã |
| | | */ |
| | | IPage<EnergyMeterMeasurement> pageReadings(Long meterId, long current, long size); |
| | | |
| | | /** |
| | | * å½å
¥ä¸æ¡æå·¥æè¡¨è®°å½ï¼ææå·®çæ/ä¿®æ£å¯¹åºæ¥ç¨éã |
| | | */ |
| | | MeterReadingResultVO addReading(Long meterId, MeterReadingRequest request); |
| | | |
| | | /** |
| | | * å é¤ä¸æ¡æå·¥æè¡¨è®°å½ï¼å¹¶éç®åå½±åçæ¥ç¨éã |
| | | */ |
| | | void removeReading(Long meterId, Long measurementId); |
| | | |
| | | /** |
| | | * ä¿®æ¹æ¬å°æ¾ç¤ºå段ä¸å¯åç¨ç¶æï¼éä¿¡å°åä¸å¯å¨æ¤ä¿®æ¹ã |
| | | */ |
| | | EnergyMeterDevice updateLocal(Long id, MeterUpdateRequest request); |
| | | |
| | | /** |
| | | * è·åå½åç§æ·ä¸çä¸å°è®¾å¤ï¼æ¾ä¸å°æ¶æä¸å¡å¼å¸¸ã |
| | | */ |
| | | EnergyMeterDevice getOwnedDevice(Long id); |
| | | |
| | | /** |
| | | * å½åç§æ·ä¸å¯ç¨ç设å¤ï¼æç±»åçéï¼å¯ä¸ºç©ºï¼ã |
| | | */ |
| | | List<EnergyMeterDevice> listEnabledDevices(String meterType); |
| | | |
| | | /** |
| | | * æ¼ç¤ºæ°æ®æ¨¡å¼æç¤ºã |
| | | */ |
| | | boolean mockMode(); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.service; |
| | | |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import com.ruoyi.energymeter.pojo.EnergyMeterMeasurement; |
| | | import com.ruoyi.energymeter.vo.EnergyMeterOverviewVO; |
| | | |
| | | import java.time.LocalDate; |
| | | |
| | | /** |
| | | * æ¦è§ä¸æç»æ¥è¯¢æå¡ï¼åªè¯»æ¬å°éé表ï¼ä¸ç´è¿ç¬¬ä¸æ¹ã |
| | | */ |
| | | public interface EnergyMeterStatService { |
| | | |
| | | /** |
| | | * ç¨è½æ¦è§ï¼å¡çãææ¥/ææå¯¹æ¯åºåãééç¶æã |
| | | */ |
| | | EnergyMeterOverviewVO overview(String meterType, Long meterId, String month, Integer year); |
| | | |
| | | /** |
| | | * åå°è®¾å¤ç读æ°/ç¨éæç»ã |
| | | */ |
| | | IPage<EnergyMeterMeasurement> pageMeasurements(Long meterId, String metricCode, String granularity, |
| | | LocalDate start, LocalDate end, long current, long size); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.service; |
| | | |
| | | import com.ruoyi.energymeter.pojo.EnergyMeterDevice; |
| | | |
| | | import java.time.LocalDate; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * 忥è°åº¦æå¡ï¼æ¹æ¬¡å建ã任塿§è¡ã失败éè¯ä¸è¿åº¦æ¨è¿ã |
| | | */ |
| | | public interface EnergyMeterSyncService { |
| | | |
| | | /** |
| | | * æ¯å¤© 08:00 çèªå¨åæ¥ï¼åä¸åäº¬æ¥æåªå建ä¸ä¸ªæ¹æ¬¡ã |
| | | */ |
| | | Long triggerScheduledSync(); |
| | | |
| | | /** |
| | | * æ°ç»å®è®¾å¤çåå²è¡¥éã |
| | | */ |
| | | void triggerBackfill(EnergyMeterDevice device, LocalDate start, LocalDate end); |
| | | |
| | | /** |
| | | * åç¨åéæ°å¯ç¨æ¶æè¿åº¦è¡¥éåç¨æé´æ°æ®ã |
| | | */ |
| | | Long triggerBackfillGap(EnergyMeterDevice device); |
| | | |
| | | /** |
| | | * æå¨æ¥è¡¨ï¼è¿åæ¹æ¬¡IDã |
| | | */ |
| | | Long triggerManual(List<Long> meterIds, LocalDate start, LocalDate end, Boolean includeReadings); |
| | | |
| | | /** |
| | | * 弿¥æ§è¡ä¸ä¸ªæ¹æ¬¡ã |
| | | */ |
| | | void executeRunAsync(Long runId); |
| | | |
| | | /** |
| | | * å¤çå°æçéè¯ä»»å¡ä¸è¶
æ¶ç RUNNING ä»»å¡ï¼è¿åå¤çæ°éã |
| | | */ |
| | | int recoverDueTasks(); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.service; |
| | | |
| | | import com.ruoyi.energymeter.vo.EnergyCollectionVO; |
| | | import com.ruoyi.energymeter.vo.EnergyRealtimeVO; |
| | | import com.ruoyi.energymeter.vo.EnergyReportVO; |
| | | |
| | | /** |
| | | * è½èæ°æ®ééã宿¶çæ§ä¸ç»è®¡åæã |
| | | */ |
| | | public interface EnergyMonitorService { |
| | | |
| | | /** |
| | | * æ°æ®é鿦è§ï¼ä¸ç±»ä»è´¨çæ¥å
¥è®¾å¤ãå½éè¿åº¦ä¸æè¿ééæ¹æ¬¡ã |
| | | */ |
| | | EnergyCollectionVO collection(); |
| | | |
| | | /** |
| | | * 宿¶çæ§ï¼ä¸ç±»ä»è´¨ææ°ç¨éãè¿ 7 æ¥è¶å¿ä¸çµè¡¨ 15 åé宿¶æ°æ®ã |
| | | * |
| | | * @param meterId åå°è®¾å¤ï¼ç©ºè¡¨ç¤ºå
¨é¨å·²å¯ç¨è®¾å¤ |
| | | */ |
| | | EnergyRealtimeVO realtime(Long meterId); |
| | | |
| | | /** |
| | | * ç»è®¡åæï¼ææ¥/æãæä»è´¨/è®¾å¤æ±æ»æ°´ãçµãè¸æ±½ç¨éã |
| | | */ |
| | | EnergyReportVO report(String startDate, String endDate, String granularity, String meterType, String dimension); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.service.impl; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.ruoyi.common.exception.ServiceException; |
| | | import com.ruoyi.common.utils.StringUtils; |
| | | import com.ruoyi.energymeter.constant.EnergyMeterConstants; |
| | | import com.ruoyi.energymeter.dto.MeterQuarterPoint; |
| | | import com.ruoyi.energymeter.mapper.EnergyMeterDeviceMapper; |
| | | import com.ruoyi.energymeter.pojo.EnergyMeterDevice; |
| | | import com.ruoyi.energymeter.provider.MeterProviderClient; |
| | | import com.ruoyi.energymeter.provider.MeterProviderException; |
| | | import com.ruoyi.energymeter.service.ElectricMeterDashboardService; |
| | | import com.ruoyi.energymeter.util.EnergyMeterSupport; |
| | | import com.ruoyi.energymeter.vo.ElectricMeterDashboardVO; |
| | | import lombok.RequiredArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.math.RoundingMode; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.time.temporal.ChronoUnit; |
| | | import java.util.ArrayList; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.TreeMap; |
| | | import java.util.concurrent.ConcurrentHashMap; |
| | | |
| | | /** |
| | | * çµè¡¨çæ¿ï¼æéç¤¾äº ElectricQuantity ç mi15 æ°æ®èåæä»æ¥æ²çº¿ä¸çµè½è´¨éã |
| | | * |
| | | * <p>15 åéæ°æ®åªå¨é¡µé¢æ¥çæ¶å®æ¶æåï¼ä¸è½åºï¼æ¥/æç´¯è®¡ä»ä»¥éé表ç D ç²åº¦ä¸ºåã |
| | | * åªè®¡ç®çµéãåçååçå æ°ï¼ä¸æ¶åä»»ä½è´¹ç¨ã</p> |
| | | */ |
| | | @Slf4j |
| | | @Service |
| | | @RequiredArgsConstructor |
| | | public class ElectricMeterDashboardServiceImpl implements ElectricMeterDashboardService { |
| | | |
| | | private static final DateTimeFormatter DAY_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd"); |
| | | private static final DateTimeFormatter LABEL_FORMAT = DateTimeFormatter.ofPattern("MM-dd HH:mm"); |
| | | private static final int SLOT_COUNT = 96; |
| | | /** ç¬¬ä¸æ¹éæµè¾ä¸¥ï¼é¡µé¢æ°æ®ç¼å 2 åéï¼é¿å
é¢ç¹åæ¢è®¾å¤/卿¬¡æ¶åå¤è¯·æ±ã */ |
| | | private static final long CACHE_TTL_MS = 120_000L; |
| | | |
| | | private final EnergyMeterDeviceMapper deviceMapper; |
| | | private final MeterProviderClient provider; |
| | | |
| | | private final Map<String, CachedPoints> cache = new ConcurrentHashMap<>(); |
| | | |
| | | @Override |
| | | public ElectricMeterDashboardVO dashboard(Long meterId, Integer weekOffset) { |
| | | LocalDate today = EnergyMeterSupport.today(); |
| | | int offset = weekOffset != null && weekOffset == 1 ? 1 : 0; |
| | | LocalDate qualityStart = offset == 1 ? today.minusDays(13) : today.minusDays(6); |
| | | LocalDate qualityEnd = offset == 1 ? today.minusDays(7) : today; |
| | | |
| | | List<EnergyMeterDevice> devices = resolveDevices(meterId); |
| | | |
| | | ElectricMeterDashboardVO vo = new ElectricMeterDashboardVO(); |
| | | vo.setUnit(EnergyMeterConstants.UNIT_ELECTRIC); |
| | | vo.setMeterId(meterId); |
| | | vo.setDeviceCount(devices.size()); |
| | | vo.setScopeLabel(scopeLabel(devices, meterId)); |
| | | vo.setMockMode(provider.mockMode()); |
| | | |
| | | ElectricMeterDashboardVO.Today todayVo = new ElectricMeterDashboardVO.Today(); |
| | | ElectricMeterDashboardVO.Quality qualityVo = new ElectricMeterDashboardVO.Quality(); |
| | | |
| | | if (devices.isEmpty()) { |
| | | fillEmptyToday(todayVo, today); |
| | | fillEmptyQuality(qualityVo, qualityStart, qualityEnd, offset); |
| | | vo.setToday(todayVo); |
| | | vo.setQuality(qualityVo); |
| | | return vo; |
| | | } |
| | | |
| | | List<MeterQuarterPoint> qualityPoints; |
| | | List<MeterQuarterPoint> todayPoints; |
| | | if (offset == 1) { |
| | | // ä¸ä¸å¨ä¸ä»æ¥æ²¡æäº¤éï¼å嫿¥è¯¢ï¼ä»æ¥æ²çº¿ä»ç¶åèªæè¿ä¸¤å¤© |
| | | qualityPoints = queryDevices(devices, qualityStart, qualityEnd); |
| | | todayPoints = queryDevices(devices, today.minusDays(1), today); |
| | | } else { |
| | | // è¿ä¸å¨å·²å
嫿¨å¤©ä¸ä»å¤©ï¼ä¸æ¬¡æ¥è¯¢å³å¯åæ¶æ»¡è¶³ä¸¤åå¾è¡¨ |
| | | qualityPoints = queryDevices(devices, qualityStart, qualityEnd); |
| | | todayPoints = qualityPoints; |
| | | } |
| | | |
| | | fillToday(todayVo, today, todayPoints); |
| | | fillQuality(qualityVo, qualityStart, qualityEnd, offset, qualityPoints); |
| | | |
| | | vo.setToday(todayVo); |
| | | vo.setQuality(qualityVo); |
| | | return vo; |
| | | } |
| | | |
| | | /* ------------------------------------------------------------------ */ |
| | | /* 仿¥æ²çº¿ */ |
| | | /* ------------------------------------------------------------------ */ |
| | | |
| | | private void fillToday(ElectricMeterDashboardVO.Today todayVo, LocalDate today, |
| | | List<MeterQuarterPoint> points) { |
| | | Map<Integer, BigDecimal[]> todaySlots = new HashMap<>(); |
| | | Map<Integer, BigDecimal[]> yesterdaySlots = new HashMap<>(); |
| | | LocalDate yesterday = today.minusDays(1); |
| | | for (MeterQuarterPoint point : points) { |
| | | if (point.getTime() == null || point.getActive() == null) { |
| | | continue; |
| | | } |
| | | LocalDate day = point.getTime().toLocalDate(); |
| | | Map<Integer, BigDecimal[]> target; |
| | | if (day.equals(today)) { |
| | | target = todaySlots; |
| | | } else if (day.equals(yesterday)) { |
| | | target = yesterdaySlots; |
| | | } else { |
| | | continue; |
| | | } |
| | | int slot = slotIndex(point.getTime()); |
| | | BigDecimal[] values = target.computeIfAbsent(slot, key -> new BigDecimal[]{BigDecimal.ZERO, BigDecimal.ZERO}); |
| | | values[0] = values[0].add(point.getActive()); |
| | | values[1] = values[1].add(point.getReactive() == null ? BigDecimal.ZERO : point.getReactive()); |
| | | } |
| | | |
| | | todayVo.setDate(today.format(DAY_FORMAT)); |
| | | todayVo.setRangeStart("00:00"); |
| | | todayVo.setSeries(buildSlots(todaySlots, 1, SLOT_COUNT)); |
| | | todayVo.setYesterdaySeries(buildSlots(yesterdaySlots, 1, SLOT_COUNT)); |
| | | |
| | | BigDecimal todayTotal = sumActive(todaySlots); |
| | | BigDecimal yesterdayTotal = sumActive(yesterdaySlots); |
| | | todayVo.setTotal(todaySlots.isEmpty() ? null : todayTotal); |
| | | todayVo.setYesterdayTotal(yesterdayTotal); |
| | | |
| | | int lastSlot = lastDataSlot(todaySlots); |
| | | BigDecimal yesterdaySame = lastSlot <= 0 ? null : sumActive(yesterdaySlots, lastSlot); |
| | | todayVo.setYesterdaySamePeriodTotal(yesterdaySame); |
| | | if (lastSlot > 0 && yesterdaySame != null && yesterdaySame.compareTo(BigDecimal.ZERO) > 0) { |
| | | todayVo.setCompareRate(todayTotal.subtract(yesterdaySame) |
| | | .multiply(BigDecimal.valueOf(100)) |
| | | .divide(yesterdaySame, 1, RoundingMode.HALF_UP)); |
| | | } |
| | | todayVo.setRangeEnd(lastSlot > 0 ? labelOfSlot(lastSlot) : "--"); |
| | | } |
| | | |
| | | private List<ElectricMeterDashboardVO.QuarterPoint> buildSlots(Map<Integer, BigDecimal[]> slots, |
| | | int fromSlot, int toSlot) { |
| | | List<ElectricMeterDashboardVO.QuarterPoint> result = new ArrayList<>(toSlot - fromSlot + 1); |
| | | for (int slot = fromSlot; slot <= toSlot; slot++) { |
| | | ElectricMeterDashboardVO.QuarterPoint point = new ElectricMeterDashboardVO.QuarterPoint(); |
| | | point.setTime(labelOfSlot(slot)); |
| | | BigDecimal[] values = slots.get(slot); |
| | | if (values != null) { |
| | | point.setActive(values[0].setScale(3, RoundingMode.HALF_UP)); |
| | | point.setReactive(values[1].setScale(3, RoundingMode.HALF_UP)); |
| | | } |
| | | result.add(point); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | private void fillEmptyToday(ElectricMeterDashboardVO.Today todayVo, LocalDate today) { |
| | | todayVo.setDate(today.format(DAY_FORMAT)); |
| | | todayVo.setRangeStart("00:00"); |
| | | todayVo.setRangeEnd("--"); |
| | | todayVo.setSeries(buildSlots(Map.of(), 1, SLOT_COUNT)); |
| | | todayVo.setYesterdaySeries(buildSlots(Map.of(), 1, SLOT_COUNT)); |
| | | } |
| | | |
| | | private BigDecimal sumActive(Map<Integer, BigDecimal[]> slots) { |
| | | return sumActive(slots, SLOT_COUNT); |
| | | } |
| | | |
| | | private BigDecimal sumActive(Map<Integer, BigDecimal[]> slots, int maxSlot) { |
| | | BigDecimal total = BigDecimal.ZERO; |
| | | for (Map.Entry<Integer, BigDecimal[]> entry : slots.entrySet()) { |
| | | if (entry.getKey() <= maxSlot) { |
| | | total = total.add(entry.getValue()[0]); |
| | | } |
| | | } |
| | | return total.setScale(3, RoundingMode.HALF_UP); |
| | | } |
| | | |
| | | private int lastDataSlot(Map<Integer, BigDecimal[]> slots) { |
| | | int last = 0; |
| | | for (Integer slot : slots.keySet()) { |
| | | if (slot > last) { |
| | | last = slot; |
| | | } |
| | | } |
| | | return last; |
| | | } |
| | | |
| | | /** æ¶é´çç»ææ¶é´ â 1..96ï¼24:00 记为第 96 çã */ |
| | | private int slotIndex(LocalDateTime time) { |
| | | int minute = time.getHour() * 60 + time.getMinute(); |
| | | if (minute == 0) { |
| | | return SLOT_COUNT; |
| | | } |
| | | return Math.min(SLOT_COUNT, Math.max(1, (minute + 14) / 15)); |
| | | } |
| | | |
| | | private String labelOfSlot(int slot) { |
| | | if (slot >= SLOT_COUNT) { |
| | | return "23:59"; |
| | | } |
| | | int minute = slot * 15; |
| | | return String.format("%02d:%02d", minute / 60, minute % 60); |
| | | } |
| | | |
| | | /* ------------------------------------------------------------------ */ |
| | | /* çµè½è´¨é */ |
| | | /* ------------------------------------------------------------------ */ |
| | | |
| | | private void fillQuality(ElectricMeterDashboardVO.Quality qualityVo, LocalDate start, LocalDate end, |
| | | int offset, List<MeterQuarterPoint> points) { |
| | | Map<LocalDateTime, BigDecimal[]> hourMap = new TreeMap<>(); |
| | | for (MeterQuarterPoint point : points) { |
| | | if (point.getTime() == null || point.getActive() == null) { |
| | | continue; |
| | | } |
| | | LocalDate day = point.getTime().toLocalDate(); |
| | | if (day.isBefore(start) || day.isAfter(end)) { |
| | | continue; |
| | | } |
| | | LocalDateTime hour = point.getTime().truncatedTo(ChronoUnit.HOURS); |
| | | BigDecimal[] values = hourMap.computeIfAbsent(hour, |
| | | key -> new BigDecimal[]{BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO}); |
| | | values[0] = values[0].add(point.getActive()); |
| | | values[1] = values[1].add(point.getReactive() == null ? BigDecimal.ZERO : point.getReactive()); |
| | | // è®°å½è¯¥å°æ¶å®é
æå 个 15 åéç¹ï¼æåä¸ä¸ªå°æ¶å¯è½è¿æ²¡èµ°å®ï¼ä¸è½ç´æ¥æ 1 å°æ¶å¹³å |
| | | values[2] = values[2].add(BigDecimal.ONE); |
| | | } |
| | | |
| | | List<ElectricMeterDashboardVO.PowerPoint> series = new ArrayList<>(hourMap.size()); |
| | | for (Map.Entry<LocalDateTime, BigDecimal[]> entry : hourMap.entrySet()) { |
| | | BigDecimal activeEnergy = entry.getValue()[0]; |
| | | BigDecimal reactiveEnergy = entry.getValue()[1]; |
| | | double hours = Math.max(entry.getValue()[2].doubleValue() * 0.25, 0.25); |
| | | double p = activeEnergy.doubleValue() / hours; |
| | | double q = reactiveEnergy.doubleValue() / hours; |
| | | ElectricMeterDashboardVO.PowerPoint powerPoint = new ElectricMeterDashboardVO.PowerPoint(); |
| | | powerPoint.setTime(entry.getKey().format(LABEL_FORMAT)); |
| | | powerPoint.setActivePower(BigDecimal.valueOf(p).setScale(3, RoundingMode.HALF_UP)); |
| | | powerPoint.setReactivePower(BigDecimal.valueOf(q).setScale(3, RoundingMode.HALF_UP)); |
| | | if (p > 0 || q > 0) { |
| | | double factor = p / Math.sqrt(p * p + q * q); |
| | | powerPoint.setPowerFactor(BigDecimal.valueOf(Math.min(factor, 1.0)) |
| | | .setScale(3, RoundingMode.HALF_UP)); |
| | | } |
| | | series.add(powerPoint); |
| | | } |
| | | |
| | | qualityVo.setWeekStart(start.format(DAY_FORMAT)); |
| | | qualityVo.setWeekEnd(end.format(DAY_FORMAT)); |
| | | qualityVo.setLabel(offset == 1 ? "ä¸ä¸å¨" : "è¿ä¸å¨"); |
| | | qualityVo.setSeries(series); |
| | | } |
| | | |
| | | private void fillEmptyQuality(ElectricMeterDashboardVO.Quality qualityVo, LocalDate start, LocalDate end, |
| | | int offset) { |
| | | qualityVo.setWeekStart(start.format(DAY_FORMAT)); |
| | | qualityVo.setWeekEnd(end.format(DAY_FORMAT)); |
| | | qualityVo.setLabel(offset == 1 ? "ä¸ä¸å¨" : "è¿ä¸å¨"); |
| | | qualityVo.setSeries(new ArrayList<>()); |
| | | } |
| | | |
| | | /* ------------------------------------------------------------------ */ |
| | | /* æ°æ®è·å */ |
| | | /* ------------------------------------------------------------------ */ |
| | | |
| | | private List<MeterQuarterPoint> queryDevices(List<EnergyMeterDevice> devices, LocalDate start, LocalDate end) { |
| | | List<MeterQuarterPoint> all = new ArrayList<>(); |
| | | for (EnergyMeterDevice device : devices) { |
| | | // æå·¥æè¡¨è®¾å¤æ²¡æ 15 åéæ°æ®ï¼ä¸åèµ·ç¬¬ä¸æ¹è¯·æ± |
| | | if (EnergyMeterConstants.isManual(device.getSourceType())) { |
| | | continue; |
| | | } |
| | | try { |
| | | all.addAll(queryDevice(device, start, end)); |
| | | } catch (MeterProviderException e) { |
| | | // åå°è®¾å¤å¤±è´¥ä¸å½±åå
¶ä»è®¾å¤ï¼é¡µé¢ä»ç¶å±ç¤ºå·²ææ°æ® |
| | | log.warn("çµè¡¨çæ¿æ¥è¯¢ 15 åéæ°æ®å¤±è´¥ meterId={} {}~{}: {}", |
| | | device.getId(), start, end, e.getMessage()); |
| | | } |
| | | } |
| | | return all; |
| | | } |
| | | |
| | | private List<MeterQuarterPoint> queryDevice(EnergyMeterDevice device, LocalDate start, LocalDate end) { |
| | | String key = device.getId() + ":" + start + ":" + end; |
| | | CachedPoints cached = cache.get(key); |
| | | long now = System.currentTimeMillis(); |
| | | if (cached != null && now - cached.at < CACHE_TTL_MS) { |
| | | return cached.points; |
| | | } |
| | | List<MeterQuarterPoint> points = provider.queryQuarterUsage(EnergyMeterConstants.TYPE_ELECTRIC, |
| | | device.getMeterAddress(), device.getProviderMeterId(), start, end); |
| | | // ç¬¬ä¸æ¹è¿åçéä¿¡å°åå¿
须䏿¬å°ç»å®ä¸è´ï¼é¿å
æå«ç表ç®è¿æ¥ |
| | | String expected = StringUtils.trim(device.getMeterAddress()); |
| | | if (StringUtils.isNotBlank(expected)) { |
| | | points.removeIf(point -> StringUtils.isNotBlank(point.getAddress()) |
| | | && !expected.equals(StringUtils.trim(point.getAddress()))); |
| | | } |
| | | if (cache.size() > 128) { |
| | | cache.clear(); |
| | | } |
| | | cache.put(key, new CachedPoints(now, points)); |
| | | return points; |
| | | } |
| | | |
| | | private List<EnergyMeterDevice> resolveDevices(Long meterId) { |
| | | if (meterId != null) { |
| | | EnergyMeterDevice device = deviceMapper.selectById(meterId); |
| | | if (device == null) { |
| | | throw new ServiceException("设å¤ä¸å卿已å é¤"); |
| | | } |
| | | if (!EnergyMeterConstants.isElectric(device.getMeterType())) { |
| | | throw new ServiceException("该设å¤ä¸æ¯çµè¡¨"); |
| | | } |
| | | Long tenantId = EnergyMeterSupport.currentTenantId(); |
| | | if (tenantId != null && device.getTenantId() != null && !tenantId.equals(device.getTenantId())) { |
| | | throw new ServiceException("æ æè®¿é®è¯¥è®¾å¤"); |
| | | } |
| | | return List.of(device); |
| | | } |
| | | LambdaQueryWrapper<EnergyMeterDevice> wrapper = new LambdaQueryWrapper<>(); |
| | | Long tenantId = EnergyMeterSupport.currentTenantId(); |
| | | if (tenantId != null) { |
| | | wrapper.eq(EnergyMeterDevice::getTenantId, tenantId); |
| | | } |
| | | wrapper.eq(EnergyMeterDevice::getMeterType, EnergyMeterConstants.TYPE_ELECTRIC) |
| | | .eq(EnergyMeterDevice::getEnabled, 1) |
| | | .eq(EnergyMeterDevice::getBindStatus, EnergyMeterConstants.BIND_VERIFIED) |
| | | .orderByAsc(EnergyMeterDevice::getId); |
| | | return deviceMapper.selectList(wrapper); |
| | | } |
| | | |
| | | private String scopeLabel(List<EnergyMeterDevice> devices, Long meterId) { |
| | | if (meterId != null && !devices.isEmpty()) { |
| | | EnergyMeterDevice device = devices.get(0); |
| | | return device.getDisplayName() + "ï¼" + device.getMeterAddress() + "ï¼"; |
| | | } |
| | | return "å
¨é¨å·²ç»å®çµè¡¨ï¼" + devices.size() + " å°ï¼"; |
| | | } |
| | | |
| | | private record CachedPoints(long at, List<MeterQuarterPoint> points) { |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.service.impl; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.ruoyi.energymeter.constant.EnergyMeterConstants; |
| | | import com.ruoyi.energymeter.mapper.EnergyMeterDeviceMapper; |
| | | import com.ruoyi.energymeter.mapper.EnergyMeterMeasurementMapper; |
| | | import com.ruoyi.energymeter.pojo.EnergyMeterDevice; |
| | | import com.ruoyi.energymeter.pojo.EnergyMeterMeasurement; |
| | | import com.ruoyi.energymeter.service.EnergyMeterDemoService; |
| | | import com.ruoyi.energymeter.util.EnergyMeterSupport; |
| | | import lombok.RequiredArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.math.RoundingMode; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * æ¼ç¤ºæ°æ®å®ç°ï¼æ°è¡¨æå¤©çææ¨¡æè¡¨ç ä¸ç¨éã |
| | | * |
| | | * <p>模æå¼æ¯â设å¤ID + æ¥æâçç¡®å®æ§å½æ°ï¼éå¤çæåä¸å¤©ç»æä¸è´ï¼ä¾¿äºæ ¸å¯¹ã</p> |
| | | */ |
| | | @Slf4j |
| | | @Service |
| | | @RequiredArgsConstructor |
| | | public class EnergyMeterDemoServiceImpl implements EnergyMeterDemoService { |
| | | |
| | | private final EnergyMeterDeviceMapper deviceMapper; |
| | | private final EnergyMeterMeasurementMapper measurementMapper; |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public int generateGasDemo(LocalDate date) { |
| | | if (date == null) { |
| | | return 0; |
| | | } |
| | | LambdaQueryWrapper<EnergyMeterDevice> wrapper = new LambdaQueryWrapper<>(); |
| | | wrapper.eq(EnergyMeterDevice::getMeterType, EnergyMeterConstants.TYPE_GAS) |
| | | .eq(EnergyMeterDevice::getSimulated, 1) |
| | | .eq(EnergyMeterDevice::getEnabled, 1); |
| | | List<EnergyMeterDevice> devices = deviceMapper.selectList(wrapper); |
| | | if (devices.isEmpty()) { |
| | | return 0; |
| | | } |
| | | |
| | | int generated = 0; |
| | | LocalDateTime measureTime = date.atStartOfDay(); |
| | | for (EnergyMeterDevice device : devices) { |
| | | if (hasUsage(device.getId(), measureTime)) { |
| | | // æ°æ®å·²å卿¶åªå·æ°ééæ¶é´ï¼ä¿è¯âæè¿éé/å¨çº¿âåæ æè¿ä¸æ¬¡èªå¨çæ |
| | | deviceMapper.markCollectSuccess(device.getId(), EnergyMeterSupport.now()); |
| | | continue; |
| | | } |
| | | BigDecimal usage = simulatedUsage(device.getId(), date); |
| | | BigDecimal previous = previousReading(device, measureTime); |
| | | BigDecimal reading = previous.add(usage); |
| | | |
| | | EnergyMeterMeasurement usagePoint = new EnergyMeterMeasurement(); |
| | | usagePoint.setTenantId(device.getTenantId()); |
| | | usagePoint.setMeterId(device.getId()); |
| | | usagePoint.setMetricCode(EnergyMeterConstants.METRIC_GAS_USAGE); |
| | | usagePoint.setGranularity(EnergyMeterConstants.GRANULARITY_DAY); |
| | | usagePoint.setMeasureTime(measureTime); |
| | | usagePoint.setMetricValue(usage); |
| | | usagePoint.setUnit(EnergyMeterConstants.UNIT_GAS); |
| | | usagePoint.setSourceApi(EnergyMeterConstants.SOURCE_MANUAL); |
| | | usagePoint.setSourceRecordTime(measureTime); |
| | | usagePoint.setCollectedAt(EnergyMeterSupport.now()); |
| | | usagePoint.setRemark("æ¨¡ææ°æ®ï¼æ¯æ¥ç¨é"); |
| | | |
| | | EnergyMeterMeasurement readingPoint = new EnergyMeterMeasurement(); |
| | | readingPoint.setTenantId(device.getTenantId()); |
| | | readingPoint.setMeterId(device.getId()); |
| | | readingPoint.setMetricCode(EnergyMeterConstants.METRIC_GAS_READING); |
| | | readingPoint.setGranularity(EnergyMeterConstants.GRANULARITY_POINT); |
| | | readingPoint.setMeasureTime(measureTime); |
| | | readingPoint.setMetricValue(reading); |
| | | readingPoint.setUnit(EnergyMeterConstants.UNIT_GAS); |
| | | readingPoint.setSourceApi(EnergyMeterConstants.SOURCE_MANUAL); |
| | | readingPoint.setSourceRecordTime(measureTime); |
| | | readingPoint.setCollectedAt(EnergyMeterSupport.now()); |
| | | readingPoint.setRemark("æ¨¡ææ°æ®ï¼æ¯æ¥è¡¨ç "); |
| | | |
| | | measurementMapper.upsertBatch(List.of(usagePoint, readingPoint)); |
| | | |
| | | // ééæ¶é´æå®é
æ§è¡æ¶é´è®°å½ï¼è䏿¯æ°æ®æå±æ¥æç 00:00 |
| | | deviceMapper.markCollectSuccess(device.getId(), EnergyMeterSupport.now()); |
| | | generated++; |
| | | } |
| | | log.info("æ°è¡¨æ¼ç¤ºæ°æ®çæå®æ date={} è®¾å¤æ°={}", date, generated); |
| | | return generated; |
| | | } |
| | | |
| | | private boolean hasUsage(Long meterId, LocalDateTime measureTime) { |
| | | LambdaQueryWrapper<EnergyMeterMeasurement> wrapper = new LambdaQueryWrapper<>(); |
| | | wrapper.eq(EnergyMeterMeasurement::getMeterId, meterId) |
| | | .eq(EnergyMeterMeasurement::getMetricCode, EnergyMeterConstants.METRIC_GAS_USAGE) |
| | | .eq(EnergyMeterMeasurement::getMeasureTime, measureTime); |
| | | return measurementMapper.selectCount(wrapper) > 0; |
| | | } |
| | | |
| | | /** |
| | | * ä¸ä¸æè¡¨ç ï¼åè¯¥æ¥æä¹åçæè¿ä¸æ¡ç¤ºå¼ï¼æ²¡æå°±ç¨è®¾å¤èµ·å§è¡¨ç ã |
| | | */ |
| | | private BigDecimal previousReading(EnergyMeterDevice device, LocalDateTime measureTime) { |
| | | EnergyMeterMeasurement previous = measurementMapper.selectPreviousPoint(device.getId(), |
| | | EnergyMeterConstants.METRIC_GAS_READING, measureTime); |
| | | if (previous != null && previous.getMetricValue() != null) { |
| | | return previous.getMetricValue(); |
| | | } |
| | | return device.getInitialReading() == null ? BigDecimal.ZERO : device.getInitialReading(); |
| | | } |
| | | |
| | | /** |
| | | * ç¡®å®æ§æ¨¡æç¨éï¼æé£ååè¸ç
®/çèçå®é
ç¨æ°éä¼°ç®ã |
| | | * |
| | | * <p>ä¼°ç®å£å¾ï¼è¸ç
®é
æ 4~6 m³/hãæ¯å¤© 6~8 å°æ¶ï¼åå°çº¦ 25~35 m³/å¤©ï¼ |
| | | * çèé
ãå°ç
®é
约 14~20 m³/天ãåºç¡å¼æè®¾å¤åºåï¼åå å å£èæ³¢å¨ä¸åªç¹ã</p> |
| | | */ |
| | | private BigDecimal simulatedUsage(Long meterId, LocalDate date) { |
| | | long seed = meterId * 131L + date.toEpochDay(); |
| | | double base = 14 + (meterId % 5) * 5; |
| | | double season = base * 0.1 * Math.sin(2 * Math.PI * date.getDayOfYear() / 365); |
| | | double noise = ((seed * 37 % 200) / 200.0 - 0.5) * 3; |
| | | double usage = Math.max(2, base + season + noise); |
| | | return BigDecimal.valueOf(usage).setScale(2, RoundingMode.HALF_UP); |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.service.impl; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import com.ruoyi.common.exception.ServiceException; |
| | | import com.ruoyi.common.utils.StringUtils; |
| | | import com.ruoyi.energymeter.constant.EnergyMeterConstants; |
| | | import com.ruoyi.energymeter.dto.EnergyMeterDeviceQuery; |
| | | import com.ruoyi.energymeter.dto.MeterArchive; |
| | | import com.ruoyi.energymeter.dto.MeterBindRequest; |
| | | import com.ruoyi.energymeter.dto.MeterManualBindRequest; |
| | | import com.ruoyi.energymeter.dto.MeterReadingRequest; |
| | | import com.ruoyi.energymeter.dto.MeterUpdateRequest; |
| | | import com.ruoyi.energymeter.dto.MeterUsageRow; |
| | | import com.ruoyi.energymeter.mapper.EnergyMeterDeviceMapper; |
| | | import com.ruoyi.energymeter.mapper.EnergyMeterMeasurementMapper; |
| | | import com.ruoyi.energymeter.mapper.EnergyMeterSyncTaskMapper; |
| | | import com.ruoyi.energymeter.pojo.EnergyMeterDevice; |
| | | import com.ruoyi.energymeter.pojo.EnergyMeterMeasurement; |
| | | import com.ruoyi.energymeter.pojo.EnergyMeterSyncTask; |
| | | import com.ruoyi.energymeter.provider.MeterProviderClient; |
| | | import com.ruoyi.energymeter.service.EnergyMeterDeviceService; |
| | | import com.ruoyi.energymeter.service.EnergyMeterSyncService; |
| | | import com.ruoyi.energymeter.util.EnergyMeterSupport; |
| | | import com.ruoyi.energymeter.vo.MeterArchiveVO; |
| | | import com.ruoyi.energymeter.vo.MeterReadingResultVO; |
| | | import lombok.RequiredArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | import java.util.ArrayList; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Set; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * è½èè¡¨è®¾å¤æå¡å®ç°ï¼ç¬¬ä¸æ¹æ¥å
¥è®¾å¤ + æå·¥æè¡¨è®¾å¤ã |
| | | */ |
| | | @Slf4j |
| | | @Service |
| | | @RequiredArgsConstructor |
| | | public class EnergyMeterDeviceServiceImpl extends ServiceImpl<EnergyMeterDeviceMapper, EnergyMeterDevice> |
| | | implements EnergyMeterDeviceService { |
| | | |
| | | private final EnergyMeterDeviceMapper deviceMapper; |
| | | private final EnergyMeterMeasurementMapper measurementMapper; |
| | | private final EnergyMeterSyncTaskMapper taskMapper; |
| | | private final MeterProviderClient provider; |
| | | private final EnergyMeterSyncService syncService; |
| | | |
| | | @Override |
| | | public IPage<EnergyMeterDevice> pageDevices(Page<EnergyMeterDevice> page, EnergyMeterDeviceQuery query) { |
| | | LambdaQueryWrapper<EnergyMeterDevice> wrapper = new LambdaQueryWrapper<>(); |
| | | Long tenantId = EnergyMeterSupport.currentTenantId(); |
| | | if (tenantId != null) { |
| | | wrapper.eq(EnergyMeterDevice::getTenantId, tenantId); |
| | | } |
| | | if (query != null) { |
| | | if (StringUtils.isNotBlank(query.getMeterType())) { |
| | | wrapper.eq(EnergyMeterDevice::getMeterType, normalizeType(query.getMeterType())); |
| | | } |
| | | if (StringUtils.isNotBlank(query.getSourceType())) { |
| | | wrapper.eq(EnergyMeterDevice::getSourceType, query.getSourceType().trim().toUpperCase()); |
| | | } |
| | | if (StringUtils.isNotBlank(query.getMeterAddress())) { |
| | | wrapper.eq(EnergyMeterDevice::getMeterAddress, query.getMeterAddress().trim()); |
| | | } |
| | | if (query.getEnabled() != null) { |
| | | wrapper.eq(EnergyMeterDevice::getEnabled, query.getEnabled()); |
| | | } |
| | | if (query.getSimulated() != null) { |
| | | wrapper.eq(EnergyMeterDevice::getSimulated, query.getSimulated()); |
| | | } |
| | | if (StringUtils.isNotBlank(query.getCollectionMode())) { |
| | | String mode = query.getCollectionMode().trim().toUpperCase(); |
| | | if ("AUTO".equals(mode)) { |
| | | // ç¬¬ä¸æ¹æ¥å
¥ + ç³»ç»æ¯æ¥èªå¨çæï¼é½å±äºèªå¨éé |
| | | wrapper.and(w -> w.eq(EnergyMeterDevice::getSourceType, |
| | | EnergyMeterConstants.SOURCE_TYPE_PROVIDER) |
| | | .or().eq(EnergyMeterDevice::getSimulated, 1)); |
| | | } else if ("MANUAL".equals(mode)) { |
| | | wrapper.eq(EnergyMeterDevice::getSourceType, EnergyMeterConstants.SOURCE_TYPE_MANUAL) |
| | | .eq(EnergyMeterDevice::getSimulated, 0); |
| | | } |
| | | } |
| | | if (StringUtils.isNotBlank(query.getBindStatus())) { |
| | | wrapper.eq(EnergyMeterDevice::getBindStatus, query.getBindStatus()); |
| | | } |
| | | if (StringUtils.isNotBlank(query.getKeyword())) { |
| | | String keyword = query.getKeyword().trim(); |
| | | wrapper.and(w -> w.like(EnergyMeterDevice::getDisplayName, keyword) |
| | | .or().like(EnergyMeterDevice::getProviderName, keyword) |
| | | .or().like(EnergyMeterDevice::getMeterAddress, keyword)); |
| | | } |
| | | } |
| | | wrapper.orderByAsc(EnergyMeterDevice::getMeterType) |
| | | .orderByDesc(EnergyMeterDevice::getIsSeed) |
| | | .orderByAsc(EnergyMeterDevice::getId); |
| | | IPage<EnergyMeterDevice> result = deviceMapper.selectPage(page, wrapper); |
| | | enrichDevices(result.getRecords()); |
| | | return result; |
| | | } |
| | | |
| | | @Override |
| | | public List<EnergyMeterDevice> listDeviceOptions(String meterType) { |
| | | LambdaQueryWrapper<EnergyMeterDevice> wrapper = new LambdaQueryWrapper<>(); |
| | | Long tenantId = EnergyMeterSupport.currentTenantId(); |
| | | if (tenantId != null) { |
| | | wrapper.eq(EnergyMeterDevice::getTenantId, tenantId); |
| | | } |
| | | if (StringUtils.isNotBlank(meterType)) { |
| | | wrapper.eq(EnergyMeterDevice::getMeterType, normalizeType(meterType)); |
| | | } |
| | | wrapper.eq(EnergyMeterDevice::getEnabled, 1) |
| | | .eq(EnergyMeterDevice::getBindStatus, EnergyMeterConstants.BIND_VERIFIED) |
| | | .orderByAsc(EnergyMeterDevice::getId); |
| | | return deviceMapper.selectList(wrapper); |
| | | } |
| | | |
| | | @Override |
| | | public MeterArchiveVO verifyArchive(String meterType, String meterAddress) { |
| | | String normalizedType = normalizeType(meterType); |
| | | String address = StringUtils.trim(meterAddress); |
| | | if (StringUtils.isBlank(address)) { |
| | | throw new ServiceException("éä¿¡å°åä¸è½ä¸ºç©º"); |
| | | } |
| | | MeterArchive archive = provider.queryArchive(normalizedType, address); |
| | | MeterArchiveVO vo = new MeterArchiveVO(); |
| | | vo.setMeterType(normalizedType); |
| | | vo.setMeterAddress(address); |
| | | vo.setProviderMeterId(archive.getProviderMeterId()); |
| | | vo.setProviderName(archive.getProviderName()); |
| | | vo.setAreaId(archive.getAreaId()); |
| | | vo.setAreaName(archive.getAreaName()); |
| | | vo.setOnlineStatus(archive.getOnlineStatus()); |
| | | vo.setParentProviderId(archive.getParentProviderId()); |
| | | vo.setMockMode(provider.mockMode()); |
| | | |
| | | EnergyMeterDevice existing = findBinding(normalizedType, address); |
| | | if (existing == null) { |
| | | vo.setBindable(true); |
| | | vo.setMessage("éªè¯éè¿ï¼å¯æ°å¢ç»å®"); |
| | | } else { |
| | | vo.setExistingDeviceId(existing.getId()); |
| | | vo.setExistingEnabled(Integer.valueOf(1).equals(existing.getEnabled())); |
| | | boolean enabled = Integer.valueOf(1).equals(existing.getEnabled()); |
| | | vo.setBindable(!enabled); |
| | | vo.setMessage(enabled |
| | | ? "该éä¿¡å°å已卿¬å°ç»å®ï¼è¯·å¿é夿°å¢" |
| | | : "该å°åå·²åå¨åç¨è®¾å¤ï¼ç¡®è®¤åå°éæ°å¯ç¨å¹¶è¡¥éåç¨æé´æ°æ®"); |
| | | } |
| | | return vo; |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public EnergyMeterDevice bind(MeterBindRequest request) { |
| | | String normalizedType = normalizeType(request.getMeterType()); |
| | | String address = StringUtils.trim(request.getMeterAddress()); |
| | | if (StringUtils.isBlank(address)) { |
| | | throw new ServiceException("éä¿¡å°åä¸è½ä¸ºç©º"); |
| | | } |
| | | MeterArchive archive = provider.queryArchive(normalizedType, address); |
| | | EnergyMeterDevice existing = findBinding(normalizedType, address); |
| | | if (existing != null && Integer.valueOf(1).equals(existing.getEnabled())) { |
| | | throw new ServiceException("该éä¿¡å°å已卿¬å°ç»å®ï¼è¯·å¿é夿°å¢"); |
| | | } |
| | | if (existing != null && EnergyMeterConstants.isManual(existing.getSourceType())) { |
| | | throw new ServiceException("该表å·å·²ç¨äºæå·¥æè¡¨è®¾å¤ï¼è¯·å
å é¤åè®¾å¤ææ¹ç¨å
¶ä»è¡¨å·"); |
| | | } |
| | | LocalDate yesterday = EnergyMeterSupport.today().minusDays(1); |
| | | // ééèµ·ç¹ç±ç³»ç»èªå¨ç¡®å®ï¼å·²åç¨è®¾å¤æ²¿ç¨åèµ·ç¹ï¼æ°è®¾å¤é»è®¤ä¸ä¸èªç¶å¹´ 1 æ 1 æ¥ |
| | | LocalDate startDate = resolveStartDate(null, |
| | | existing != null ? existing.getSyncStartDate() : null, yesterday); |
| | | |
| | | EnergyMeterDevice device = existing == null ? new EnergyMeterDevice() : existing; |
| | | device.setMeterType(normalizedType); |
| | | device.setSourceType(EnergyMeterConstants.SOURCE_TYPE_PROVIDER); |
| | | device.setMeterAddress(address); |
| | | device.setProviderMeterId(archive.getProviderMeterId()); |
| | | device.setProviderName(archive.getProviderName()); |
| | | device.setProviderAreaId(archive.getAreaId()); |
| | | device.setProviderAreaName(archive.getAreaName()); |
| | | device.setParentProviderId(archive.getParentProviderId()); |
| | | device.setOnlineStatus(archive.getOnlineStatus()); |
| | | device.setBindStatus(EnergyMeterConstants.BIND_VERIFIED); |
| | | device.setEnabled(1); |
| | | device.setSyncStartDate(startDate); |
| | | device.setDisplayName(StringUtils.isNotBlank(request.getDisplayName()) |
| | | ? request.getDisplayName().trim() |
| | | : StringUtils.defaultIfBlank(archive.getProviderName(), address)); |
| | | device.setLocation(StringUtils.defaultIfBlank(request.getLocation(), device.getLocation())); |
| | | if (device.getIsSeed() == null) { |
| | | device.setIsSeed(0); |
| | | } |
| | | if (existing == null) { |
| | | deviceMapper.insert(device); |
| | | } else { |
| | | deviceMapper.updateById(device); |
| | | } |
| | | log.info("è½è表ç»å®æå meterId={} type={} address={}", device.getId(), normalizedType, address); |
| | | |
| | | try { |
| | | syncService.triggerBackfill(device, startDate, yesterday); |
| | | } catch (Exception e) { |
| | | log.warn("ç»å®æåä½åå²è¡¥éæ¹æ¬¡å建失败 meterId={}: {}", device.getId(), e.getMessage()); |
| | | } |
| | | return device; |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public EnergyMeterDevice addManual(MeterManualBindRequest request) { |
| | | String type = normalizeType(request.getMeterType()); |
| | | String address = StringUtils.trim(request.getMeterAddress()); |
| | | if (StringUtils.isBlank(address)) { |
| | | throw new ServiceException("表å·ä¸è½ä¸ºç©º"); |
| | | } |
| | | if (request.getInitialReading() == null) { |
| | | throw new ServiceException("èµ·å§è¡¨ç ä¸è½ä¸ºç©º"); |
| | | } |
| | | if (request.getInitialReading().signum() < 0) { |
| | | throw new ServiceException("èµ·å§è¡¨ç ä¸è½ä¸ºè´æ°"); |
| | | } |
| | | LocalDate today = EnergyMeterSupport.today(); |
| | | LocalDate initialDate = request.getInitialReadingDate() == null ? today : request.getInitialReadingDate(); |
| | | if (initialDate.isAfter(today)) { |
| | | throw new ServiceException("èµ·å§è¡¨ç æ¥æä¸è½æäºä»å¤©"); |
| | | } |
| | | |
| | | EnergyMeterDevice existing = findBinding(type, address); |
| | | if (existing != null) { |
| | | if (Integer.valueOf(1).equals(existing.getEnabled())) { |
| | | throw new ServiceException("该表å·å·²å卿æç" + EnergyMeterConstants.typeName(type) + "设å¤ï¼è¯·å¿é夿°å¢"); |
| | | } |
| | | if (!EnergyMeterConstants.isManual(existing.getSourceType())) { |
| | | throw new ServiceException("该表å·å·²è¢«ç¬¬ä¸æ¹æ¥å
¥è®¾å¤å ç¨ï¼è¯·å
åç¨åè®¾å¤ææ¹ç¨å
¶ä»è¡¨å·"); |
| | | } |
| | | } |
| | | |
| | | EnergyMeterDevice device = existing == null ? new EnergyMeterDevice() : existing; |
| | | device.setMeterType(type); |
| | | device.setSourceType(EnergyMeterConstants.SOURCE_TYPE_MANUAL); |
| | | device.setMeterAddress(address); |
| | | device.setDisplayName(StringUtils.isNotBlank(request.getDisplayName()) |
| | | ? request.getDisplayName().trim() |
| | | : address); |
| | | device.setLocation(StringUtils.defaultIfBlank(request.getLocation(), device.getLocation())); |
| | | device.setBindStatus(EnergyMeterConstants.BIND_VERIFIED); |
| | | device.setEnabled(1); |
| | | device.setIsSeed(0); |
| | | device.setInitialReading(request.getInitialReading()); |
| | | device.setInitialReadingDate(initialDate); |
| | | device.setSyncStartDate(initialDate); |
| | | device.setOnlineStatus(null); |
| | | device.setLastErrorCode(null); |
| | | device.setLastErrorMessage(null); |
| | | if (existing == null) { |
| | | deviceMapper.insert(device); |
| | | } else { |
| | | deviceMapper.updateById(device); |
| | | } |
| | | |
| | | // èµ·å§è¡¨ç ä½ä¸ºåºåè®°å½åå
¥ï¼ä¸è®¡å
¥ç¨é |
| | | EnergyMeterMeasurement basePoint = newManualPoint(device, initialDate.atStartOfDay(), |
| | | request.getInitialReading(), "èµ·å§è¡¨ç "); |
| | | measurementMapper.upsertBatch(List.of(basePoint)); |
| | | deviceMapper.markCollectSuccess(device.getId(), EnergyMeterSupport.now()); |
| | | log.info("æ°å¢æå·¥æè¡¨è®¾å¤ meterId={} type={} address={} initial={}", |
| | | device.getId(), type, address, request.getInitialReading()); |
| | | return deviceMapper.selectById(device.getId()); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void removeDevice(Long id) { |
| | | EnergyMeterDevice device = getOwnedDevice(id); |
| | | if (Integer.valueOf(1).equals(device.getIsSeed())) { |
| | | throw new ServiceException("åå§å设å¤ä¸å
许å é¤ï¼å¦éåç¨è¯·ç¼è¾è®¾å¤ç¶æ"); |
| | | } |
| | | if (!EnergyMeterConstants.isManual(device.getSourceType())) { |
| | | throw new ServiceException("ç¬¬ä¸æ¹æ¥å
¥è®¾å¤è¯·ä½¿ç¨âåç¨âï¼ä¸å
许å é¤"); |
| | | } |
| | | measurementMapper.delete(new LambdaQueryWrapper<EnergyMeterMeasurement>() |
| | | .eq(EnergyMeterMeasurement::getMeterId, id)); |
| | | removeById(id); |
| | | log.info("å 餿工æè¡¨è®¾å¤ meterId={} address={}", id, device.getMeterAddress()); |
| | | } |
| | | |
| | | @Override |
| | | public IPage<EnergyMeterMeasurement> pageReadings(Long meterId, long current, long size) { |
| | | EnergyMeterDevice device = getOwnedDevice(meterId); |
| | | String readingMetric = EnergyMeterConstants.readingMetric(device.getMeterType()); |
| | | String usageMetric = EnergyMeterConstants.usageMetric(device.getMeterType()); |
| | | long safeSize = Math.min(Math.max(size, 1), 200); |
| | | Page<EnergyMeterMeasurement> page = new Page<>(Math.max(current, 1), safeSize); |
| | | LambdaQueryWrapper<EnergyMeterMeasurement> wrapper = new LambdaQueryWrapper<>(); |
| | | wrapper.eq(EnergyMeterMeasurement::getMeterId, device.getId()) |
| | | .eq(EnergyMeterMeasurement::getMetricCode, readingMetric) |
| | | .eq(EnergyMeterMeasurement::getGranularity, EnergyMeterConstants.GRANULARITY_POINT) |
| | | .orderByDesc(EnergyMeterMeasurement::getMeasureTime) |
| | | .orderByDesc(EnergyMeterMeasurement::getId); |
| | | IPage<EnergyMeterMeasurement> result = measurementMapper.selectPage(page, wrapper); |
| | | |
| | | List<EnergyMeterMeasurement> records = result.getRecords(); |
| | | if (!records.isEmpty()) { |
| | | LocalDateTime maxTime = records.get(0).getMeasureTime(); |
| | | LocalDateTime minTime = records.get(records.size() - 1).getMeasureTime(); |
| | | List<EnergyMeterMeasurement> usages = measurementMapper.selectList( |
| | | new LambdaQueryWrapper<EnergyMeterMeasurement>() |
| | | .eq(EnergyMeterMeasurement::getMeterId, device.getId()) |
| | | .eq(EnergyMeterMeasurement::getMetricCode, usageMetric) |
| | | .eq(EnergyMeterMeasurement::getGranularity, EnergyMeterConstants.GRANULARITY_DAY) |
| | | .ge(EnergyMeterMeasurement::getMeasureTime, minTime) |
| | | .le(EnergyMeterMeasurement::getMeasureTime, maxTime)); |
| | | Map<LocalDate, BigDecimal> usageMap = new HashMap<>(); |
| | | for (EnergyMeterMeasurement usage : usages) { |
| | | usageMap.put(usage.getMeasureTime().toLocalDate(), usage.getMetricValue()); |
| | | } |
| | | for (EnergyMeterMeasurement record : records) { |
| | | record.setUsageValue(usageMap.get(record.getMeasureTime().toLocalDate())); |
| | | record.setMeterName(device.getDisplayName()); |
| | | record.setMeterType(device.getMeterType()); |
| | | record.setMeterAddress(device.getMeterAddress()); |
| | | } |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public MeterReadingResultVO addReading(Long meterId, MeterReadingRequest request) { |
| | | EnergyMeterDevice device = requireManualDevice(meterId); |
| | | if (request.getReadingDate() == null) { |
| | | throw new ServiceException("æè¡¨æ¥æä¸è½ä¸ºç©º"); |
| | | } |
| | | if (request.getReadingValue() == null) { |
| | | throw new ServiceException("æ¬æ¬¡è¡¨ç ä¸è½ä¸ºç©º"); |
| | | } |
| | | LocalDate date = request.getReadingDate(); |
| | | LocalDate today = EnergyMeterSupport.today(); |
| | | if (date.isAfter(today)) { |
| | | throw new ServiceException("æè¡¨æ¥æä¸è½æäºä»å¤©"); |
| | | } |
| | | if (device.getInitialReadingDate() != null && date.isBefore(device.getInitialReadingDate())) { |
| | | throw new ServiceException("æè¡¨æ¥æä¸è½æ©äºèµ·å§è¡¨ç æ¥æï¼" |
| | | + device.getInitialReadingDate() + "ï¼"); |
| | | } |
| | | BigDecimal value = request.getReadingValue(); |
| | | if (value.signum() < 0) { |
| | | throw new ServiceException("æ¬æ¬¡è¡¨ç ä¸è½ä¸ºè´æ°"); |
| | | } |
| | | |
| | | BigDecimal previous = resolvePreviousReading(device, date.atStartOfDay()); |
| | | if (previous != null && value.compareTo(previous) < 0) { |
| | | throw new ServiceException("æ¬æ¬¡è¡¨ç ä¸è½å°äºä¸æè¡¨ç ï¼ä¸æ " + previous.stripTrailingZeros().toPlainString() + "ï¼"); |
| | | } |
| | | |
| | | EnergyMeterMeasurement point = newManualPoint(device, date.atStartOfDay(), value, |
| | | StringUtils.defaultIfBlank(request.getRemark(), null)); |
| | | measurementMapper.upsertBatch(List.of(point)); |
| | | |
| | | BigDecimal usage = previous == null ? null : value.subtract(previous); |
| | | upsertUsage(device, date, usage); |
| | | |
| | | // è¥è¯¥æ¥æä¹åå·²ææè¡¨ï¼éæ°è®¡ç®ä¸ä¸æçç¨é |
| | | EnergyMeterMeasurement next = measurementMapper.selectNextPoint(device.getId(), |
| | | EnergyMeterConstants.readingMetric(device.getMeterType()), date.atStartOfDay()); |
| | | if (next != null) { |
| | | recalcUsage(device, next); |
| | | } |
| | | deviceMapper.markCollectSuccess(device.getId(), EnergyMeterSupport.now()); |
| | | |
| | | MeterReadingResultVO result = new MeterReadingResultVO(); |
| | | result.setMeterId(device.getId()); |
| | | result.setMeasureTime(date.atStartOfDay()); |
| | | result.setReadingValue(value); |
| | | result.setPreviousReading(previous); |
| | | result.setUsage(usage); |
| | | result.setUnit(EnergyMeterConstants.unit(device.getMeterType())); |
| | | return result; |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void removeReading(Long meterId, Long measurementId) { |
| | | EnergyMeterDevice device = requireManualDevice(meterId); |
| | | EnergyMeterMeasurement record = measurementMapper.selectById(measurementId); |
| | | if (record == null || !meterId.equals(record.getMeterId())) { |
| | | throw new ServiceException("æè¡¨è®°å½ä¸åå¨"); |
| | | } |
| | | if (!EnergyMeterConstants.GRANULARITY_POINT.equals(record.getGranularity())) { |
| | | throw new ServiceException("åªè½å é¤æè¡¨è®°å½"); |
| | | } |
| | | if (device.getInitialReadingDate() != null |
| | | && device.getInitialReadingDate().equals(record.getMeasureTime().toLocalDate())) { |
| | | throw new ServiceException("èµ·å§è¡¨ç ä¸å
许å é¤ï¼å¦éä¿®æ¹è¯·ç¼è¾è®¾å¤"); |
| | | } |
| | | |
| | | EnergyMeterMeasurement next = measurementMapper.selectNextPoint(device.getId(), |
| | | EnergyMeterConstants.readingMetric(device.getMeterType()), record.getMeasureTime()); |
| | | measurementMapper.deleteById(measurementId); |
| | | deleteUsage(device, record.getMeasureTime().toLocalDate()); |
| | | if (next != null) { |
| | | recalcUsage(device, next); |
| | | } |
| | | log.info("å é¤æè¡¨è®°å½ meterId={} measurementId={} date={}", |
| | | meterId, measurementId, record.getMeasureTime().toLocalDate()); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public EnergyMeterDevice updateLocal(Long id, MeterUpdateRequest request) { |
| | | EnergyMeterDevice device = getOwnedDevice(id); |
| | | LambdaUpdateWrapper<EnergyMeterDevice> wrapper = new LambdaUpdateWrapper<>(); |
| | | wrapper.eq(EnergyMeterDevice::getId, id); |
| | | if (request.getDisplayName() != null) { |
| | | if (StringUtils.isBlank(request.getDisplayName())) { |
| | | throw new ServiceException("æ¾ç¤ºåç§°ä¸è½ä¸ºç©º"); |
| | | } |
| | | wrapper.set(EnergyMeterDevice::getDisplayName, request.getDisplayName().trim()); |
| | | } |
| | | if (request.getLocation() != null) { |
| | | wrapper.set(EnergyMeterDevice::getLocation, request.getLocation()); |
| | | } |
| | | boolean reEnabled = false; |
| | | if (request.getEnabled() != null) { |
| | | if (request.getEnabled() != 0 && request.getEnabled() != 1) { |
| | | throw new ServiceException("å¯åç¨åæ°ä¸åæ³"); |
| | | } |
| | | reEnabled = request.getEnabled() == 1 && !Integer.valueOf(1).equals(device.getEnabled()); |
| | | wrapper.set(EnergyMeterDevice::getEnabled, request.getEnabled()); |
| | | } |
| | | deviceMapper.update(null, wrapper); |
| | | EnergyMeterDevice updated = getOwnedDevice(id); |
| | | if (reEnabled && !EnergyMeterConstants.isManual(updated.getSourceType())) { |
| | | try { |
| | | syncService.triggerBackfillGap(updated); |
| | | } catch (Exception e) { |
| | | log.warn("设å¤å¯ç¨æåä½è¡¥éæ¹æ¬¡å建失败 meterId={}: {}", id, e.getMessage()); |
| | | } |
| | | } |
| | | enrichDevices(List.of(updated)); |
| | | return updated; |
| | | } |
| | | |
| | | @Override |
| | | public EnergyMeterDevice getOwnedDevice(Long id) { |
| | | EnergyMeterDevice device = deviceMapper.selectById(id); |
| | | if (device == null) { |
| | | throw new ServiceException("设å¤ä¸å卿已å é¤"); |
| | | } |
| | | Long tenantId = EnergyMeterSupport.currentTenantId(); |
| | | if (tenantId != null && device.getTenantId() != null && !tenantId.equals(device.getTenantId())) { |
| | | throw new ServiceException("æ æè®¿é®è¯¥è®¾å¤"); |
| | | } |
| | | return device; |
| | | } |
| | | |
| | | @Override |
| | | public List<EnergyMeterDevice> listEnabledDevices(String meterType) { |
| | | LambdaQueryWrapper<EnergyMeterDevice> wrapper = new LambdaQueryWrapper<>(); |
| | | Long tenantId = EnergyMeterSupport.currentTenantId(); |
| | | if (tenantId != null) { |
| | | wrapper.eq(EnergyMeterDevice::getTenantId, tenantId); |
| | | } |
| | | if (StringUtils.isNotBlank(meterType)) { |
| | | wrapper.eq(EnergyMeterDevice::getMeterType, normalizeType(meterType)); |
| | | } |
| | | wrapper.eq(EnergyMeterDevice::getEnabled, 1) |
| | | .eq(EnergyMeterDevice::getBindStatus, EnergyMeterConstants.BIND_VERIFIED) |
| | | .orderByAsc(EnergyMeterDevice::getId); |
| | | return deviceMapper.selectList(wrapper); |
| | | } |
| | | |
| | | @Override |
| | | public boolean mockMode() { |
| | | return provider.mockMode(); |
| | | } |
| | | |
| | | /* ------------------------------------------------------------------ */ |
| | | |
| | | /** |
| | | * è®¡ç®æå®æ¥æä¹åçä¸ä¸æè¡¨ç ï¼ä¼å
åæè¡¨è®°å½ï¼å
¶æ¬¡å设å¤èµ·å§è¡¨ç ã |
| | | */ |
| | | private BigDecimal resolvePreviousReading(EnergyMeterDevice device, LocalDateTime time) { |
| | | EnergyMeterMeasurement previous = measurementMapper.selectPreviousPoint(device.getId(), |
| | | EnergyMeterConstants.readingMetric(device.getMeterType()), time); |
| | | if (previous != null) { |
| | | return previous.getMetricValue(); |
| | | } |
| | | return device.getInitialReading(); |
| | | } |
| | | |
| | | /** |
| | | * éç®ææ¡æè¡¨è®°å½å¯¹åºçæ¥ç¨éï¼å¨æå
¥/å é¤å
¶å®æè¡¨è®°å½åè°ç¨ï¼ã |
| | | */ |
| | | private void recalcUsage(EnergyMeterDevice device, EnergyMeterMeasurement point) { |
| | | BigDecimal previous = resolvePreviousReading(device, point.getMeasureTime()); |
| | | if (previous == null) { |
| | | deleteUsage(device, point.getMeasureTime().toLocalDate()); |
| | | return; |
| | | } |
| | | upsertUsage(device, point.getMeasureTime().toLocalDate(), point.getMetricValue().subtract(previous)); |
| | | } |
| | | |
| | | private void upsertUsage(EnergyMeterDevice device, LocalDate date, BigDecimal usage) { |
| | | if (usage == null) { |
| | | return; |
| | | } |
| | | EnergyMeterMeasurement record = new EnergyMeterMeasurement(); |
| | | record.setTenantId(device.getTenantId()); |
| | | record.setMeterId(device.getId()); |
| | | record.setMetricCode(EnergyMeterConstants.usageMetric(device.getMeterType())); |
| | | record.setGranularity(EnergyMeterConstants.GRANULARITY_DAY); |
| | | record.setMeasureTime(date.atStartOfDay()); |
| | | record.setMetricValue(usage); |
| | | record.setUnit(EnergyMeterConstants.unit(device.getMeterType())); |
| | | record.setSourceApi(EnergyMeterConstants.SOURCE_MANUAL); |
| | | record.setSourceRecordTime(date.atStartOfDay()); |
| | | record.setCollectedAt(EnergyMeterSupport.now()); |
| | | measurementMapper.upsertBatch(List.of(record)); |
| | | } |
| | | |
| | | private void deleteUsage(EnergyMeterDevice device, LocalDate date) { |
| | | measurementMapper.delete(new LambdaQueryWrapper<EnergyMeterMeasurement>() |
| | | .eq(EnergyMeterMeasurement::getMeterId, device.getId()) |
| | | .eq(EnergyMeterMeasurement::getMetricCode, EnergyMeterConstants.usageMetric(device.getMeterType())) |
| | | .eq(EnergyMeterMeasurement::getGranularity, EnergyMeterConstants.GRANULARITY_DAY) |
| | | .eq(EnergyMeterMeasurement::getMeasureTime, date.atStartOfDay())); |
| | | } |
| | | |
| | | private EnergyMeterMeasurement newManualPoint(EnergyMeterDevice device, LocalDateTime time, |
| | | BigDecimal value, String remark) { |
| | | EnergyMeterMeasurement point = new EnergyMeterMeasurement(); |
| | | point.setTenantId(device.getTenantId()); |
| | | point.setMeterId(device.getId()); |
| | | point.setMetricCode(EnergyMeterConstants.readingMetric(device.getMeterType())); |
| | | point.setGranularity(EnergyMeterConstants.GRANULARITY_POINT); |
| | | point.setMeasureTime(time); |
| | | point.setMetricValue(value); |
| | | point.setUnit(EnergyMeterConstants.unit(device.getMeterType())); |
| | | point.setSourceApi(EnergyMeterConstants.SOURCE_MANUAL); |
| | | point.setSourceRecordTime(time); |
| | | point.setCollectedAt(EnergyMeterSupport.now()); |
| | | point.setRemark(remark); |
| | | return point; |
| | | } |
| | | |
| | | private EnergyMeterDevice requireManualDevice(Long meterId) { |
| | | EnergyMeterDevice device = getOwnedDevice(meterId); |
| | | if (!EnergyMeterConstants.isManual(device.getSourceType())) { |
| | | throw new ServiceException("该设å¤ä¸ºç¬¬ä¸æ¹æ¥å
¥ï¼è¯·ä½¿ç¨âæ¥è¡¨âè·åæ°æ®"); |
| | | } |
| | | return device; |
| | | } |
| | | |
| | | private void enrichDevices(List<EnergyMeterDevice> devices) { |
| | | if (devices == null || devices.isEmpty()) { |
| | | return; |
| | | } |
| | | List<Long> ids = devices.stream().map(EnergyMeterDevice::getId).collect(Collectors.toList()); |
| | | Map<Long, EnergyMeterSyncTask> latestTask = new HashMap<>(); |
| | | for (EnergyMeterSyncTask task : taskMapper.selectLatestByMeterIds(ids)) { |
| | | latestTask.put(task.getMeterId(), task); |
| | | } |
| | | LocalDate yesterday = EnergyMeterSupport.today().minusDays(1); |
| | | LocalDateTime start = yesterday.atStartOfDay(); |
| | | LocalDateTime end = yesterday.plusDays(1).atStartOfDay(); |
| | | |
| | | Map<Long, BigDecimal> usageMap = new HashMap<>(); |
| | | Set<String> types = devices.stream().map(EnergyMeterDevice::getMeterType) |
| | | .filter(StringUtils::isNotBlank).collect(Collectors.toSet()); |
| | | for (String type : types) { |
| | | List<Long> typeIds = devices.stream() |
| | | .filter(d -> type.equals(d.getMeterType())) |
| | | .map(EnergyMeterDevice::getId).collect(Collectors.toList()); |
| | | if (typeIds.isEmpty()) { |
| | | continue; |
| | | } |
| | | for (MeterUsageRow row : measurementMapper.sumUsageByMeter(typeIds, |
| | | EnergyMeterConstants.usageMetric(type), start, end)) { |
| | | usageMap.put(row.getMeterId(), row.getTotal()); |
| | | } |
| | | } |
| | | |
| | | for (EnergyMeterDevice device : devices) { |
| | | boolean manual = EnergyMeterConstants.isManual(device.getSourceType()); |
| | | EnergyMeterSyncTask task = latestTask.get(device.getId()); |
| | | if (task != null) { |
| | | device.setLastTaskStatus(task.getStatus()); |
| | | device.setLastTaskTime(task.getFinishedAt() != null ? task.getFinishedAt() : task.getStartedAt()); |
| | | } |
| | | BigDecimal dayUsage = usageMap.get(device.getId()); |
| | | if (dayUsage != null) { |
| | | device.setLastDayUsage(dayUsage); |
| | | device.setLastDayUsageDate(yesterday); |
| | | } else { |
| | | // æ¨å¤©æ²¡æç¨éæ¶ï¼æå·¥æè¡¨ææè¡¨æå
¥è´¦ãç¬¬ä¸æ¹è®¾å¤å¯è½åªæå½å¤©æ°æ®ï¼ï¼ |
| | | // éåæè¿ä¸æ¡ç¨éåå
¶ä¸å¡æ¥æï¼é¿å
åè¡¨é¿ææ¾ç¤º "--" |
| | | EnergyMeterMeasurement latestUsage = measurementMapper.selectLatestPoint(device.getId(), |
| | | EnergyMeterConstants.usageMetric(device.getMeterType())); |
| | | if (latestUsage != null) { |
| | | device.setLastDayUsage(latestUsage.getMetricValue()); |
| | | device.setLastDayUsageDate(latestUsage.getMeasureTime().toLocalDate()); |
| | | } |
| | | } |
| | | EnergyMeterMeasurement latest = measurementMapper.selectLatestPoint(device.getId(), |
| | | EnergyMeterConstants.readingMetric(device.getMeterType())); |
| | | if (latest != null) { |
| | | device.setLatestReading(latest.getMetricValue()); |
| | | EnergyMeterMeasurement previous = measurementMapper.selectPreviousPoint(device.getId(), |
| | | EnergyMeterConstants.readingMetric(device.getMeterType()), latest.getMeasureTime()); |
| | | if (previous != null) { |
| | | device.setPreviousReading(previous.getMetricValue()); |
| | | } else if (device.getLastDayUsage() != null) { |
| | | // åªæä¸æ¡è¯»æ°æ¶ï¼æ°è£
表第ä¸å¤©ï¼ï¼ç¨âææ°è¡¨ç - 彿ç¨éâåæ¨ä¸æè¡¨ç |
| | | device.setPreviousReading(latest.getMetricValue().subtract(device.getLastDayUsage())); |
| | | } |
| | | } |
| | | device.setCollectStateText(buildCollectState(device, task)); |
| | | device.setMeterTypeName(EnergyMeterConstants.typeName(device.getMeterType())); |
| | | device.setSourceTypeName(EnergyMeterConstants.isAutoCollect(device.getSourceType(), device.getSimulated()) |
| | | ? "èªå¨éé" : "æå·¥æè¡¨"); |
| | | device.setUnit(EnergyMeterConstants.unit(device.getMeterType())); |
| | | device.setDeletable(!Integer.valueOf(1).equals(device.getIsSeed()) && manual); |
| | | } |
| | | } |
| | | |
| | | private String buildCollectState(EnergyMeterDevice device, EnergyMeterSyncTask task) { |
| | | if (EnergyMeterConstants.isSimulated(device.getSimulated())) { |
| | | return "èªå¨éé"; |
| | | } |
| | | if (EnergyMeterConstants.isManual(device.getSourceType())) { |
| | | return device.getLastSuccessAt() == null ? "å°æªæè¡¨" : "æå·¥æè¡¨"; |
| | | } |
| | | if (task == null) { |
| | | return "å°æªéé"; |
| | | } |
| | | return switch (StringUtils.defaultString(task.getStatus())) { |
| | | case "SUCCESS" -> "ééæå"; |
| | | case "EMPTY" -> "ç¡®è®¤æ æ°æ®"; |
| | | case "FAILED" -> "éé失败"; |
| | | case "RETRY" -> "çå¾
éè¯"; |
| | | case "RUNNING" -> "ééä¸"; |
| | | default -> "å¾
æ§è¡"; |
| | | }; |
| | | } |
| | | |
| | | private EnergyMeterDevice findBinding(String meterType, String address) { |
| | | LambdaQueryWrapper<EnergyMeterDevice> wrapper = new LambdaQueryWrapper<>(); |
| | | wrapper.eq(EnergyMeterDevice::getMeterType, meterType) |
| | | .eq(EnergyMeterDevice::getMeterAddress, address); |
| | | Long tenantId = EnergyMeterSupport.currentTenantId(); |
| | | if (tenantId != null) { |
| | | wrapper.eq(EnergyMeterDevice::getTenantId, tenantId); |
| | | } |
| | | List<EnergyMeterDevice> list = deviceMapper.selectList(wrapper); |
| | | return list.isEmpty() ? null : list.get(0); |
| | | } |
| | | |
| | | private LocalDate resolveStartDate(LocalDate requested, LocalDate existingStart, LocalDate yesterday) { |
| | | LocalDate latestAllowed = yesterday; |
| | | LocalDate defaultStart = LocalDate.of(latestAllowed.getYear() - 1, 1, 1); |
| | | LocalDate start = requested != null ? requested : (existingStart != null ? existingStart : defaultStart); |
| | | if (start.isAfter(latestAllowed)) { |
| | | throw new ServiceException("è¡¥éèµ·å§æ¥æä¸è½æäºæ¨å¤©"); |
| | | } |
| | | if (start.isBefore(LocalDate.of(2000, 1, 1))) { |
| | | throw new ServiceException("è¡¥éèµ·å§æ¥æè¿æ©ï¼è¯·ç¡®è®¤ä¾åºåå
许çåå²èå´"); |
| | | } |
| | | return start; |
| | | } |
| | | |
| | | |
| | | private String normalizeType(String meterType) { |
| | | String type = EnergyMeterConstants.canonicalType(meterType); |
| | | if (type == null) { |
| | | throw new ServiceException("è½æºç±»ååªæ¯ææ°´è¡¨ï¼WATERï¼ãçµè¡¨ï¼ELECTRICï¼ææ°è¡¨ï¼GASï¼"); |
| | | } |
| | | return type; |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.service.impl; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.ruoyi.common.exception.ServiceException; |
| | | import com.ruoyi.common.utils.StringUtils; |
| | | import com.ruoyi.energymeter.constant.EnergyMeterConstants; |
| | | import com.ruoyi.energymeter.dto.DailyUsageRow; |
| | | import com.ruoyi.energymeter.dto.DataRangeRow; |
| | | import com.ruoyi.energymeter.dto.MonthlyUsageRow; |
| | | import com.ruoyi.energymeter.mapper.EnergyMeterDeviceMapper; |
| | | import com.ruoyi.energymeter.mapper.EnergyMeterMeasurementMapper; |
| | | import com.ruoyi.energymeter.pojo.EnergyMeterDevice; |
| | | import com.ruoyi.energymeter.pojo.EnergyMeterMeasurement; |
| | | import com.ruoyi.energymeter.provider.MeterProviderClient; |
| | | import com.ruoyi.energymeter.service.EnergyMeterStatService; |
| | | import com.ruoyi.energymeter.util.EnergyMeterSupport; |
| | | import com.ruoyi.energymeter.vo.EnergyMeterOverviewVO; |
| | | import lombok.RequiredArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.math.RoundingMode; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | import java.time.YearMonth; |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.util.ArrayList; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * æ¦è§ç»è®¡å®ç°ã |
| | | * |
| | | * <p>åªä» D ç²åº¦ç *_USAGE ææ æ±æ»ï¼ç»ä¸ç´¯å POINT 表ç ï¼ç¼ºå¤±æ¥æä¿æ nullï¼ç±å端æ¾ç¤ºç¼ºå£ã</p> |
| | | */ |
| | | @Slf4j |
| | | @Service |
| | | @RequiredArgsConstructor |
| | | public class EnergyMeterStatServiceImpl implements EnergyMeterStatService { |
| | | |
| | | private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd"); |
| | | |
| | | private final EnergyMeterDeviceMapper deviceMapper; |
| | | private final EnergyMeterMeasurementMapper measurementMapper; |
| | | private final MeterProviderClient provider; |
| | | |
| | | @Override |
| | | public EnergyMeterOverviewVO overview(String meterType, Long meterId, String month, Integer year) { |
| | | String type = normalizeType(meterType); |
| | | YearMonth selectedMonth = parseMonth(month); |
| | | int selectedYear = year == null ? selectedMonth.getYear() : year; |
| | | if (selectedYear < 2000 || selectedYear > 2100) { |
| | | throw new ServiceException("年份ä¸åæ³"); |
| | | } |
| | | |
| | | EnergyMeterOverviewVO vo = new EnergyMeterOverviewVO(); |
| | | vo.setMeterType(type); |
| | | vo.setMetricCode(EnergyMeterConstants.usageMetric(type)); |
| | | vo.setUnit(EnergyMeterConstants.unit(type)); |
| | | vo.setMeterId(meterId); |
| | | vo.setMockMode(provider.mockMode()); |
| | | vo.setSelectedMonth(selectedMonth.toString()); |
| | | vo.setSelectedYear(String.valueOf(selectedYear)); |
| | | vo.setMonthCost(null); |
| | | vo.setYearCost(null); |
| | | |
| | | List<EnergyMeterDevice> devices = resolveDevices(type, meterId); |
| | | vo.setDeviceCount(devices.size()); |
| | | vo.setScopeLabel(buildScopeLabel(devices, meterId)); |
| | | List<Long> meterIds = devices.stream().map(EnergyMeterDevice::getId).collect(Collectors.toList()); |
| | | |
| | | LocalDate today = EnergyMeterSupport.today(); |
| | | LocalDate yesterday = today.minusDays(1); |
| | | LocalDate monthStart = selectedMonth.atDay(1); |
| | | LocalDate monthEndExclusive = selectedMonth.plusMonths(1).atDay(1); |
| | | YearMonth previousMonth = selectedMonth.minusMonths(1); |
| | | |
| | | Map<LocalDate, BigDecimal> currentDaily = toDayMap(monthIdsEmpty(meterIds) ? List.of() : measurementMapper.sumDailyUsage( |
| | | meterIds, vo.getMetricCode(), monthStart.atStartOfDay(), monthEndExclusive.atStartOfDay())); |
| | | Map<LocalDate, BigDecimal> previousDaily = toDayMap(monthIdsEmpty(meterIds) ? List.of() : measurementMapper.sumDailyUsage( |
| | | meterIds, vo.getMetricCode(), previousMonth.atDay(1).atStartOfDay(), monthStart.atStartOfDay())); |
| | | |
| | | int daysInMonth = selectedMonth.lengthOfMonth(); |
| | | int daysInPreviousMonth = previousMonth.lengthOfMonth(); |
| | | int cutDay = resolveCutDay(selectedMonth, today); |
| | | |
| | | List<EnergyMeterOverviewVO.MonthDayPoint> monthSeries = new ArrayList<>(daysInMonth); |
| | | BigDecimal monthTotal = BigDecimal.ZERO; |
| | | int collectedDays = 0; |
| | | for (int day = 1; day <= daysInMonth; day++) { |
| | | LocalDate date = monthStart.withDayOfMonth(day); |
| | | BigDecimal currentValue = currentDaily.get(date); |
| | | if (currentValue != null) { |
| | | monthTotal = monthTotal.add(currentValue); |
| | | if (day <= cutDay) { |
| | | collectedDays++; |
| | | } |
| | | } |
| | | EnergyMeterOverviewVO.MonthDayPoint point = new EnergyMeterOverviewVO.MonthDayPoint(); |
| | | point.setDay(date.format(DATE_FORMAT)); |
| | | point.setCurrent(currentValue); |
| | | point.setPrevious(day <= daysInPreviousMonth ? previousDaily.get(previousMonth.atDay(day)) : null); |
| | | monthSeries.add(point); |
| | | } |
| | | vo.setMonthSeries(monthSeries); |
| | | boolean monthHasData = !currentDaily.isEmpty(); |
| | | vo.setMonthHasData(monthHasData); |
| | | vo.setMonthTotal(monthHasData ? monthTotal : null); |
| | | |
| | | BigDecimal previousTotal = BigDecimal.ZERO; |
| | | int previousDayCount = 0; |
| | | int compareDays = Math.min(cutDay, daysInPreviousMonth); |
| | | for (int day = 1; day <= compareDays; day++) { |
| | | BigDecimal value = previousDaily.get(previousMonth.atDay(day)); |
| | | if (value != null) { |
| | | previousTotal = previousTotal.add(value); |
| | | previousDayCount++; |
| | | } |
| | | } |
| | | vo.setMonthPreviousTotal(previousDayCount > 0 ? previousTotal : null); |
| | | |
| | | int expectedDays = cutDay; |
| | | // 设å¤å
¥ç½ä¹åçæ¥æä¸åºè®¡å
¥ç¼ºå£ï¼ä»è®¾å¤åæ¥èµ·ç¹ä¸æåçè¾å¤§è
å¼å§ç® |
| | | if (!devices.isEmpty()) { |
| | | LocalDate earliestSync = devices.stream() |
| | | .map(EnergyMeterDevice::getSyncStartDate) |
| | | .filter(java.util.Objects::nonNull) |
| | | .min(LocalDate::compareTo) |
| | | .orElse(null); |
| | | if (earliestSync != null && earliestSync.isAfter(monthStart)) { |
| | | int days = (int) java.time.temporal.ChronoUnit.DAYS.between(earliestSync, |
| | | monthStart.plusDays(cutDay)); |
| | | expectedDays = Math.max(0, Math.min(days, cutDay)); |
| | | } |
| | | } |
| | | vo.setCollectedDays(collectedDays); |
| | | vo.setExpectedDays(expectedDays); |
| | | vo.setCoverageRate(expectedDays <= 0 ? BigDecimal.valueOf(100) |
| | | : BigDecimal.valueOf(collectedDays * 100.0 / expectedDays).setScale(1, RoundingMode.HALF_UP)); |
| | | |
| | | java.time.LocalDate yearStart = LocalDate.of(selectedYear, 1, 1); |
| | | java.time.LocalDate yearEndExclusive = yearStart.plusYears(1); |
| | | java.time.LocalDate previousYearStart = yearStart.minusYears(1); |
| | | Map<String, BigDecimal> currentMonthly = toMonthMap(monthIdsEmpty(meterIds) ? List.of() |
| | | : measurementMapper.sumMonthlyUsage(meterIds, vo.getMetricCode(), |
| | | yearStart.atStartOfDay(), yearEndExclusive.atStartOfDay())); |
| | | Map<String, BigDecimal> previousMonthly = toMonthMap(monthIdsEmpty(meterIds) ? List.of() |
| | | : measurementMapper.sumMonthlyUsage(meterIds, vo.getMetricCode(), |
| | | previousYearStart.atStartOfDay(), yearStart.atStartOfDay())); |
| | | boolean yearHasData = !currentMonthly.isEmpty(); |
| | | vo.setYearHasData(yearHasData); |
| | | |
| | | int currentYear = today.getYear(); |
| | | int cutMonth = selectedYear < currentYear ? 12 : (selectedYear > currentYear ? 0 : today.getMonthValue()); |
| | | List<EnergyMeterOverviewVO.YearMonthPoint> yearSeries = new ArrayList<>(12); |
| | | BigDecimal yearTotal = BigDecimal.ZERO; |
| | | for (int m = 1; m <= 12; m++) { |
| | | String key = selectedYear + "-" + String.format("%02d", m); |
| | | String previousKey = (selectedYear - 1) + "-" + String.format("%02d", m); |
| | | BigDecimal currentValue = currentMonthly.get(key); |
| | | if (currentValue != null) { |
| | | yearTotal = yearTotal.add(currentValue); |
| | | } |
| | | EnergyMeterOverviewVO.YearMonthPoint point = new EnergyMeterOverviewVO.YearMonthPoint(); |
| | | point.setMonth(key); |
| | | point.setCurrent(currentValue); |
| | | point.setPrevious(previousMonthly.get(previousKey)); |
| | | yearSeries.add(point); |
| | | } |
| | | vo.setYearSeries(yearSeries); |
| | | vo.setYearTotal(yearHasData ? yearTotal : null); |
| | | |
| | | BigDecimal previousYearTotal = BigDecimal.ZERO; |
| | | int previousMonthCount = 0; |
| | | for (int m = 1; m <= cutMonth; m++) { |
| | | BigDecimal value = previousMonthly.get((selectedYear - 1) + "-" + String.format("%02d", m)); |
| | | if (value != null) { |
| | | previousYearTotal = previousYearTotal.add(value); |
| | | previousMonthCount++; |
| | | } |
| | | } |
| | | vo.setYearPreviousTotal(previousMonthCount > 0 ? previousYearTotal : null); |
| | | |
| | | DataRangeRow range = monthIdsEmpty(meterIds) ? null |
| | | : measurementMapper.selectDataRange(meterIds, vo.getMetricCode()); |
| | | vo.setDataStart(range != null && range.getMinTime() != null ? range.getMinTime().toLocalDate().format(DATE_FORMAT) : null); |
| | | vo.setDataEnd(range != null && range.getMaxTime() != null ? range.getMaxTime().toLocalDate().format(DATE_FORMAT) : null); |
| | | vo.setDataThrough(yesterday.format(DATE_FORMAT)); |
| | | |
| | | LocalDateTime lastSuccess = devices.stream() |
| | | .map(EnergyMeterDevice::getLastSuccessAt) |
| | | .filter(java.util.Objects::nonNull) |
| | | .max(LocalDateTime::compareTo) |
| | | .orElse(null); |
| | | vo.setLastSuccessAt(lastSuccess == null ? null : lastSuccess.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); |
| | | |
| | | boolean hasData = monthHasData || yearHasData || range != null && range.getMaxTime() != null; |
| | | vo.setHasData(hasData); |
| | | long manualCount = devices.stream() |
| | | .filter(d -> EnergyMeterConstants.isManual(d.getSourceType())) |
| | | .count(); |
| | | boolean manualOnly = !devices.isEmpty() && manualCount == devices.size(); |
| | | int expectedForStatus = expectedDays; |
| | | if (manualOnly) { |
| | | // æå·¥æè¡¨æâæè¡¨ææ°â计ï¼ä¸æèªç¶æ¥ç®ç¼ºå£ |
| | | vo.setExpectedDays(collectedDays); |
| | | vo.setCoverageRate(collectedDays > 0 ? BigDecimal.valueOf(100) : BigDecimal.ZERO); |
| | | expectedForStatus = collectedDays; |
| | | } |
| | | applySyncStatus(vo, hasData, lastSuccess, collectedDays, expectedForStatus, monthHasData, yearHasData, manualOnly); |
| | | return vo; |
| | | } |
| | | |
| | | @Override |
| | | public IPage<EnergyMeterMeasurement> pageMeasurements(Long meterId, String metricCode, String granularity, |
| | | LocalDate start, LocalDate end, long current, long size) { |
| | | EnergyMeterDevice device = requireDevice(meterId); |
| | | long safeSize = Math.min(Math.max(size, 1), 200); |
| | | Page<EnergyMeterMeasurement> page = new Page<>(Math.max(current, 1), safeSize); |
| | | LambdaQueryWrapper<EnergyMeterMeasurement> wrapper = new LambdaQueryWrapper<>(); |
| | | wrapper.eq(EnergyMeterMeasurement::getMeterId, device.getId()); |
| | | if (StringUtils.isNotBlank(metricCode)) { |
| | | wrapper.eq(EnergyMeterMeasurement::getMetricCode, metricCode); |
| | | } |
| | | if (StringUtils.isNotBlank(granularity)) { |
| | | wrapper.eq(EnergyMeterMeasurement::getGranularity, granularity); |
| | | } |
| | | if (start != null) { |
| | | wrapper.ge(EnergyMeterMeasurement::getMeasureTime, start.atStartOfDay()); |
| | | } |
| | | if (end != null) { |
| | | wrapper.lt(EnergyMeterMeasurement::getMeasureTime, end.plusDays(1).atStartOfDay()); |
| | | } |
| | | wrapper.orderByDesc(EnergyMeterMeasurement::getMeasureTime) |
| | | .orderByDesc(EnergyMeterMeasurement::getId); |
| | | IPage<EnergyMeterMeasurement> result = measurementMapper.selectPage(page, wrapper); |
| | | result.getRecords().forEach(item -> { |
| | | item.setMeterName(device.getDisplayName()); |
| | | item.setMeterType(device.getMeterType()); |
| | | item.setMeterAddress(device.getMeterAddress()); |
| | | }); |
| | | return result; |
| | | } |
| | | |
| | | /* ------------------------------------------------------------------ */ |
| | | |
| | | private List<EnergyMeterDevice> resolveDevices(String meterType, Long meterId) { |
| | | if (meterId != null) { |
| | | EnergyMeterDevice device = requireDevice(meterId); |
| | | if (!meterType.equals(device.getMeterType())) { |
| | | throw new ServiceException("设å¤ç±»åä¸å½åè½æºç±»åä¸ä¸è´"); |
| | | } |
| | | return List.of(device); |
| | | } |
| | | LambdaQueryWrapper<EnergyMeterDevice> wrapper = new LambdaQueryWrapper<>(); |
| | | Long tenantId = EnergyMeterSupport.currentTenantId(); |
| | | if (tenantId != null) { |
| | | wrapper.eq(EnergyMeterDevice::getTenantId, tenantId); |
| | | } |
| | | wrapper.eq(EnergyMeterDevice::getMeterType, meterType) |
| | | .eq(EnergyMeterDevice::getEnabled, 1) |
| | | .eq(EnergyMeterDevice::getBindStatus, EnergyMeterConstants.BIND_VERIFIED) |
| | | .orderByAsc(EnergyMeterDevice::getId); |
| | | return deviceMapper.selectList(wrapper); |
| | | } |
| | | |
| | | private EnergyMeterDevice requireDevice(Long meterId) { |
| | | if (meterId == null) { |
| | | throw new ServiceException("设å¤IDä¸è½ä¸ºç©º"); |
| | | } |
| | | EnergyMeterDevice device = deviceMapper.selectById(meterId); |
| | | if (device == null) { |
| | | throw new ServiceException("设å¤ä¸å卿已å é¤"); |
| | | } |
| | | Long tenantId = EnergyMeterSupport.currentTenantId(); |
| | | if (tenantId != null && device.getTenantId() != null && !tenantId.equals(device.getTenantId())) { |
| | | throw new ServiceException("æ æè®¿é®è¯¥è®¾å¤"); |
| | | } |
| | | return device; |
| | | } |
| | | |
| | | private String buildScopeLabel(List<EnergyMeterDevice> devices, Long meterId) { |
| | | if (meterId != null && !devices.isEmpty()) { |
| | | EnergyMeterDevice device = devices.get(0); |
| | | return device.getDisplayName() + "ï¼" + device.getMeterAddress() + "ï¼"; |
| | | } |
| | | return "å
¨é¨å·²ç»å®è®¾å¤ï¼" + devices.size() + " å°ï¼"; |
| | | } |
| | | |
| | | private void applySyncStatus(EnergyMeterOverviewVO vo, boolean hasData, LocalDateTime lastSuccess, |
| | | int collectedDays, int expectedDays, boolean monthHasData, boolean yearHasData, |
| | | boolean manualOnly) { |
| | | String status; |
| | | String text; |
| | | if (manualOnly) { |
| | | if (!monthHasData && !yearHasData) { |
| | | status = "EMPTY"; |
| | | text = "ææ æè¡¨è®°å½"; |
| | | } else if (expectedDays > 0 && collectedDays < expectedDays) { |
| | | status = "PARTIAL"; |
| | | text = "æè¡¨æ°æ®åå¨ç¼ºå£ï¼" + collectedDays + "/" + expectedDays + " 天ï¼"; |
| | | } else { |
| | | status = "OK"; |
| | | text = "æå·¥æè¡¨æ°æ®"; |
| | | } |
| | | vo.setSyncStatus(status); |
| | | vo.setSyncStatusText(text); |
| | | return; |
| | | } |
| | | if (!monthHasData && !yearHasData) { |
| | | status = "EMPTY"; |
| | | text = "ææ ééæ°æ®"; |
| | | } else if (!hasData) { |
| | | status = "EMPTY"; |
| | | text = "ææ ééæ°æ®"; |
| | | } else if (lastSuccess == null |
| | | || lastSuccess.isBefore(EnergyMeterSupport.now().minusHours(36))) { |
| | | status = "STALE"; |
| | | text = "è¶
è¿ 36 å°æ¶æ æåéé"; |
| | | } else if (expectedDays > 0 && collectedDays < expectedDays) { |
| | | status = "PARTIAL"; |
| | | text = "æ°æ®åå¨ç¼ºå£ï¼" + collectedDays + "/" + expectedDays + " 天ï¼"; |
| | | } else { |
| | | status = "OK"; |
| | | text = "æ°æ®å®æ´"; |
| | | } |
| | | vo.setSyncStatus(status); |
| | | vo.setSyncStatusText(text); |
| | | } |
| | | |
| | | private int resolveCutDay(YearMonth month, LocalDate today) { |
| | | YearMonth currentMonth = YearMonth.from(today); |
| | | if (month.isAfter(currentMonth)) { |
| | | return 0; |
| | | } |
| | | if (month.equals(currentMonth)) { |
| | | return Math.max(today.minusDays(1).getDayOfMonth(), 0); |
| | | } |
| | | return month.lengthOfMonth(); |
| | | } |
| | | |
| | | private Map<LocalDate, BigDecimal> toDayMap(List<DailyUsageRow> rows) { |
| | | Map<LocalDate, BigDecimal> map = new HashMap<>(); |
| | | for (DailyUsageRow row : rows) { |
| | | if (row.getDay() != null && row.getTotal() != null) { |
| | | map.put(LocalDate.parse(row.getDay()), row.getTotal()); |
| | | } |
| | | } |
| | | return map; |
| | | } |
| | | |
| | | private Map<String, BigDecimal> toMonthMap(List<MonthlyUsageRow> rows) { |
| | | Map<String, BigDecimal> map = new HashMap<>(); |
| | | for (MonthlyUsageRow row : rows) { |
| | | if (row.getMonth() != null && row.getTotal() != null) { |
| | | map.put(row.getMonth(), row.getTotal()); |
| | | } |
| | | } |
| | | return map; |
| | | } |
| | | |
| | | private boolean monthIdsEmpty(List<Long> ids) { |
| | | return ids == null || ids.isEmpty(); |
| | | } |
| | | |
| | | private YearMonth parseMonth(String month) { |
| | | if (StringUtils.isBlank(month)) { |
| | | return YearMonth.now(EnergyMeterConstants.ZONE); |
| | | } |
| | | try { |
| | | return YearMonth.parse(month.trim()); |
| | | } catch (Exception e) { |
| | | throw new ServiceException("æä»½æ ¼å¼åºä¸º yyyy-MM"); |
| | | } |
| | | } |
| | | |
| | | private String normalizeType(String meterType) { |
| | | String type = EnergyMeterConstants.canonicalType(meterType); |
| | | if (type == null) { |
| | | throw new ServiceException("è½æºç±»ååªæ¯ææ°´è¡¨ï¼WATERï¼ãçµè¡¨ï¼ELECTRICï¼ææ°è¡¨ï¼GASï¼"); |
| | | } |
| | | return type; |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.service.impl; |
| | | |
| | | import com.ruoyi.common.exception.ServiceException; |
| | | import com.ruoyi.common.utils.StringUtils; |
| | | import com.ruoyi.energymeter.config.EnergyMeterProperties; |
| | | import com.ruoyi.energymeter.constant.EnergyMeterConstants; |
| | | import com.ruoyi.energymeter.dto.MeterReadingPoint; |
| | | import com.ruoyi.energymeter.dto.MeterUsagePoint; |
| | | import com.ruoyi.energymeter.dto.TaskStatusCount; |
| | | import com.ruoyi.energymeter.mapper.EnergyMeterDeviceMapper; |
| | | import com.ruoyi.energymeter.mapper.EnergyMeterMeasurementMapper; |
| | | import com.ruoyi.energymeter.mapper.EnergyMeterSyncCheckpointMapper; |
| | | import com.ruoyi.energymeter.mapper.EnergyMeterSyncRunMapper; |
| | | import com.ruoyi.energymeter.mapper.EnergyMeterSyncTaskMapper; |
| | | import com.ruoyi.energymeter.pojo.EnergyMeterDevice; |
| | | import com.ruoyi.energymeter.pojo.EnergyMeterMeasurement; |
| | | import com.ruoyi.energymeter.pojo.EnergyMeterSyncCheckpoint; |
| | | import com.ruoyi.energymeter.pojo.EnergyMeterSyncRun; |
| | | import com.ruoyi.energymeter.pojo.EnergyMeterSyncTask; |
| | | import com.ruoyi.energymeter.provider.MeterProviderClient; |
| | | import com.ruoyi.energymeter.provider.MeterProviderException; |
| | | import com.ruoyi.energymeter.service.EnergyMeterSyncService; |
| | | import com.ruoyi.energymeter.util.EnergyMeterSupport; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Qualifier; |
| | | import org.springframework.dao.DuplicateKeyException; |
| | | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.PlatformTransactionManager; |
| | | import org.springframework.transaction.support.TransactionSynchronization; |
| | | import org.springframework.transaction.support.TransactionSynchronizationManager; |
| | | import org.springframework.transaction.support.TransactionTemplate; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.time.temporal.ChronoUnit; |
| | | import java.util.ArrayList; |
| | | import java.util.Comparator; |
| | | import java.util.HashMap; |
| | | import java.util.LinkedHashMap; |
| | | import java.util.LinkedHashSet; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Set; |
| | | import java.util.UUID; |
| | | import java.util.concurrent.CompletableFuture; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * åæ¥ç¼æï¼æ¹æ¬¡å建ã任塿§è¡ãå¹çè½åºãè¿åº¦æ¨è¿ä¸å¤±è´¥éè¯ã |
| | | * |
| | | * <p>å¤é¨ HTTP è°ç¨ä¸æ¾å¨æ°æ®åºäºå¡ä¸ï¼åå
¥ééè¡¨ãæ´æ°ä»»å¡åè¿åº¦å¨çäºå¡å
æäº¤ã</p> |
| | | */ |
| | | @Slf4j |
| | | @Service |
| | | public class EnergyMeterSyncServiceImpl implements EnergyMeterSyncService { |
| | | |
| | | private static final int UPSERT_CHUNK = 500; |
| | | |
| | | private final EnergyMeterDeviceMapper deviceMapper; |
| | | private final EnergyMeterMeasurementMapper measurementMapper; |
| | | private final EnergyMeterSyncRunMapper runMapper; |
| | | private final EnergyMeterSyncTaskMapper taskMapper; |
| | | private final EnergyMeterSyncCheckpointMapper checkpointMapper; |
| | | private final MeterProviderClient provider; |
| | | private final EnergyMeterProperties properties; |
| | | private final TransactionTemplate transactionTemplate; |
| | | private final ThreadPoolTaskExecutor taskExecutor; |
| | | private final ThreadPoolTaskExecutor runExecutor; |
| | | |
| | | public EnergyMeterSyncServiceImpl(EnergyMeterDeviceMapper deviceMapper, |
| | | EnergyMeterMeasurementMapper measurementMapper, |
| | | EnergyMeterSyncRunMapper runMapper, |
| | | EnergyMeterSyncTaskMapper taskMapper, |
| | | EnergyMeterSyncCheckpointMapper checkpointMapper, |
| | | MeterProviderClient provider, |
| | | EnergyMeterProperties properties, |
| | | PlatformTransactionManager transactionManager, |
| | | @Qualifier("energyMeterSyncExecutor") ThreadPoolTaskExecutor taskExecutor, |
| | | @Qualifier("energyMeterRunExecutor") ThreadPoolTaskExecutor runExecutor) { |
| | | this.deviceMapper = deviceMapper; |
| | | this.measurementMapper = measurementMapper; |
| | | this.runMapper = runMapper; |
| | | this.taskMapper = taskMapper; |
| | | this.checkpointMapper = checkpointMapper; |
| | | this.provider = provider; |
| | | this.properties = properties; |
| | | this.transactionTemplate = new TransactionTemplate(transactionManager); |
| | | this.taskExecutor = taskExecutor; |
| | | this.runExecutor = runExecutor; |
| | | } |
| | | |
| | | /* ------------------------------------------------------------------ */ |
| | | /* æ¹æ¬¡å建 */ |
| | | /* ------------------------------------------------------------------ */ |
| | | |
| | | @Override |
| | | public Long triggerScheduledSync() { |
| | | if (!provider.mockMode() && !provider.hasApiKey()) { |
| | | log.warn("æªé
ç½®ç¬¬ä¸æ¹ææç ï¼NH_ENERGY_API_KEYï¼ï¼è·³è¿æ¯æ¥èªå¨åæ¥"); |
| | | return null; |
| | | } |
| | | LocalDate today = EnergyMeterSupport.today(); |
| | | LocalDate target = today.minusDays(1); |
| | | String runKey = EnergyMeterConstants.AUTO_RUN_KEY_PREFIX |
| | | + today.format(DateTimeFormatter.BASIC_ISO_DATE); |
| | | EnergyMeterSyncRun existing = runMapper.selectByRunKey(runKey); |
| | | if (existing != null) { |
| | | log.info("å½å¤©èªå¨åæ¥æ¹æ¬¡å·²åå¨ï¼è·³è¿éå¤è§¦å runKey={}", runKey); |
| | | return existing.getId(); |
| | | } |
| | | |
| | | EnergyMeterSyncRun run = newRun(EnergyMeterConstants.RUN_SCHEDULED, runKey, today, target, target); |
| | | try { |
| | | runMapper.insert(run); |
| | | } catch (DuplicateKeyException e) { |
| | | EnergyMeterSyncRun duplicated = runMapper.selectByRunKey(runKey); |
| | | log.info("å¹¶å触åèªå¨åæ¥ï¼å¤ç¨å·²ææ¹æ¬¡ runKey={}", runKey); |
| | | return duplicated == null ? null : duplicated.getId(); |
| | | } |
| | | |
| | | List<EnergyMeterDevice> devices = deviceMapper.selectScannableDevices(); |
| | | LocalDate minStart = target; |
| | | int taskCount = 0; |
| | | for (EnergyMeterDevice device : devices) { |
| | | LocalDate start = resolveAutoStart(device, target); |
| | | if (start == null) { |
| | | continue; |
| | | } |
| | | if (start.isBefore(minStart)) { |
| | | minStart = start; |
| | | } |
| | | taskCount += createDeviceTasks(run.getId(), device, start, target, properties.isRawReadingEnabled()); |
| | | } |
| | | applyRunRange(run, minStart, target, taskCount); |
| | | log.info("èªå¨åæ¥æ¹æ¬¡åå»ºå®æ runKey={} è®¾å¤æ°={} 任塿°={}", runKey, devices.size(), taskCount); |
| | | |
| | | if (taskCount == 0) { |
| | | EnergyMeterSyncRun finished = new EnergyMeterSyncRun(); |
| | | finished.setId(run.getId()); |
| | | finished.setStatus(EnergyMeterConstants.RUN_SUCCESS); |
| | | finished.setFinishedAt(EnergyMeterSupport.now()); |
| | | runMapper.updateById(finished); |
| | | return run.getId(); |
| | | } |
| | | executeRunAfterCommit(run.getId()); |
| | | return run.getId(); |
| | | } |
| | | |
| | | @Override |
| | | public void triggerBackfill(EnergyMeterDevice device, LocalDate start, LocalDate end) { |
| | | if (device == null || start == null || end == null || start.isAfter(end)) { |
| | | return; |
| | | } |
| | | if (EnergyMeterConstants.isManual(device.getSourceType())) { |
| | | log.info("æå·¥æè¡¨è®¾å¤ä¸åå»ºè¡¥éæ¹æ¬¡ meterId={}", device.getId()); |
| | | return; |
| | | } |
| | | if (!provider.mockMode() && !provider.hasApiKey()) { |
| | | log.warn("æªé
ç½®ç¬¬ä¸æ¹ææç ï¼è·³è¿è¡¥é meterId={}", device.getId()); |
| | | return; |
| | | } |
| | | EnergyMeterSyncRun run = newRun(EnergyMeterConstants.RUN_BACKFILL, |
| | | "BACKFILL:" + UUID.randomUUID(), null, start, end); |
| | | runMapper.insert(run); |
| | | int taskCount = createDeviceTasks(run.getId(), device, start, end, properties.isRawReadingEnabled()); |
| | | applyRunRange(run, start, end, taskCount); |
| | | log.info("åå²è¡¥éæ¹æ¬¡åå»ºå®æ meterId={} range={}~{} tasks={}", device.getId(), start, end, taskCount); |
| | | if (taskCount > 0) { |
| | | executeRunAfterCommit(run.getId()); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public Long triggerBackfillGap(EnergyMeterDevice device) { |
| | | if (device == null) { |
| | | return null; |
| | | } |
| | | if (EnergyMeterConstants.isManual(device.getSourceType())) { |
| | | log.info("æå·¥æè¡¨è®¾å¤ä¸åä¸ç¼ºå£è¡¥é meterId={}", device.getId()); |
| | | return null; |
| | | } |
| | | if (!provider.mockMode() && !provider.hasApiKey()) { |
| | | log.warn("æªé
ç½®ç¬¬ä¸æ¹ææç ï¼è·³è¿ç¼ºå£è¡¥é meterId={}", device.getId()); |
| | | return null; |
| | | } |
| | | LocalDate target = EnergyMeterSupport.today().minusDays(1); |
| | | LocalDate base = device.getSyncStartDate() != null |
| | | ? device.getSyncStartDate() |
| | | : LocalDate.of(target.getYear() - 1, 1, 1); |
| | | EnergyMeterSyncCheckpoint checkpoint = checkpointMapper.selectUnit(device.getId(), |
| | | EnergyMeterConstants.usageSource(device.getMeterType()), EnergyMeterConstants.GRANULARITY_DAY); |
| | | LocalDate start = base; |
| | | if (checkpoint != null && checkpoint.getLastCompleteDate() != null) { |
| | | start = checkpoint.getLastCompleteDate().plusDays(1); |
| | | } |
| | | if (start.isBefore(base)) { |
| | | start = base; |
| | | } |
| | | if (start.isAfter(target)) { |
| | | log.info("è®¾å¤ {} æ 缺å£éè¦è¡¥é", device.getId()); |
| | | return null; |
| | | } |
| | | EnergyMeterSyncRun run = newRun(EnergyMeterConstants.RUN_BACKFILL, |
| | | "BACKFILL:" + UUID.randomUUID(), null, start, target); |
| | | runMapper.insert(run); |
| | | int taskCount = createDeviceTasks(run.getId(), device, start, target, properties.isRawReadingEnabled()); |
| | | applyRunRange(run, start, target, taskCount); |
| | | if (taskCount > 0) { |
| | | executeRunAfterCommit(run.getId()); |
| | | } |
| | | return run.getId(); |
| | | } |
| | | |
| | | @Override |
| | | public Long triggerManual(List<Long> meterIds, LocalDate start, LocalDate end, Boolean includeReadings) { |
| | | if (!provider.mockMode() && !provider.hasApiKey()) { |
| | | throw new ServiceException("æªé
ç½®ç¬¬ä¸æ¹ææç ï¼ç¯å¢åé NH_ENERGY_API_KEYï¼ï¼æ æ³æ¥è¡¨"); |
| | | } |
| | | if (meterIds == null || meterIds.isEmpty()) { |
| | | throw new ServiceException("è¯·éæ©è³å°ä¸å°è®¾å¤"); |
| | | } |
| | | // æå¨æ¥è¡¨å
许æ¥å°ä»å¤©ï¼å½å¤©ç¨é为æªè³æ¤å»ç累计å¼ï¼ï¼åªæ¡æªæ¥æ¥æ |
| | | LocalDate today = EnergyMeterSupport.today(); |
| | | LocalDate rangeEnd = end != null ? end : today; |
| | | if (rangeEnd.isAfter(today)) { |
| | | rangeEnd = today; |
| | | } |
| | | LocalDate rangeStart = start != null ? start : rangeEnd.minusDays(2); |
| | | if (rangeStart.isAfter(rangeEnd)) { |
| | | throw new ServiceException("å¼å§æ¥æä¸è½æäºç»ææ¥æ"); |
| | | } |
| | | if (ChronoUnit.DAYS.between(rangeStart, rangeEnd) > EnergyMeterConstants.MAX_RANGE_DAYS) { |
| | | throw new ServiceException("æ¥è¯¢è·¨åº¦è¶
åºä¸éï¼è¯·ç¼©å°æ¥æèå´"); |
| | | } |
| | | |
| | | List<EnergyMeterDevice> devices = new ArrayList<>(); |
| | | for (Long meterId : new LinkedHashSet<>(meterIds)) { |
| | | EnergyMeterDevice device = deviceMapper.selectById(meterId); |
| | | if (device == null) { |
| | | throw new ServiceException("设å¤ä¸åå¨ï¼" + meterId); |
| | | } |
| | | Long tenantId = EnergyMeterSupport.currentTenantId(); |
| | | if (tenantId != null && device.getTenantId() != null && !tenantId.equals(device.getTenantId())) { |
| | | throw new ServiceException("æ ææä½è®¾å¤ï¼" + meterId); |
| | | } |
| | | if (!EnergyMeterConstants.BIND_VERIFIED.equals(device.getBindStatus())) { |
| | | throw new ServiceException("è®¾å¤æªéè¿ç¬¬ä¸æ¹æ¡£æ¡éªè¯ï¼ä¸è½æ¥è¡¨ï¼" + meterId); |
| | | } |
| | | if (EnergyMeterConstants.isManual(device.getSourceType())) { |
| | | throw new ServiceException("æå·¥æè¡¨è®¾å¤æ éæ¥è¡¨ï¼è¯·å¨è¡¨å
·å°è´¦ä¸å½å
¥è¡¨ç ï¼" |
| | | + StringUtils.defaultIfBlank(device.getDisplayName(), device.getMeterAddress())); |
| | | } |
| | | devices.add(device); |
| | | } |
| | | |
| | | EnergyMeterSyncRun run = newRun(EnergyMeterConstants.RUN_MANUAL, |
| | | "MANUAL:" + UUID.randomUUID(), null, rangeStart, rangeEnd); |
| | | runMapper.insert(run); |
| | | boolean withReadings = includeReadings == null ? properties.isRawReadingEnabled() : includeReadings; |
| | | int taskCount = 0; |
| | | for (EnergyMeterDevice device : devices) { |
| | | taskCount += createDeviceTasks(run.getId(), device, rangeStart, rangeEnd, withReadings); |
| | | } |
| | | applyRunRange(run, rangeStart, rangeEnd, taskCount); |
| | | log.info("æå¨æ¥è¡¨æ¹æ¬¡åå»ºå®æ runId={} è®¾å¤æ°={} 任塿°={} range={}~{}", |
| | | run.getId(), devices.size(), taskCount, rangeStart, rangeEnd); |
| | | if (taskCount > 0) { |
| | | executeRunAfterCommit(run.getId()); |
| | | } |
| | | return run.getId(); |
| | | } |
| | | |
| | | /* ------------------------------------------------------------------ */ |
| | | /* æ¹æ¬¡æ§è¡ */ |
| | | /* ------------------------------------------------------------------ */ |
| | | |
| | | @Override |
| | | public void executeRunAsync(Long runId) { |
| | | if (runId == null) { |
| | | return; |
| | | } |
| | | runExecutor.execute(() -> { |
| | | try { |
| | | processRun(runId); |
| | | } catch (Throwable e) { |
| | | log.error("åæ¥æ¹æ¬¡æ§è¡å¼å¸¸ runId=" + runId, e); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | /** |
| | | * å¨äºå¡æäº¤ååå¼å§æ§è¡ï¼é¿å
弿¥çº¿ç¨è¯»ä¸å°å°æªæäº¤çä»»å¡è®°å½ã |
| | | */ |
| | | private void executeRunAfterCommit(Long runId) { |
| | | if (runId == null) { |
| | | return; |
| | | } |
| | | if (TransactionSynchronizationManager.isSynchronizationActive()) { |
| | | TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { |
| | | @Override |
| | | public void afterCommit() { |
| | | executeRunAsync(runId); |
| | | } |
| | | }); |
| | | } else { |
| | | executeRunAsync(runId); |
| | | } |
| | | } |
| | | |
| | | private void processRun(Long runId) { |
| | | EnergyMeterSyncRun run = runMapper.selectById(runId); |
| | | if (run == null) { |
| | | return; |
| | | } |
| | | if (EnergyMeterConstants.RUN_PENDING.equals(run.getStatus())) { |
| | | EnergyMeterSyncRun running = new EnergyMeterSyncRun(); |
| | | running.setId(runId); |
| | | running.setStatus(EnergyMeterConstants.RUN_RUNNING); |
| | | running.setStartedAt(EnergyMeterSupport.now()); |
| | | runMapper.updateById(running); |
| | | } |
| | | |
| | | LocalDateTime now = EnergyMeterSupport.now(); |
| | | // åä¸è®¾å¤ãå䏿¥å£ãåä¸ç²åº¦çåçææ¥æé¡ºåºä¸²è¡æ§è¡ï¼ä¿è¯è¿ç»è¿åº¦ä¸ä¼è¢«ä¹±åºæ¨è¿ï¼ |
| | | // ä¸å设å¤/æ¥å£ä¹é´ä»ç¶å¹¶è¡ï¼åçº¿ç¨æ± å¹¶åæ°éå¶ã |
| | | Map<String, List<EnergyMeterSyncTask>> groups = new LinkedHashMap<>(); |
| | | for (EnergyMeterSyncTask task : taskMapper.selectByRunId(runId)) { |
| | | if (!isRunnable(task, now)) { |
| | | continue; |
| | | } |
| | | String key = task.getMeterId() + "|" + task.getSourceApi() + "|" + task.getGranularity(); |
| | | groups.computeIfAbsent(key, k -> new ArrayList<>()).add(task); |
| | | } |
| | | List<CompletableFuture<Void>> futures = new ArrayList<>(); |
| | | for (List<EnergyMeterSyncTask> group : groups.values()) { |
| | | group.sort(Comparator.comparing(EnergyMeterSyncTask::getRangeStart, |
| | | Comparator.nullsFirst(LocalDate::compareTo))); |
| | | futures.add(CompletableFuture.runAsync(() -> { |
| | | for (EnergyMeterSyncTask task : group) { |
| | | executeTask(task.getId()); |
| | | } |
| | | }, taskExecutor)); |
| | | } |
| | | if (!futures.isEmpty()) { |
| | | CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); |
| | | } |
| | | finalizeRun(runId); |
| | | } |
| | | |
| | | private boolean isRunnable(EnergyMeterSyncTask task, LocalDateTime now) { |
| | | if (EnergyMeterConstants.TASK_PENDING.equals(task.getStatus())) { |
| | | return true; |
| | | } |
| | | if (EnergyMeterConstants.TASK_RETRY.equals(task.getStatus())) { |
| | | return task.getNextRetryAt() == null || !task.getNextRetryAt().isAfter(now); |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | private void executeTask(Long taskId) { |
| | | LocalDateTime now = EnergyMeterSupport.now(); |
| | | if (taskMapper.claim(taskId, now) == 0) { |
| | | return; |
| | | } |
| | | EnergyMeterSyncTask task = taskMapper.selectById(taskId); |
| | | EnergyMeterDevice device = deviceMapper.selectById(task.getMeterId()); |
| | | if (device == null) { |
| | | markTaskFailed(task, "DEVICE_MISSING", "æ¬å°è®¾å¤ä¸åå¨ï¼æ æ³éé"); |
| | | return; |
| | | } |
| | | try { |
| | | FetchResult result = fetch(device, task); |
| | | persist(device, task, result); |
| | | } catch (MeterProviderException e) { |
| | | markTaskFailed(task, e.getCode(), e.getMessage()); |
| | | } catch (Exception e) { |
| | | log.error("忥任å¡å¼å¸¸ taskId=" + taskId, e); |
| | | markTaskFailed(task, EnergyMeterConstants.ERROR_UPSTREAM, e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | private FetchResult fetch(EnergyMeterDevice device, EnergyMeterSyncTask task) { |
| | | String meterType = device.getMeterType(); |
| | | String address = device.getMeterAddress(); |
| | | String providerMeterId = device.getProviderMeterId(); |
| | | LocalDate start = task.getRangeStart(); |
| | | LocalDate end = task.getRangeEnd(); |
| | | LocalDateTime collectedAt = EnergyMeterSupport.now(); |
| | | List<EnergyMeterMeasurement> measurements = new ArrayList<>(); |
| | | int fetched = 0; |
| | | |
| | | if (EnergyMeterConstants.GRANULARITY_DAY.equals(task.getGranularity())) { |
| | | List<MeterUsagePoint> points = provider.queryDailyUsage(meterType, address, providerMeterId, start, end); |
| | | fetched = points.size(); |
| | | String metric = EnergyMeterConstants.usageMetric(meterType); |
| | | String unit = EnergyMeterConstants.unit(meterType); |
| | | for (MeterUsagePoint point : points) { |
| | | validateAddress(address, point.getAddress()); |
| | | if (point.getTime() == null || point.getValue() == null) { |
| | | throw new MeterProviderException(EnergyMeterConstants.ERROR_PARSE, "ç¨éæ°æ®ç¼ºå°æ¶é´ææ°å¼"); |
| | | } |
| | | LocalDate day = point.getTime().toLocalDate(); |
| | | if (day.isBefore(start) || day.isAfter(end)) { |
| | | continue; |
| | | } |
| | | EnergyMeterMeasurement measurement = new EnergyMeterMeasurement(); |
| | | measurement.setTenantId(device.getTenantId()); |
| | | measurement.setMeterId(device.getId()); |
| | | measurement.setMetricCode(metric); |
| | | measurement.setGranularity(EnergyMeterConstants.GRANULARITY_DAY); |
| | | measurement.setMeasureTime(day.atStartOfDay()); |
| | | measurement.setMetricValue(point.getValue()); |
| | | measurement.setUnit(unit); |
| | | measurement.setSourceApi(task.getSourceApi()); |
| | | measurement.setSourceRecordTime(point.getTime()); |
| | | measurement.setCollectedAt(collectedAt); |
| | | measurements.add(measurement); |
| | | } |
| | | } else { |
| | | List<MeterReadingPoint> points = provider.queryReadings(meterType, address, providerMeterId, start, end); |
| | | fetched = points.size(); |
| | | String metric = EnergyMeterConstants.readingMetric(meterType); |
| | | String unit = EnergyMeterConstants.unit(meterType); |
| | | for (MeterReadingPoint point : points) { |
| | | validateAddress(address, point.getAddress()); |
| | | if (point.getTime() == null || point.getReading() == null) { |
| | | throw new MeterProviderException(EnergyMeterConstants.ERROR_PARSE, "ç¤ºå¼æ°æ®ç¼ºå°æ¶é´ææ°å¼"); |
| | | } |
| | | LocalDate day = point.getTime().toLocalDate(); |
| | | if (day.isBefore(start) || day.isAfter(end)) { |
| | | continue; |
| | | } |
| | | EnergyMeterMeasurement measurement = new EnergyMeterMeasurement(); |
| | | measurement.setTenantId(device.getTenantId()); |
| | | measurement.setMeterId(device.getId()); |
| | | measurement.setMetricCode(metric); |
| | | measurement.setGranularity(EnergyMeterConstants.GRANULARITY_POINT); |
| | | measurement.setMeasureTime(point.getTime()); |
| | | measurement.setMetricValue(point.getReading()); |
| | | measurement.setUnit(unit); |
| | | measurement.setSourceApi(task.getSourceApi()); |
| | | measurement.setSourceRecordTime(point.getTime()); |
| | | measurement.setCollectedAt(collectedAt); |
| | | measurements.add(measurement); |
| | | } |
| | | } |
| | | FetchResult result = new FetchResult(); |
| | | result.fetched = fetched; |
| | | result.measurements = measurements; |
| | | result.metricCode = EnergyMeterConstants.GRANULARITY_DAY.equals(task.getGranularity()) |
| | | ? EnergyMeterConstants.usageMetric(meterType) |
| | | : EnergyMeterConstants.readingMetric(meterType); |
| | | return result; |
| | | } |
| | | |
| | | private void validateAddress(String expected, String actual) { |
| | | if (StringUtils.isNotBlank(actual) && !expected.equals(actual.trim())) { |
| | | throw new MeterProviderException(EnergyMeterConstants.ERROR_ADDRESS_MISMATCH, |
| | | "ç¬¬ä¸æ¹è¿åçéä¿¡å°å䏿¬å°ç»å®ä¸ä¸è´"); |
| | | } |
| | | } |
| | | |
| | | private void persist(EnergyMeterDevice device, EnergyMeterSyncTask task, FetchResult result) { |
| | | LocalDateTime now = EnergyMeterSupport.now(); |
| | | LocalDateTime rangeStart = task.getRangeStart().atStartOfDay(); |
| | | LocalDateTime rangeEnd = task.getRangeEnd().plusDays(1).atStartOfDay(); |
| | | |
| | | int[] counters = transactionTemplate.execute(txStatus -> { |
| | | int inserted = 0; |
| | | int updated = 0; |
| | | List<EnergyMeterMeasurement> writes = new ArrayList<>(); |
| | | if (!result.measurements.isEmpty()) { |
| | | Map<LocalDateTime, BigDecimal> existing = new HashMap<>(); |
| | | for (EnergyMeterMeasurement row : measurementMapper.selectExistingPoints(device.getId(), |
| | | result.metricCode, task.getGranularity(), rangeStart, rangeEnd)) { |
| | | existing.put(row.getMeasureTime(), row.getMetricValue()); |
| | | } |
| | | for (EnergyMeterMeasurement measurement : result.measurements) { |
| | | BigDecimal oldValue = existing.get(measurement.getMeasureTime()); |
| | | if (oldValue == null) { |
| | | inserted++; |
| | | writes.add(measurement); |
| | | } else if (oldValue.compareTo(measurement.getMetricValue()) != 0) { |
| | | updated++; |
| | | writes.add(measurement); |
| | | } |
| | | } |
| | | } |
| | | for (int from = 0; from < writes.size(); from += UPSERT_CHUNK) { |
| | | int to = Math.min(from + UPSERT_CHUNK, writes.size()); |
| | | measurementMapper.upsertBatch(writes.subList(from, to)); |
| | | } |
| | | |
| | | String status = result.measurements.isEmpty() |
| | | ? EnergyMeterConstants.TASK_EMPTY : EnergyMeterConstants.TASK_SUCCESS; |
| | | taskMapper.markFinished(task.getId(), status, result.fetched, inserted, updated, now); |
| | | deviceMapper.markCollectSuccess(device.getId(), now); |
| | | advanceCheckpoint(device, task, now); |
| | | return new int[]{inserted, updated}; |
| | | }); |
| | | int inserted = counters == null ? 0 : counters[0]; |
| | | int updated = counters == null ? 0 : counters[1]; |
| | | log.info("忥任å¡å®æ taskId={} meterId={} æå={} æ°å¢={} ä¿®æ£={}", |
| | | task.getId(), device.getId(), result.fetched, inserted, updated); |
| | | } |
| | | |
| | | private void advanceCheckpoint(EnergyMeterDevice device, EnergyMeterSyncTask task, LocalDateTime now) { |
| | | LocalDate start = task.getRangeStart(); |
| | | LocalDate end = task.getRangeEnd(); |
| | | // å½å¤©æ°æ®ä»å¨æ»å¨ç´¯è®¡ï¼æå¨æ¥è¡¨æå½å¤©è¡¥éä¼ä¸æè¦çï¼ï¼ä¸è½æä»å¤©è®°ä¸ºâ已宿âï¼ |
| | | // å¦åè¡¥é缺å£å¤æä¼è¯¯ä»¥ä¸ºä»å¤©å·²ç»å®æ´ã宿è¿åº¦åªæ¨è¿å°æ¨å¤©åæ´æ©ã |
| | | if (!end.isBefore(EnergyMeterSupport.today())) { |
| | | log.debug("è·³è¿å½å¤©è¿åº¦æ¨è¿ meterId={} source={} granularity={} end={}", |
| | | device.getId(), task.getSourceApi(), task.getGranularity(), end); |
| | | return; |
| | | } |
| | | EnergyMeterSyncCheckpoint checkpoint = checkpointMapper.selectUnit(device.getId(), |
| | | task.getSourceApi(), task.getGranularity()); |
| | | LocalDate existingDate = checkpoint == null ? null : checkpoint.getLastCompleteDate(); |
| | | boolean contiguous = existingDate == null || !start.isAfter(existingDate.plusDays(1)); |
| | | LocalDate lastComplete; |
| | | if (contiguous) { |
| | | lastComplete = existingDate == null || end.isAfter(existingDate) ? end : existingDate; |
| | | } else { |
| | | lastComplete = existingDate != null ? existingDate : start.minusDays(1); |
| | | } |
| | | EnergyMeterSyncCheckpoint upsert = new EnergyMeterSyncCheckpoint(); |
| | | upsert.setTenantId(device.getTenantId()); |
| | | upsert.setMeterId(device.getId()); |
| | | upsert.setSourceApi(task.getSourceApi()); |
| | | upsert.setGranularity(task.getGranularity()); |
| | | upsert.setLastCompleteDate(lastComplete); |
| | | upsert.setLastSuccessAt(now); |
| | | upsert.setLastRunId(task.getRunId()); |
| | | checkpointMapper.upsert(upsert); |
| | | } |
| | | |
| | | private void markTaskFailed(EnergyMeterSyncTask task, String code, String message) { |
| | | String safeCode = StringUtils.defaultIfBlank(code, EnergyMeterConstants.ERROR_UPSTREAM); |
| | | String safeMessage = EnergyMeterSupport.truncate( |
| | | StringUtils.defaultIfBlank(message, "æªç¥é误"), 450); |
| | | int attempts = task.getAttemptCount() == null ? 1 : task.getAttemptCount(); |
| | | // max-attempts 表示âæå¤éè¯æ¬¡æ°âï¼é¦æ¬¡æ§è¡ä¹å¤è¿å¯éè¯ N 次 |
| | | int maxTotalAttempts = Math.max(1, properties.getMaxAttempts()) + 1; |
| | | boolean retry = attempts < maxTotalAttempts; |
| | | LocalDateTime now = EnergyMeterSupport.now(); |
| | | LocalDateTime nextRetryAt = null; |
| | | if (retry) { |
| | | int index = Math.min(Math.max(attempts - 1, 0), EnergyMeterConstants.RETRY_DELAY_MINUTES.length - 1); |
| | | nextRetryAt = now.plusMinutes(EnergyMeterConstants.RETRY_DELAY_MINUTES[index]); |
| | | } |
| | | String status = retry ? EnergyMeterConstants.TASK_RETRY : EnergyMeterConstants.TASK_FAILED; |
| | | LocalDateTime finalNextRetryAt = nextRetryAt; |
| | | transactionTemplate.executeWithoutResult(state -> { |
| | | taskMapper.markFailed(task.getId(), status, safeCode, safeMessage, finalNextRetryAt, now); |
| | | deviceMapper.markCollectFailure(task.getMeterId(), safeCode, safeMessage); |
| | | }); |
| | | log.warn("忥任å¡å¤±è´¥ taskId={} meterId={} code={} attempts={} å°éè¯={}", |
| | | task.getId(), task.getMeterId(), safeCode, attempts, retry); |
| | | } |
| | | |
| | | private void finalizeRun(Long runId) { |
| | | TaskStatusCount count = taskMapper.countByRunId(runId); |
| | | runMapper.refreshTotals(runId); |
| | | int total = count == null || count.getTotal() == null ? 0 : count.getTotal(); |
| | | int success = count == null || count.getSuccess() == null ? 0 : count.getSuccess(); |
| | | int empty = count == null || count.getEmpty() == null ? 0 : count.getEmpty(); |
| | | int failed = count == null || count.getFailed() == null ? 0 : count.getFailed(); |
| | | int retry = count == null || count.getRetry() == null ? 0 : count.getRetry(); |
| | | int pending = count == null || count.getPending() == null ? 0 : count.getPending(); |
| | | int running = count == null || count.getRunning() == null ? 0 : count.getRunning(); |
| | | |
| | | boolean finished = pending == 0 && running == 0 && retry == 0; |
| | | String status; |
| | | if (!finished) { |
| | | status = EnergyMeterConstants.RUN_PARTIAL; |
| | | } else if (failed == 0) { |
| | | status = EnergyMeterConstants.RUN_SUCCESS; |
| | | } else if (success + empty > 0) { |
| | | status = EnergyMeterConstants.RUN_PARTIAL; |
| | | } else { |
| | | status = EnergyMeterConstants.RUN_FAILED; |
| | | } |
| | | EnergyMeterSyncRun update = new EnergyMeterSyncRun(); |
| | | update.setId(runId); |
| | | update.setStatus(status); |
| | | if (finished) { |
| | | update.setFinishedAt(EnergyMeterSupport.now()); |
| | | } |
| | | if (failed > 0) { |
| | | update.setErrorSummary(EnergyMeterSupport.truncate( |
| | | failed + "/" + total + " 个任å¡å¤±è´¥ï¼å¯å¨æ¹æ¬¡è¯¦æ
ä¸éè¯", 500)); |
| | | } |
| | | runMapper.updateById(update); |
| | | log.info("åæ¥æ¹æ¬¡æ±æ» runId={} status={} total={} success={} empty={} failed={} retry={}", |
| | | runId, status, total, success, empty, failed, retry); |
| | | } |
| | | |
| | | /* ------------------------------------------------------------------ */ |
| | | /* éè¯ä¸æ¢å¤ */ |
| | | /* ------------------------------------------------------------------ */ |
| | | |
| | | @Override |
| | | public int recoverDueTasks() { |
| | | LocalDateTime now = EnergyMeterSupport.now(); |
| | | int timeoutMinutes = Math.max(1, properties.getRunningTimeoutMinutes()); |
| | | LocalDateTime deadline = now.minusMinutes(timeoutMinutes); |
| | | int handled = 0; |
| | | int maxTotalAttempts = Math.max(1, properties.getMaxAttempts()) + 1; |
| | | for (EnergyMeterSyncTask task : taskMapper.selectStaleRunning(deadline, 200)) { |
| | | int attempts = task.getAttemptCount() == null ? 0 : task.getAttemptCount(); |
| | | if (attempts >= maxTotalAttempts) { |
| | | transactionTemplate.executeWithoutResult(state -> taskMapper.markFailed(task.getId(), |
| | | EnergyMeterConstants.TASK_FAILED, EnergyMeterConstants.ERROR_TIMEOUT, |
| | | "任塿§è¡è¶
æ¶ï¼è¶
è¿ " + timeoutMinutes + " åéï¼", null, now)); |
| | | } else { |
| | | taskMapper.resetToRetry(task.getId(), now, now, "任塿§è¡è¶
æ¶ï¼èªå¨è½¬å
¥éè¯"); |
| | | } |
| | | handled++; |
| | | } |
| | | |
| | | List<EnergyMeterSyncTask> dueTasks = taskMapper.selectDueRetry(now, 200); |
| | | Set<Long> runIds = dueTasks.stream().map(EnergyMeterSyncTask::getRunId) |
| | | .collect(Collectors.toCollection(LinkedHashSet::new)); |
| | | for (Long runId : runIds) { |
| | | try { |
| | | processRun(runId); |
| | | } catch (Exception e) { |
| | | log.error("æ¢å¤ä»»å¡å¤çæ¹æ¬¡å¤±è´¥ runId=" + runId, e); |
| | | } |
| | | } |
| | | handled += dueTasks.size(); |
| | | |
| | | // å´©æºå
åºï¼æ¹æ¬¡åå¨ RUNNING ä½ä»»å¡é½å·²ç»æï¼ä¾å¦æ±æ»é¶æ®µå¼å¸¸éåºï¼æ¶éæ°æ±æ» |
| | | for (EnergyMeterSyncRun stuck : runMapper.selectStuckRuns(now.minusMinutes(5), 50)) { |
| | | try { |
| | | finalizeRun(stuck.getId()); |
| | | handled++; |
| | | log.info("å
åºæ±æ»æ»çæ¹æ¬¡ runId={}", stuck.getId()); |
| | | } catch (Exception e) { |
| | | log.error("å
åºæ±æ»æ¹æ¬¡å¤±è´¥ runId=" + stuck.getId(), e); |
| | | } |
| | | } |
| | | if (handled > 0) { |
| | | log.info("忥æ¢å¤ä½ä¸å¤ç {} 个任å¡/æ¹æ¬¡", handled); |
| | | } |
| | | return handled; |
| | | } |
| | | |
| | | /* ------------------------------------------------------------------ */ |
| | | /* å
é¨å·¥å
· */ |
| | | /* ------------------------------------------------------------------ */ |
| | | |
| | | private EnergyMeterSyncRun newRun(String triggerType, String runKey, LocalDate scheduleDate, |
| | | LocalDate start, LocalDate end) { |
| | | EnergyMeterSyncRun run = new EnergyMeterSyncRun(); |
| | | run.setRunKey(runKey); |
| | | run.setTriggerType(triggerType); |
| | | run.setScheduleDate(scheduleDate); |
| | | run.setRangeStart(start); |
| | | run.setRangeEnd(end); |
| | | run.setStatus(EnergyMeterConstants.RUN_PENDING); |
| | | run.setTotalTasks(0); |
| | | run.setSuccessTasks(0); |
| | | run.setEmptyTasks(0); |
| | | run.setFailedTasks(0); |
| | | run.setCreateUser(EnergyMeterSupport.currentUserId()); |
| | | return run; |
| | | } |
| | | |
| | | private void applyRunRange(EnergyMeterSyncRun run, LocalDate start, LocalDate end, int taskCount) { |
| | | EnergyMeterSyncRun update = new EnergyMeterSyncRun(); |
| | | update.setId(run.getId()); |
| | | update.setRangeStart(start); |
| | | update.setRangeEnd(end); |
| | | update.setTotalTasks(taskCount); |
| | | runMapper.updateById(update); |
| | | } |
| | | |
| | | private int createDeviceTasks(Long runId, EnergyMeterDevice device, LocalDate start, LocalDate end, |
| | | boolean includeReadings) { |
| | | if (EnergyMeterConstants.isManual(device.getSourceType())) { |
| | | return 0; |
| | | } |
| | | int created = createTasksFor(runId, device, |
| | | EnergyMeterConstants.usageSource(device.getMeterType()), |
| | | EnergyMeterConstants.GRANULARITY_DAY, start, end, |
| | | Math.max(1, properties.getMaxShardDays())); |
| | | if (includeReadings && !EnergyMeterConstants.isGas(device.getMeterType())) { |
| | | // ç¤ºå¼æ¥å£çæ¥è¯¢è·¨åº¦éå¶æ¯ç¨éæ¥å£æ´ä¸¥ï¼é社äºä¸º 15 天ï¼ï¼å¿
é¡»ç¨æ´å°çåçã |
| | | // æ°è¡¨ç¤ºå¼æ¥å£åªæ¯æ mi15ï¼15 åéï¼ç²åº¦ï¼96 ç¹/å¤©ï¼æ°æ®éè¿å¤§ï¼æä¸å建示å¼ä»»å¡ã |
| | | created += createTasksFor(runId, device, |
| | | EnergyMeterConstants.readingSource(device.getMeterType()), |
| | | EnergyMeterConstants.GRANULARITY_POINT, start, end, |
| | | Math.max(1, properties.getMaxReadingShardDays())); |
| | | } |
| | | return created; |
| | | } |
| | | |
| | | private int createTasksFor(Long runId, EnergyMeterDevice device, String sourceApi, String granularity, |
| | | LocalDate start, LocalDate end, int shardDays) { |
| | | int created = 0; |
| | | LocalDate cursor = start; |
| | | while (!cursor.isAfter(end)) { |
| | | LocalDate shardEnd = cursor.plusDays(shardDays - 1L); |
| | | if (shardEnd.isAfter(end)) { |
| | | shardEnd = end; |
| | | } |
| | | created += taskMapper.insertIgnore(buildTask(runId, device, sourceApi, granularity, cursor, shardEnd)); |
| | | cursor = shardEnd.plusDays(1); |
| | | } |
| | | return created; |
| | | } |
| | | |
| | | private EnergyMeterSyncTask buildTask(Long runId, EnergyMeterDevice device, String sourceApi, |
| | | String granularity, LocalDate start, LocalDate end) { |
| | | EnergyMeterSyncTask task = new EnergyMeterSyncTask(); |
| | | task.setRunId(runId); |
| | | task.setTenantId(device.getTenantId()); |
| | | task.setMeterId(device.getId()); |
| | | task.setSourceApi(sourceApi); |
| | | task.setGranularity(granularity); |
| | | task.setRangeStart(start); |
| | | task.setRangeEnd(end); |
| | | task.setStatus(EnergyMeterConstants.TASK_PENDING); |
| | | return task; |
| | | } |
| | | |
| | | /** |
| | | * èªå¨åæ¥èµ·ç¹ï¼ä¼å
è¡¥é½è¿åº¦ç¼ºå£ï¼åæ¶å§ç»åæ¥æè¿ N 天ï¼é»è®¤ 3 天ï¼ã |
| | | */ |
| | | private LocalDate resolveAutoStart(EnergyMeterDevice device, LocalDate target) { |
| | | LocalDate base = device.getSyncStartDate() != null |
| | | ? device.getSyncStartDate() |
| | | : LocalDate.of(target.getYear() - 1, 1, 1); |
| | | LocalDate start = base; |
| | | EnergyMeterSyncCheckpoint checkpoint = checkpointMapper.selectUnit(device.getId(), |
| | | EnergyMeterConstants.usageSource(device.getMeterType()), EnergyMeterConstants.GRANULARITY_DAY); |
| | | if (checkpoint != null && checkpoint.getLastCompleteDate() != null) { |
| | | LocalDate next = checkpoint.getLastCompleteDate().plusDays(1); |
| | | if (next.isAfter(start)) { |
| | | start = next; |
| | | } |
| | | } |
| | | int lookback = Math.max(1, properties.getLookbackDays()); |
| | | LocalDate lookbackStart = target.minusDays(lookback - 1L); |
| | | if (start.isAfter(lookbackStart)) { |
| | | start = lookbackStart; |
| | | } |
| | | if (start.isBefore(base)) { |
| | | start = base; |
| | | } |
| | | if (start.isAfter(target)) { |
| | | return null; |
| | | } |
| | | return start; |
| | | } |
| | | |
| | | /** 䏿¬¡ä»»å¡çæåç»æã */ |
| | | private static class FetchResult { |
| | | private int fetched; |
| | | private String metricCode; |
| | | private List<EnergyMeterMeasurement> measurements = new ArrayList<>(); |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.service.impl; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.ruoyi.common.exception.ServiceException; |
| | | import com.ruoyi.common.utils.StringUtils; |
| | | import com.ruoyi.energymeter.constant.EnergyMeterConstants; |
| | | import com.ruoyi.energymeter.dto.DailyUsageRow; |
| | | import com.ruoyi.energymeter.dto.DataRangeRow; |
| | | import com.ruoyi.energymeter.dto.MeterUsageRow; |
| | | import com.ruoyi.energymeter.dto.MonthlyUsageRow; |
| | | import com.ruoyi.energymeter.mapper.EnergyMeterDeviceMapper; |
| | | import com.ruoyi.energymeter.mapper.EnergyMeterMeasurementMapper; |
| | | import com.ruoyi.energymeter.mapper.EnergyMeterSyncRunMapper; |
| | | import com.ruoyi.energymeter.pojo.EnergyMeterDevice; |
| | | import com.ruoyi.energymeter.pojo.EnergyMeterMeasurement; |
| | | import com.ruoyi.energymeter.pojo.EnergyMeterSyncRun; |
| | | import com.ruoyi.energymeter.provider.MeterProviderClient; |
| | | import com.ruoyi.energymeter.service.ElectricMeterDashboardService; |
| | | import com.ruoyi.energymeter.service.EnergyMonitorService; |
| | | import com.ruoyi.energymeter.util.EnergyMeterSupport; |
| | | import com.ruoyi.energymeter.vo.ElectricMeterDashboardVO; |
| | | import com.ruoyi.energymeter.vo.EnergyCollectionVO; |
| | | import com.ruoyi.energymeter.vo.EnergyRealtimeVO; |
| | | import com.ruoyi.energymeter.vo.EnergyReportVO; |
| | | import lombok.RequiredArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.math.RoundingMode; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | import java.time.YearMonth; |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.time.temporal.ChronoUnit; |
| | | import java.util.ArrayList; |
| | | import java.util.Comparator; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Objects; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * è½èæ°æ®ééã宿¶çæ§ä¸ç»è®¡åæå®ç°ã |
| | | * |
| | | * <p>ç»è®¡å£å¾ä¸ç¨è½æ¦è§ä¿æä¸è´ï¼åªæ±æ» D ç²åº¦çç¨éææ ï¼è¡¨ç ï¼POINTï¼ä¸åä¸ç´¯å ï¼ |
| | | * ç¼ºå¤±æ¥æä¿æ nullï¼ç±å端æ¾ç¤ºä¸ºç¼ºå£è䏿¯ 0ã</p> |
| | | */ |
| | | @Slf4j |
| | | @Service |
| | | @RequiredArgsConstructor |
| | | public class EnergyMonitorServiceImpl implements EnergyMonitorService { |
| | | |
| | | private static final DateTimeFormatter DAY_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd"); |
| | | private static final DateTimeFormatter DATETIME_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); |
| | | private static final List<String> ALL_TYPES = List.of(EnergyMeterConstants.TYPE_WATER, |
| | | EnergyMeterConstants.TYPE_ELECTRIC, EnergyMeterConstants.TYPE_GAS); |
| | | private static final int TREND_DAYS = 7; |
| | | private static final int MAX_REPORT_DAYS = 366; |
| | | |
| | | private final EnergyMeterDeviceMapper deviceMapper; |
| | | private final EnergyMeterMeasurementMapper measurementMapper; |
| | | private final EnergyMeterSyncRunMapper runMapper; |
| | | private final ElectricMeterDashboardService dashboardService; |
| | | private final MeterProviderClient provider; |
| | | |
| | | /* ------------------------------------------------------------------ */ |
| | | /* æ°æ®éé */ |
| | | /* ------------------------------------------------------------------ */ |
| | | |
| | | @Override |
| | | public EnergyCollectionVO collection() { |
| | | LocalDate today = EnergyMeterSupport.today(); |
| | | EnergyCollectionVO vo = new EnergyCollectionVO(); |
| | | vo.setGeneratedAt(EnergyMeterSupport.now().format(DATETIME_FORMAT)); |
| | | vo.setToday(today.format(DAY_FORMAT)); |
| | | vo.setMockMode(provider.mockMode()); |
| | | |
| | | List<EnergyMeterSyncRun> runs = runMapper.selectList(new LambdaQueryWrapper<EnergyMeterSyncRun>() |
| | | .orderByDesc(EnergyMeterSyncRun::getId) |
| | | .last("LIMIT 8")); |
| | | int failed = 0; |
| | | int pending = 0; |
| | | for (EnergyMeterSyncRun run : runs) { |
| | | EnergyCollectionVO.RunItem item = toRunItem(run); |
| | | vo.getRuns().add(item); |
| | | failed += nvl(item.getFailedTasks()); |
| | | pending += Math.max(0, nvl(item.getTotalTasks()) - nvl(item.getSuccessTasks()) |
| | | - nvl(item.getEmptyTasks()) - nvl(item.getFailedTasks())); |
| | | } |
| | | vo.setFailedTaskCount(failed); |
| | | vo.setPendingTaskCount(pending); |
| | | |
| | | for (String type : ALL_TYPES) { |
| | | List<EnergyMeterDevice> devices = loadDevices(type); |
| | | EnergyCollectionVO.Medium medium = new EnergyCollectionVO.Medium(); |
| | | medium.setMeterType(type); |
| | | medium.setMeterName(mediumName(type)); |
| | | medium.setUnit(EnergyMeterConstants.unit(type)); |
| | | medium.setDeviceCount(devices.size()); |
| | | |
| | | int providerCount = 0; |
| | | int manualCount = 0; |
| | | for (EnergyMeterDevice device : devices) { |
| | | if (EnergyMeterConstants.isAutoCollect(device.getSourceType(), device.getSimulated())) { |
| | | providerCount++; |
| | | } else { |
| | | manualCount++; |
| | | } |
| | | } |
| | | medium.setProviderCount(providerCount); |
| | | medium.setManualCount(manualCount); |
| | | |
| | | List<Long> ids = devices.stream().map(EnergyMeterDevice::getId).collect(Collectors.toList()); |
| | | DataRangeRow range = ids.isEmpty() ? null |
| | | : measurementMapper.selectDataRange(ids, EnergyMeterConstants.usageMetric(type)); |
| | | LocalDate dataStart = range == null || range.getMinTime() == null ? null : range.getMinTime().toLocalDate(); |
| | | LocalDate dataEnd = range == null || range.getMaxTime() == null ? null : range.getMaxTime().toLocalDate(); |
| | | medium.setDataStart(dataStart == null ? null : dataStart.format(DAY_FORMAT)); |
| | | medium.setDataEnd(dataEnd == null ? null : dataEnd.format(DAY_FORMAT)); |
| | | |
| | | LocalDateTime lastSuccess = devices.stream() |
| | | .map(EnergyMeterDevice::getLastSuccessAt) |
| | | .filter(Objects::nonNull) |
| | | .max(LocalDateTime::compareTo) |
| | | .orElse(null); |
| | | medium.setLastSuccessAt(lastSuccess == null ? null : lastSuccess.format(DATETIME_FORMAT)); |
| | | |
| | | if (!ids.isEmpty() && dataEnd != null) { |
| | | Integer latestDayMeters = measurementMapper.countMetersWithUsage(ids, |
| | | EnergyMeterConstants.usageMetric(type), dataEnd.atStartOfDay(), |
| | | dataEnd.plusDays(1).atStartOfDay()); |
| | | medium.setLatestDayMeters(latestDayMeters == null ? 0 : latestDayMeters); |
| | | } |
| | | |
| | | Map<LocalDate, BigDecimal> daily = ids.isEmpty() ? Map.of() : toDayMap(measurementMapper.sumDailyUsage(ids, |
| | | EnergyMeterConstants.usageMetric(type), today.minusDays(TREND_DAYS - 1).atStartOfDay(), |
| | | today.plusDays(1).atStartOfDay())); |
| | | medium.setCoveredDays(daily.size()); |
| | | medium.setExpectedDays(TREND_DAYS); |
| | | medium.setCoverageRate(daily.isEmpty() ? BigDecimal.ZERO |
| | | : BigDecimal.valueOf(daily.size() * 100.0 / TREND_DAYS).setScale(1, RoundingMode.HALF_UP)); |
| | | |
| | | // å¨çº¿å£å¾ï¼ä¾åºåæ è®°å¨çº¿ï¼ææè¿ 36 å°æ¶æåééï¼æ¨¡æè¡¨åçæè¿æ°æ®æ¥æ¯å¦å·²çæ |
| | | boolean simulatedFresh = dataEnd != null && !dataEnd.isBefore(today.minusDays(1)); |
| | | int onlineCount = 0; |
| | | for (EnergyMeterDevice device : devices) { |
| | | if (isOnline(device) |
| | | || (EnergyMeterConstants.isSimulated(device.getSimulated()) && simulatedFresh)) { |
| | | onlineCount++; |
| | | } |
| | | } |
| | | medium.setOnlineCount(onlineCount); |
| | | |
| | | boolean manualOnly = !devices.isEmpty() && providerCount == 0; |
| | | boolean simulatedOnly = !devices.isEmpty() |
| | | && devices.stream().allMatch(d -> EnergyMeterConstants.isSimulated(d.getSimulated())); |
| | | applyCollectionStatus(medium, devices.isEmpty(), dataEnd, lastSuccess, manualOnly, simulatedOnly, today); |
| | | vo.getMedia().add(medium); |
| | | } |
| | | return vo; |
| | | } |
| | | |
| | | private EnergyCollectionVO.RunItem toRunItem(EnergyMeterSyncRun run) { |
| | | EnergyCollectionVO.RunItem item = new EnergyCollectionVO.RunItem(); |
| | | item.setId(run.getId()); |
| | | item.setRunKey(run.getRunKey()); |
| | | item.setTriggerType(run.getTriggerType()); |
| | | item.setTriggerTypeName(switch (StringUtils.defaultString(run.getTriggerType())) { |
| | | case EnergyMeterConstants.RUN_SCHEDULED -> "宿¶åæ¥"; |
| | | case EnergyMeterConstants.RUN_BACKFILL -> "åå²è¡¥é"; |
| | | default -> "æå¨éé"; |
| | | }); |
| | | item.setStatus(run.getStatus()); |
| | | item.setStatusText(switch (StringUtils.defaultString(run.getStatus())) { |
| | | case EnergyMeterConstants.RUN_SUCCESS -> "å
¨é¨æå"; |
| | | case EnergyMeterConstants.RUN_PARTIAL -> "é¨å失败"; |
| | | case EnergyMeterConstants.RUN_FAILED -> "éé失败"; |
| | | case EnergyMeterConstants.RUN_RUNNING -> "ééä¸"; |
| | | default -> "å¾
æ§è¡"; |
| | | }); |
| | | item.setRangeStart(run.getRangeStart() == null ? null : run.getRangeStart().format(DAY_FORMAT)); |
| | | item.setRangeEnd(run.getRangeEnd() == null ? null : run.getRangeEnd().format(DAY_FORMAT)); |
| | | item.setTotalTasks(nvl(run.getTotalTasks())); |
| | | item.setSuccessTasks(nvl(run.getSuccessTasks())); |
| | | item.setEmptyTasks(nvl(run.getEmptyTasks())); |
| | | item.setFailedTasks(nvl(run.getFailedTasks())); |
| | | item.setStartedAt(run.getStartedAt() == null ? null : run.getStartedAt().format(DATETIME_FORMAT)); |
| | | item.setFinishedAt(run.getFinishedAt() == null ? null : run.getFinishedAt().format(DATETIME_FORMAT)); |
| | | return item; |
| | | } |
| | | |
| | | private void applyCollectionStatus(EnergyCollectionVO.Medium medium, boolean empty, LocalDate dataEnd, |
| | | LocalDateTime lastSuccess, boolean manualOnly, boolean simulatedOnly, |
| | | LocalDate today) { |
| | | if (empty) { |
| | | medium.setStatus("NO_DEVICE"); |
| | | medium.setStatusText("æªæ¥å
¥è®¾å¤"); |
| | | return; |
| | | } |
| | | if (dataEnd == null) { |
| | | medium.setStatus("EMPTY"); |
| | | medium.setStatusText("ææ ééæ°æ®"); |
| | | return; |
| | | } |
| | | if (simulatedOnly) { |
| | | if (dataEnd.isBefore(today.minusDays(1))) { |
| | | medium.setStatus("PARTIAL"); |
| | | medium.setStatusText("èªå¨ééæ°æ®æ»å " + ChronoUnit.DAYS.between(dataEnd, today) + " 天"); |
| | | } else { |
| | | medium.setStatus("OK"); |
| | | medium.setStatusText("èªå¨ééæ°æ®"); |
| | | } |
| | | return; |
| | | } |
| | | if (manualOnly) { |
| | | if (dataEnd.isBefore(today.minusDays(1))) { |
| | | medium.setStatus("PARTIAL"); |
| | | medium.setStatusText("æ°æ®æ»å " + ChronoUnit.DAYS.between(dataEnd, today) + " 天"); |
| | | } else { |
| | | medium.setStatus("OK"); |
| | | medium.setStatusText("æå·¥æè¡¨æ°æ®"); |
| | | } |
| | | return; |
| | | } |
| | | if (lastSuccess == null || lastSuccess.isBefore(EnergyMeterSupport.now().minusHours(36))) { |
| | | medium.setStatus("STALE"); |
| | | medium.setStatusText("è¶
è¿ 36 å°æ¶æ æåéé"); |
| | | return; |
| | | } |
| | | if (dataEnd.isBefore(today.minusDays(1))) { |
| | | medium.setStatus("PARTIAL"); |
| | | medium.setStatusText("æ°æ®æ»å " + ChronoUnit.DAYS.between(dataEnd, today) + " 天"); |
| | | return; |
| | | } |
| | | medium.setStatus("OK"); |
| | | medium.setStatusText("é鿣叏"); |
| | | } |
| | | |
| | | /** |
| | | * å¨çº¿å£å¾ï¼ä¾åºåæ è®°å¨çº¿ï¼ææè¿ 36 å°æ¶å
ææåééã |
| | | * |
| | | * <p>ç¬¬ä¸æ¹æ¡£æ¡çå¨çº¿æ è®°åªå¨ç»å®/éªè¯æ¶è½åºï¼é¿æä¸å·æ°ï¼ä¸è½åç¬ä½ä¸ºâå¨çº¿â便®ã</p> |
| | | */ |
| | | private boolean isOnline(EnergyMeterDevice device) { |
| | | if (Integer.valueOf(1).equals(device.getOnlineStatus())) { |
| | | return true; |
| | | } |
| | | return device.getLastSuccessAt() != null |
| | | && device.getLastSuccessAt().isAfter(EnergyMeterSupport.now().minusHours(36)); |
| | | } |
| | | |
| | | /* ------------------------------------------------------------------ */ |
| | | /* 宿¶çæ§ */ |
| | | /* ------------------------------------------------------------------ */ |
| | | |
| | | @Override |
| | | public EnergyRealtimeVO realtime(Long meterId) { |
| | | LocalDate today = EnergyMeterSupport.today(); |
| | | LocalDate windowStart = today.minusDays(TREND_DAYS); |
| | | LocalDate monthStart = today.withDayOfMonth(1); |
| | | |
| | | EnergyRealtimeVO vo = new EnergyRealtimeVO(); |
| | | vo.setGeneratedAt(EnergyMeterSupport.now().format(DATETIME_FORMAT)); |
| | | vo.setToday(today.format(DAY_FORMAT)); |
| | | vo.setMockMode(provider.mockMode()); |
| | | vo.setMeterId(meterId); |
| | | |
| | | List<EnergyMeterDevice> devices; |
| | | List<String> types; |
| | | if (meterId != null) { |
| | | EnergyMeterDevice device = requireDevice(meterId); |
| | | devices = List.of(device); |
| | | String type = EnergyMeterConstants.canonicalType(device.getMeterType()); |
| | | if (type == null) { |
| | | throw new ServiceException("设å¤ä»è´¨ç±»åä¸åæ³"); |
| | | } |
| | | types = List.of(type); |
| | | vo.setScopeLabel(device.getDisplayName() + "ï¼" + device.getMeterAddress() + "ï¼"); |
| | | } else { |
| | | devices = loadDevices(null); |
| | | types = ALL_TYPES; |
| | | vo.setScopeLabel("å
¨é¨å·²æ¥å
¥è¡¨å
·ï¼" + devices.size() + " å°ï¼"); |
| | | } |
| | | |
| | | Map<String, Map<LocalDate, BigDecimal>> dailyByType = new HashMap<>(); |
| | | for (String type : types) { |
| | | List<EnergyMeterDevice> typeDevices = devices.stream() |
| | | .filter(d -> type.equals(d.getMeterType())) |
| | | .collect(Collectors.toList()); |
| | | List<Long> ids = typeDevices.stream().map(EnergyMeterDevice::getId).collect(Collectors.toList()); |
| | | |
| | | Map<LocalDate, BigDecimal> windowDaily = ids.isEmpty() ? Map.of() |
| | | : toDayMap(measurementMapper.sumDailyUsage(ids, EnergyMeterConstants.usageMetric(type), |
| | | windowStart.atStartOfDay(), today.plusDays(1).atStartOfDay())); |
| | | dailyByType.put(type, windowDaily); |
| | | |
| | | EnergyRealtimeVO.Medium medium = new EnergyRealtimeVO.Medium(); |
| | | medium.setMeterType(type); |
| | | medium.setMeterName(mediumName(type)); |
| | | medium.setUnit(EnergyMeterConstants.unit(type)); |
| | | medium.setDeviceCount(typeDevices.size()); |
| | | |
| | | LocalDate latestDate = latestDate(windowDaily, today, windowStart); |
| | | BigDecimal latest = latestDate == null ? null : windowDaily.get(latestDate); |
| | | LocalDate previousDate = latestDate == null ? null |
| | | : latestDate(windowDaily, latestDate.minusDays(1), windowStart); |
| | | BigDecimal previous = previousDate == null ? null : windowDaily.get(previousDate); |
| | | |
| | | boolean simulatedFresh = latestDate != null && !latestDate.isBefore(today.minusDays(1)); |
| | | medium.setOnlineCount((int) typeDevices.stream() |
| | | .filter(d -> isOnline(d) |
| | | || (EnergyMeterConstants.isSimulated(d.getSimulated()) && simulatedFresh)) |
| | | .count()); |
| | | |
| | | medium.setLatestUsage(latest); |
| | | medium.setLatestUsageDate(latestDate == null ? null : latestDate.format(DAY_FORMAT)); |
| | | medium.setPreviousUsage(previous); |
| | | medium.setPreviousUsageDate(previousDate == null ? null : previousDate.format(DAY_FORMAT)); |
| | | medium.setCompareRate(compareRate(latest, previous)); |
| | | |
| | | BigDecimal monthTotal = null; |
| | | if (!ids.isEmpty()) { |
| | | Map<LocalDate, BigDecimal> monthDaily = toDayMap(measurementMapper.sumDailyUsage(ids, |
| | | EnergyMeterConstants.usageMetric(type), monthStart.atStartOfDay(), |
| | | today.plusDays(1).atStartOfDay())); |
| | | monthTotal = sumValues(monthDaily.values()); |
| | | if (monthTotal != null) { |
| | | monthTotal = monthTotal.setScale(3, RoundingMode.HALF_UP); |
| | | } |
| | | } |
| | | medium.setMonthTotal(monthTotal); |
| | | |
| | | List<BigDecimal> trendValues = new ArrayList<>(); |
| | | for (int i = TREND_DAYS - 1; i >= 0; i--) { |
| | | BigDecimal value = windowDaily.get(today.minusDays(i)); |
| | | if (value != null) { |
| | | trendValues.add(value); |
| | | } |
| | | } |
| | | medium.setAvgDaily(average(trendValues)); |
| | | medium.setPeakDaily(trendValues.stream().max(BigDecimal::compareTo).orElse(null)); |
| | | |
| | | EnergyMeterMeasurement reading = null; |
| | | for (EnergyMeterDevice device : typeDevices) { |
| | | EnergyMeterMeasurement point = measurementMapper.selectLatestPoint(device.getId(), |
| | | EnergyMeterConstants.readingMetric(type)); |
| | | if (point != null && (reading == null || point.getMeasureTime().isAfter(reading.getMeasureTime()))) { |
| | | reading = point; |
| | | } |
| | | } |
| | | if (reading != null) { |
| | | medium.setLatestReading(reading.getMetricValue()); |
| | | medium.setLatestReadingTime(reading.getMeasureTime().format(DATETIME_FORMAT)); |
| | | } |
| | | |
| | | LocalDateTime lastSuccess = typeDevices.stream() |
| | | .map(EnergyMeterDevice::getLastSuccessAt) |
| | | .filter(Objects::nonNull) |
| | | .max(LocalDateTime::compareTo) |
| | | .orElse(null); |
| | | medium.setLastSuccessAt(lastSuccess == null ? null : lastSuccess.format(DATETIME_FORMAT)); |
| | | |
| | | boolean manualOnly = !typeDevices.isEmpty() |
| | | && typeDevices.stream().noneMatch(d -> |
| | | EnergyMeterConstants.isAutoCollect(d.getSourceType(), d.getSimulated())); |
| | | boolean simulatedOnly = !typeDevices.isEmpty() |
| | | && typeDevices.stream().allMatch(d -> EnergyMeterConstants.isSimulated(d.getSimulated())); |
| | | applyRealtimeStatus(medium, typeDevices.isEmpty(), latest, latestDate, lastSuccess, |
| | | manualOnly, simulatedOnly, today); |
| | | vo.getMedia().add(medium); |
| | | } |
| | | |
| | | /* è¿ 7 æ¥è¶å¿ */ |
| | | for (int i = TREND_DAYS - 1; i >= 0; i--) { |
| | | LocalDate day = today.minusDays(i); |
| | | EnergyRealtimeVO.TrendPoint point = new EnergyRealtimeVO.TrendPoint(); |
| | | point.setDay(day.format(DAY_FORMAT)); |
| | | point.setWater(dailyByType.getOrDefault(EnergyMeterConstants.TYPE_WATER, Map.of()).get(day)); |
| | | point.setElectric(dailyByType.getOrDefault(EnergyMeterConstants.TYPE_ELECTRIC, Map.of()).get(day)); |
| | | point.setGas(dailyByType.getOrDefault(EnergyMeterConstants.TYPE_GAS, Map.of()).get(day)); |
| | | vo.getTrend().add(point); |
| | | } |
| | | |
| | | /* çµè¡¨å®æ¶æ²çº¿ */ |
| | | if (types.contains(EnergyMeterConstants.TYPE_ELECTRIC)) { |
| | | EnergyRealtimeVO.Electric electric = buildElectric(meterId); |
| | | vo.setElectric(electric); |
| | | if (electric != null) { |
| | | for (EnergyRealtimeVO.Medium medium : vo.getMedia()) { |
| | | if (EnergyMeterConstants.TYPE_ELECTRIC.equals(medium.getMeterType())) { |
| | | medium.setCurrentPower(electric.getCurrentPower()); |
| | | medium.setPowerFactor(electric.getPowerFactor()); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | buildAlerts(vo, devices, today); |
| | | return vo; |
| | | } |
| | | |
| | | private EnergyRealtimeVO.Electric buildElectric(Long meterId) { |
| | | ElectricMeterDashboardVO dashboard; |
| | | try { |
| | | dashboard = dashboardService.dashboard(meterId, 0); |
| | | } catch (Exception e) { |
| | | log.warn("宿¶çæ§æ¥è¯¢çµè¡¨ 15 åéæ°æ®å¤±è´¥ï¼{}", e.getMessage()); |
| | | return null; |
| | | } |
| | | EnergyRealtimeVO.Electric electric = new EnergyRealtimeVO.Electric(); |
| | | electric.setRangeStart(dashboard.getToday() == null ? null : dashboard.getToday().getRangeStart()); |
| | | electric.setRangeEnd(dashboard.getToday() == null ? null : dashboard.getToday().getRangeEnd()); |
| | | electric.setTodayTotal(dashboard.getToday() == null ? null : dashboard.getToday().getTotal()); |
| | | electric.setYesterdaySamePeriodTotal(dashboard.getToday() == null ? null |
| | | : dashboard.getToday().getYesterdaySamePeriodTotal()); |
| | | |
| | | List<ElectricMeterDashboardVO.QuarterPoint> points = dashboard.getToday() == null |
| | | ? List.of() : dashboard.getToday().getSeries(); |
| | | BigDecimal lastPower = null; |
| | | BigDecimal lastFactor = null; |
| | | for (ElectricMeterDashboardVO.QuarterPoint point : points) { |
| | | EnergyRealtimeVO.CurvePoint curvePoint = new EnergyRealtimeVO.CurvePoint(); |
| | | curvePoint.setTime(point.getTime()); |
| | | curvePoint.setActive(point.getActive()); |
| | | if (point.getActive() == null) { |
| | | electric.getSeries().add(curvePoint); |
| | | continue; |
| | | } |
| | | // 15 åéçµéæç®åçï¼kWh / 0.25h = kW |
| | | BigDecimal power = point.getActive().multiply(BigDecimal.valueOf(4)).setScale(3, RoundingMode.HALF_UP); |
| | | curvePoint.setPower(power); |
| | | electric.getSeries().add(curvePoint); |
| | | lastPower = power; |
| | | lastFactor = powerFactor(power, point.getReactive()); |
| | | } |
| | | electric.setCurrentPower(lastPower); |
| | | electric.setPowerFactor(lastFactor); |
| | | return electric; |
| | | } |
| | | |
| | | private BigDecimal powerFactor(BigDecimal activePower, BigDecimal reactiveEnergy) { |
| | | if (activePower == null) { |
| | | return null; |
| | | } |
| | | BigDecimal reactivePower = reactiveEnergy == null ? BigDecimal.ZERO |
| | | : reactiveEnergy.multiply(BigDecimal.valueOf(4)); |
| | | double p = activePower.doubleValue(); |
| | | double q = reactivePower.doubleValue(); |
| | | if (p <= 0 && q <= 0) { |
| | | return null; |
| | | } |
| | | double factor = p / Math.sqrt(p * p + q * q); |
| | | return BigDecimal.valueOf(Math.min(factor, 1.0)).setScale(3, RoundingMode.HALF_UP); |
| | | } |
| | | |
| | | private void applyRealtimeStatus(EnergyRealtimeVO.Medium medium, boolean noDevice, BigDecimal latest, |
| | | LocalDate latestDate, LocalDateTime lastSuccess, boolean manualOnly, |
| | | boolean simulatedOnly, LocalDate today) { |
| | | if (noDevice) { |
| | | medium.setStatus("NO_DEVICE"); |
| | | medium.setStatusText("æªæ¥å
¥è®¾å¤"); |
| | | return; |
| | | } |
| | | if (latest == null && medium.getLatestReading() == null) { |
| | | medium.setStatus("EMPTY"); |
| | | medium.setStatusText("ææ æ°æ®"); |
| | | return; |
| | | } |
| | | if (simulatedOnly) { |
| | | if (latestDate != null && latestDate.isBefore(today.minusDays(1))) { |
| | | medium.setStatus("STALE"); |
| | | medium.setStatusText("èªå¨ééæ°æ®æ»å"); |
| | | } else { |
| | | medium.setStatus("OK"); |
| | | medium.setStatusText("èªå¨ééæ°æ®"); |
| | | } |
| | | return; |
| | | } |
| | | if (manualOnly) { |
| | | if (latestDate != null && latestDate.isBefore(today.minusDays(1))) { |
| | | medium.setStatus("STALE"); |
| | | medium.setStatusText("æè¡¨æ°æ®æ»å"); |
| | | } else { |
| | | medium.setStatus("OK"); |
| | | medium.setStatusText("æå·¥æè¡¨æ°æ®"); |
| | | } |
| | | return; |
| | | } |
| | | if (lastSuccess == null || lastSuccess.isBefore(EnergyMeterSupport.now().minusHours(36))) { |
| | | medium.setStatus("STALE"); |
| | | medium.setStatusText("ééæ»å"); |
| | | return; |
| | | } |
| | | medium.setStatus("OK"); |
| | | medium.setStatusText("è¿è¡æ£å¸¸"); |
| | | } |
| | | |
| | | private void buildAlerts(EnergyRealtimeVO vo, List<EnergyMeterDevice> devices, LocalDate today) { |
| | | List<EnergyRealtimeVO.Alert> alerts = vo.getAlerts(); |
| | | for (EnergyRealtimeVO.Medium medium : vo.getMedia()) { |
| | | if ("STALE".equals(medium.getStatus()) || "EMPTY".equals(medium.getStatus())) { |
| | | alerts.add(alert("warning", medium.getMeterName() + "ï¼" + medium.getStatusText() |
| | | + "ï¼è¯·æ£æ¥è®¾å¤ææå¨éé")); |
| | | } |
| | | } |
| | | int deviceAlerts = 0; |
| | | for (EnergyMeterDevice device : devices) { |
| | | if (StringUtils.isNotBlank(device.getLastErrorCode()) && deviceAlerts < 3) { |
| | | String message = StringUtils.isBlank(device.getLastErrorMessage()) |
| | | ? device.getLastErrorCode() : device.getLastErrorMessage(); |
| | | alerts.add(alert("warning", "ã" + device.getDisplayName() + "ãæè¿ä¸æ¬¡éé失败ï¼" + message)); |
| | | deviceAlerts++; |
| | | } |
| | | } |
| | | if (Boolean.TRUE.equals(vo.getMockMode())) { |
| | | alerts.add(alert("info", "å½å为æ¼ç¤ºæ°æ®æ¨¡å¼ï¼ééç»æç±æ¬å°æ¨¡æçæï¼ä»
ç¨äºèè°ä¸é¡µé¢æ¼ç¤ºã")); |
| | | } |
| | | if (alerts.size() > 6) { |
| | | vo.setAlerts(new ArrayList<>(alerts.subList(0, 6))); |
| | | } |
| | | } |
| | | |
| | | private EnergyRealtimeVO.Alert alert(String level, String text) { |
| | | EnergyRealtimeVO.Alert alert = new EnergyRealtimeVO.Alert(); |
| | | alert.setLevel(level); |
| | | alert.setText(text); |
| | | return alert; |
| | | } |
| | | |
| | | /* ------------------------------------------------------------------ */ |
| | | /* ç»è®¡åæ */ |
| | | /* ------------------------------------------------------------------ */ |
| | | |
| | | @Override |
| | | public EnergyReportVO report(String startDate, String endDate, String granularity, String meterType, |
| | | String dimension) { |
| | | LocalDate today = EnergyMeterSupport.today(); |
| | | LocalDate start = StringUtils.isBlank(startDate) ? today.withDayOfMonth(1) : parseDate(startDate, "å¼å§æ¥æ"); |
| | | LocalDate end = StringUtils.isBlank(endDate) ? today : parseDate(endDate, "ç»ææ¥æ"); |
| | | if (end.isBefore(start)) { |
| | | throw new ServiceException("ç»ææ¥æä¸è½æ©äºå¼å§æ¥æ"); |
| | | } |
| | | if (ChronoUnit.DAYS.between(start, end) > MAX_REPORT_DAYS) { |
| | | throw new ServiceException("ç»è®¡è·¨åº¦ä¸è½è¶
è¿ " + MAX_REPORT_DAYS + " 天ï¼è¯·ç¼©å°æ¶é´èå´"); |
| | | } |
| | | |
| | | String gran = "MONTH".equalsIgnoreCase(StringUtils.trim(granularity)) ? "MONTH" : "DAY"; |
| | | String dim = "DEVICE".equalsIgnoreCase(StringUtils.trim(dimension)) ? "DEVICE" : "MEDIUM"; |
| | | String filterType = StringUtils.isBlank(meterType) || "ALL".equalsIgnoreCase(meterType.trim()) |
| | | ? "ALL" : EnergyMeterConstants.canonicalType(meterType); |
| | | if (filterType == null) { |
| | | throw new ServiceException("è½æºç±»ååªæ¯ææ°´è¡¨ï¼WATERï¼ãçµè¡¨ï¼ELECTRICï¼æè¸æ±½è¡¨ï¼GASï¼"); |
| | | } |
| | | List<String> types = "ALL".equals(filterType) ? ALL_TYPES : List.of(filterType); |
| | | |
| | | EnergyReportVO vo = new EnergyReportVO(); |
| | | vo.setGeneratedAt(EnergyMeterSupport.now().format(DATETIME_FORMAT)); |
| | | vo.setMockMode(provider.mockMode()); |
| | | vo.setStart(start.format(DAY_FORMAT)); |
| | | vo.setEnd(end.format(DAY_FORMAT)); |
| | | vo.setGranularity(gran); |
| | | vo.setDimension(dim); |
| | | vo.setMeterType(filterType); |
| | | |
| | | List<String> periods = buildPeriods(start, end, gran); |
| | | vo.setPeriods(periods); |
| | | vo.setTotalPeriods(periods.size()); |
| | | vo.setNote("ç»è®¡å£å¾ï¼ä»
æ±æ»æ¥ç²åº¦ç¨éï¼è¡¨ç ä¸åä¸ç´¯å ï¼ç¼ºå¤±å¨ææç©ºå¼å±ç¤ºï¼ä¸æ 0 计ç®ã"); |
| | | |
| | | List<EnergyMeterDevice> devices = loadDevices(null).stream() |
| | | .filter(d -> types.contains(d.getMeterType())) |
| | | .collect(Collectors.toList()); |
| | | |
| | | Map<String, Map<String, BigDecimal>> valuesByType = new HashMap<>(); |
| | | for (String type : types) { |
| | | List<Long> ids = devices.stream() |
| | | .filter(d -> type.equals(d.getMeterType())) |
| | | .map(EnergyMeterDevice::getId) |
| | | .collect(Collectors.toList()); |
| | | Map<String, BigDecimal> values = new HashMap<>(); |
| | | if (!ids.isEmpty()) { |
| | | if ("MONTH".equals(gran)) { |
| | | for (MonthlyUsageRow row : measurementMapper.sumMonthlyUsage(ids, |
| | | EnergyMeterConstants.usageMetric(type), start.atStartOfDay(), |
| | | end.plusDays(1).atStartOfDay())) { |
| | | if (row.getMonth() != null && row.getTotal() != null) { |
| | | values.put(row.getMonth(), row.getTotal()); |
| | | } |
| | | } |
| | | } else { |
| | | for (DailyUsageRow row : measurementMapper.sumDailyUsage(ids, |
| | | EnergyMeterConstants.usageMetric(type), start.atStartOfDay(), |
| | | end.plusDays(1).atStartOfDay())) { |
| | | if (row.getDay() != null && row.getTotal() != null) { |
| | | values.put(row.getDay(), row.getTotal()); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | valuesByType.put(type, values); |
| | | } |
| | | |
| | | int coveredPeriods = 0; |
| | | for (String period : periods) { |
| | | EnergyReportVO.PeriodRow row = new EnergyReportVO.PeriodRow(); |
| | | row.setPeriod(period); |
| | | boolean hasValue = false; |
| | | for (String type : types) { |
| | | BigDecimal value = valuesByType.get(type).get(period); |
| | | if (value != null) { |
| | | hasValue = true; |
| | | } |
| | | if (EnergyMeterConstants.isWater(type)) { |
| | | row.setWater(value); |
| | | } else if (EnergyMeterConstants.isElectric(type)) { |
| | | row.setElectric(value); |
| | | } else { |
| | | row.setGas(value); |
| | | } |
| | | } |
| | | if (hasValue) { |
| | | coveredPeriods++; |
| | | } |
| | | vo.getRows().add(row); |
| | | } |
| | | vo.setCoveredPeriods(coveredPeriods); |
| | | |
| | | Map<String, BigDecimal> mediumTotals = new HashMap<>(); |
| | | for (String type : types) { |
| | | BigDecimal total = sumValues(valuesByType.get(type).values()); |
| | | mediumTotals.put(type, total); |
| | | EnergyReportVO.MediumTotal mediumTotal = new EnergyReportVO.MediumTotal(); |
| | | mediumTotal.setMeterType(type); |
| | | mediumTotal.setMeterName(mediumName(type)); |
| | | mediumTotal.setUnit(EnergyMeterConstants.unit(type)); |
| | | mediumTotal.setTotal(total == null ? null : total.setScale(3, RoundingMode.HALF_UP)); |
| | | mediumTotal.setDeviceCount((int) devices.stream() |
| | | .filter(d -> type.equals(d.getMeterType())).count()); |
| | | vo.getTotals().add(mediumTotal); |
| | | } |
| | | |
| | | for (String type : types) { |
| | | List<EnergyMeterDevice> typeDevices = devices.stream() |
| | | .filter(d -> type.equals(d.getMeterType())) |
| | | .collect(Collectors.toList()); |
| | | if (typeDevices.isEmpty()) { |
| | | continue; |
| | | } |
| | | List<Long> ids = typeDevices.stream().map(EnergyMeterDevice::getId).collect(Collectors.toList()); |
| | | Map<Long, BigDecimal> usageMap = new HashMap<>(); |
| | | for (MeterUsageRow row : measurementMapper.sumUsageByMeter(ids, EnergyMeterConstants.usageMetric(type), |
| | | start.atStartOfDay(), end.plusDays(1).atStartOfDay())) { |
| | | if (row.getMeterId() != null && row.getTotal() != null) { |
| | | usageMap.put(row.getMeterId(), row.getTotal()); |
| | | } |
| | | } |
| | | BigDecimal mediumTotal = mediumTotals.get(type); |
| | | for (EnergyMeterDevice device : typeDevices) { |
| | | EnergyReportVO.DeviceRow row = new EnergyReportVO.DeviceRow(); |
| | | row.setMeterId(device.getId()); |
| | | row.setMeterName(device.getDisplayName()); |
| | | row.setMeterAddress(device.getMeterAddress()); |
| | | row.setMeterType(type); |
| | | row.setMeterTypeName(mediumName(type)); |
| | | row.setSourceTypeName(EnergyMeterConstants.isAutoCollect(device.getSourceType(), device.getSimulated()) |
| | | ? "èªå¨éé" : "æå·¥æè¡¨"); |
| | | row.setUnit(EnergyMeterConstants.unit(type)); |
| | | BigDecimal total = usageMap.get(device.getId()); |
| | | row.setTotal(total == null ? null : total.setScale(3, RoundingMode.HALF_UP)); |
| | | if (total != null && mediumTotal != null && mediumTotal.compareTo(BigDecimal.ZERO) > 0) { |
| | | row.setShare(total.multiply(BigDecimal.valueOf(100)) |
| | | .divide(mediumTotal, 1, RoundingMode.HALF_UP)); |
| | | } |
| | | vo.getDevices().add(row); |
| | | } |
| | | } |
| | | vo.getDevices().sort(Comparator |
| | | .comparingInt((EnergyReportVO.DeviceRow row) -> typeOrder(row.getMeterType())) |
| | | .thenComparing(EnergyReportVO.DeviceRow::getTotal, Comparator.nullsLast(Comparator.reverseOrder())) |
| | | .thenComparing(EnergyReportVO.DeviceRow::getMeterId)); |
| | | return vo; |
| | | } |
| | | |
| | | private int typeOrder(String type) { |
| | | if (EnergyMeterConstants.isWater(type)) { |
| | | return 0; |
| | | } |
| | | if (EnergyMeterConstants.isElectric(type)) { |
| | | return 1; |
| | | } |
| | | return 2; |
| | | } |
| | | |
| | | private List<String> buildPeriods(LocalDate start, LocalDate end, String gran) { |
| | | List<String> periods = new ArrayList<>(); |
| | | if ("MONTH".equals(gran)) { |
| | | YearMonth month = YearMonth.from(start); |
| | | YearMonth last = YearMonth.from(end); |
| | | while (!month.isAfter(last)) { |
| | | periods.add(month.toString()); |
| | | month = month.plusMonths(1); |
| | | } |
| | | } else { |
| | | for (LocalDate day = start; !day.isAfter(end); day = day.plusDays(1)) { |
| | | periods.add(day.format(DAY_FORMAT)); |
| | | } |
| | | } |
| | | return periods; |
| | | } |
| | | |
| | | /* ------------------------------------------------------------------ */ |
| | | /* å·¥å
· */ |
| | | /* ------------------------------------------------------------------ */ |
| | | |
| | | private List<EnergyMeterDevice> loadDevices(String meterType) { |
| | | LambdaQueryWrapper<EnergyMeterDevice> wrapper = new LambdaQueryWrapper<>(); |
| | | Long tenantId = EnergyMeterSupport.currentTenantId(); |
| | | if (tenantId != null) { |
| | | wrapper.eq(EnergyMeterDevice::getTenantId, tenantId); |
| | | } |
| | | if (StringUtils.isNotBlank(meterType)) { |
| | | wrapper.eq(EnergyMeterDevice::getMeterType, meterType); |
| | | } |
| | | wrapper.eq(EnergyMeterDevice::getEnabled, 1) |
| | | .eq(EnergyMeterDevice::getBindStatus, EnergyMeterConstants.BIND_VERIFIED) |
| | | .orderByAsc(EnergyMeterDevice::getId); |
| | | return deviceMapper.selectList(wrapper); |
| | | } |
| | | |
| | | private EnergyMeterDevice requireDevice(Long meterId) { |
| | | EnergyMeterDevice device = deviceMapper.selectById(meterId); |
| | | if (device == null) { |
| | | throw new ServiceException("设å¤ä¸å卿已å é¤"); |
| | | } |
| | | Long tenantId = EnergyMeterSupport.currentTenantId(); |
| | | if (tenantId != null && device.getTenantId() != null && !tenantId.equals(device.getTenantId())) { |
| | | throw new ServiceException("æ æè®¿é®è¯¥è®¾å¤"); |
| | | } |
| | | return device; |
| | | } |
| | | |
| | | private String mediumName(String meterType) { |
| | | if (EnergyMeterConstants.isWater(meterType)) { |
| | | return "水表"; |
| | | } |
| | | if (EnergyMeterConstants.isElectric(meterType)) { |
| | | return "çµè¡¨"; |
| | | } |
| | | if (EnergyMeterConstants.isGas(meterType)) { |
| | | return "è¸æ±½è¡¨"; |
| | | } |
| | | return meterType; |
| | | } |
| | | |
| | | private Map<LocalDate, BigDecimal> toDayMap(List<DailyUsageRow> rows) { |
| | | Map<LocalDate, BigDecimal> map = new HashMap<>(); |
| | | for (DailyUsageRow row : rows) { |
| | | if (row.getDay() != null && row.getTotal() != null) { |
| | | map.put(LocalDate.parse(row.getDay()), row.getTotal()); |
| | | } |
| | | } |
| | | return map; |
| | | } |
| | | |
| | | private LocalDate latestDate(Map<LocalDate, BigDecimal> daily, LocalDate from, LocalDate floor) { |
| | | LocalDate day = from; |
| | | while (!day.isBefore(floor)) { |
| | | BigDecimal value = daily.get(day); |
| | | if (value != null) { |
| | | return day; |
| | | } |
| | | day = day.minusDays(1); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | private BigDecimal compareRate(BigDecimal latest, BigDecimal previous) { |
| | | if (latest == null || previous == null || previous.compareTo(BigDecimal.ZERO) <= 0) { |
| | | return null; |
| | | } |
| | | return latest.subtract(previous) |
| | | .multiply(BigDecimal.valueOf(100)) |
| | | .divide(previous, 1, RoundingMode.HALF_UP); |
| | | } |
| | | |
| | | private BigDecimal sumValues(java.util.Collection<BigDecimal> values) { |
| | | BigDecimal sum = BigDecimal.ZERO; |
| | | boolean hasValue = false; |
| | | for (BigDecimal value : values) { |
| | | if (value != null) { |
| | | sum = sum.add(value); |
| | | hasValue = true; |
| | | } |
| | | } |
| | | return hasValue ? sum : null; |
| | | } |
| | | |
| | | private BigDecimal average(List<BigDecimal> values) { |
| | | if (values == null || values.isEmpty()) { |
| | | return null; |
| | | } |
| | | BigDecimal sum = BigDecimal.ZERO; |
| | | for (BigDecimal value : values) { |
| | | sum = sum.add(value); |
| | | } |
| | | return sum.divide(BigDecimal.valueOf(values.size()), 3, RoundingMode.HALF_UP); |
| | | } |
| | | |
| | | private int nvl(Integer value) { |
| | | return value == null ? 0 : value; |
| | | } |
| | | |
| | | private LocalDate parseDate(String value, String label) { |
| | | try { |
| | | return LocalDate.parse(value.trim()); |
| | | } catch (Exception e) { |
| | | throw new ServiceException(label + "æ ¼å¼åºä¸º yyyy-MM-dd"); |
| | | } |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.util; |
| | | |
| | | import com.ruoyi.common.utils.SecurityUtils; |
| | | |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | import java.time.ZoneId; |
| | | |
| | | /** |
| | | * ç»å½æä¸æ¶é´å·¥å
·ï¼ç³»ç»çº§å®æ¶ä»»å¡ä¸ä¼æºå¸¦ç»å½æï¼è¿éç»ä¸å
åºã |
| | | */ |
| | | public final class EnergyMeterSupport { |
| | | |
| | | private EnergyMeterSupport() { |
| | | } |
| | | |
| | | public static Long currentTenantId() { |
| | | try { |
| | | return SecurityUtils.getLoginUser().getTenantId(); |
| | | } catch (Exception e) { |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | public static Long currentUserId() { |
| | | try { |
| | | return SecurityUtils.getUserId(); |
| | | } catch (Exception e) { |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | public static boolean isAdmin() { |
| | | try { |
| | | return SecurityUtils.getLoginUser().getUser().isAdmin(); |
| | | } catch (Exception e) { |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | public static LocalDate today() { |
| | | return LocalDate.now(ZoneId.of("Asia/Shanghai")); |
| | | } |
| | | |
| | | public static LocalDateTime now() { |
| | | return LocalDateTime.now(ZoneId.of("Asia/Shanghai")); |
| | | } |
| | | |
| | | public static String truncate(String text, int maxLength) { |
| | | if (text == null) { |
| | | return null; |
| | | } |
| | | return text.length() <= maxLength ? text : text.substring(0, maxLength); |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serializable; |
| | | import java.math.BigDecimal; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * çµè¡¨å®æ¶çæ¿ï¼ä»æ¥ 15 åéæ²çº¿ + è¿ä¸å¨çµè½è´¨éã |
| | | * |
| | | * <p>åªå
å«çµéãåçãåçå æ°ï¼ä¸å
å«ä»»ä½è´¹ç¨å段ã</p> |
| | | */ |
| | | @Data |
| | | @Schema(description = "çµè¡¨å®æ¶çæ¿") |
| | | public class ElectricMeterDashboardVO implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | private String meterType = "ELECTRIC"; |
| | | |
| | | @Schema(description = "çµéåä½") |
| | | private String unit; |
| | | |
| | | private Long meterId; |
| | | |
| | | private String scopeLabel; |
| | | |
| | | private Integer deviceCount; |
| | | |
| | | private Boolean mockMode; |
| | | |
| | | @Schema(description = "仿¥æ°æ®") |
| | | private Today today; |
| | | |
| | | @Schema(description = "çµè½è´¨é") |
| | | private Quality quality; |
| | | |
| | | @Data |
| | | public static class Today implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | @Schema(description = "ä¸å¡æ¥æ yyyy-MM-dd") |
| | | private String date; |
| | | |
| | | @Schema(description = "彿¥æ°æ®èµ·å§ï¼å¦ 00:00") |
| | | private String rangeStart; |
| | | |
| | | @Schema(description = "彿¥æ°æ®æªæ¢ï¼å¦ 17:58") |
| | | private String rangeEnd; |
| | | |
| | | @Schema(description = "彿¥ç´¯è®¡ç¨çµé kWh") |
| | | private BigDecimal total; |
| | | |
| | | @Schema(description = "æ¨æ¥å
¨å¤©ç´¯è®¡ç¨çµé kWh") |
| | | private BigDecimal yesterdayTotal; |
| | | |
| | | @Schema(description = "æ¨æ¥å䏿¶å»ç´¯è®¡ç¨çµé kWh") |
| | | private BigDecimal yesterdaySamePeriodTotal; |
| | | |
| | | @Schema(description = "è¾æ¨æ¥åæ¶æ®µååç¾åæ¯ï¼æ¨æ¥æ æ°æ®æ¶ä¸º null") |
| | | private BigDecimal compareRate; |
| | | |
| | | @Schema(description = "仿¥ 96 个æ¶é´ç") |
| | | private List<QuarterPoint> series = new ArrayList<>(); |
| | | |
| | | @Schema(description = "æ¨æ¥ 96 个æ¶é´ç") |
| | | private List<QuarterPoint> yesterdaySeries = new ArrayList<>(); |
| | | } |
| | | |
| | | @Data |
| | | public static class QuarterPoint implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | @Schema(description = "æ¶é´çç»ææ¶é´ HH:mmï¼å¦ 17:45") |
| | | private String time; |
| | | |
| | | @Schema(description = "æåçµé kWh") |
| | | private BigDecimal active; |
| | | |
| | | @Schema(description = "æ åçµé kvarh") |
| | | private BigDecimal reactive; |
| | | } |
| | | |
| | | @Data |
| | | public static class Quality implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | @Schema(description = "ç»è®¡å¼å§æ¥æ") |
| | | private String weekStart; |
| | | |
| | | @Schema(description = "ç»è®¡ç»ææ¥æ") |
| | | private String weekEnd; |
| | | |
| | | @Schema(description = "è¿ä¸å¨ / ä¸ä¸å¨") |
| | | private String label; |
| | | |
| | | @Schema(description = "æå°æ¶èåçåçç¹") |
| | | private List<PowerPoint> series = new ArrayList<>(); |
| | | } |
| | | |
| | | @Data |
| | | public static class PowerPoint implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | @Schema(description = "æ¶é´ï¼MM-dd HH:mm") |
| | | private String time; |
| | | |
| | | @Schema(description = "æååç kW") |
| | | private BigDecimal activePower; |
| | | |
| | | @Schema(description = "æ ååç kvar") |
| | | private BigDecimal reactivePower; |
| | | |
| | | @Schema(description = "åçå æ° 0-1") |
| | | private BigDecimal powerFactor; |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serializable; |
| | | import java.math.BigDecimal; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * è½èæ°æ®é鿦è§ï¼æ°´ãçµãè¸æ±½ä¸ç±»ä»è´¨çæ¥å
¥è®¾å¤ãå½éè¿åº¦ä¸æè¿ééæ¹æ¬¡ã |
| | | */ |
| | | @Data |
| | | @Schema(description = "è½èæ°æ®é鿦è§") |
| | | public class EnergyCollectionVO implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | @Schema(description = "çææ¶é´") |
| | | private String generatedAt; |
| | | |
| | | @Schema(description = "ä¸å¡æ¥æ yyyy-MM-dd") |
| | | private String today; |
| | | |
| | | @Schema(description = "æ¯å¦æ¼ç¤ºæ°æ®æ¨¡å¼") |
| | | private Boolean mockMode; |
| | | |
| | | @Schema(description = "ä¸ç±»ä»è´¨é鿦è§") |
| | | private List<Medium> media = new ArrayList<>(); |
| | | |
| | | @Schema(description = "æè¿ééæ¹æ¬¡") |
| | | private List<RunItem> runs = new ArrayList<>(); |
| | | |
| | | @Schema(description = "æè¿æ¹æ¬¡å¤±è´¥ä»»å¡æ°") |
| | | private Integer failedTaskCount = 0; |
| | | |
| | | @Schema(description = "æè¿æ¹æ¬¡å¾
æ§è¡ä»»å¡æ°") |
| | | private Integer pendingTaskCount = 0; |
| | | |
| | | @Data |
| | | @Schema(description = "åç±»ä»è´¨é鿦è§") |
| | | public static class Medium implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | private String meterType; |
| | | |
| | | @Schema(description = "ä»è´¨åç§°ï¼æ°´è¡¨ / çµè¡¨ / è¸æ±½è¡¨") |
| | | private String meterName; |
| | | |
| | | @Schema(description = "åä½ m3 / kWh") |
| | | private String unit; |
| | | |
| | | @Schema(description = "å¯ç¨è®¾å¤æ°") |
| | | private Integer deviceCount = 0; |
| | | |
| | | @Schema(description = "ç¬¬ä¸æ¹èªå¨ééè®¾å¤æ°") |
| | | private Integer providerCount = 0; |
| | | |
| | | @Schema(description = "æå·¥æè¡¨è®¾å¤æ°") |
| | | private Integer manualCount = 0; |
| | | |
| | | @Schema(description = "ä¾åºåä¾§å¨çº¿è®¾å¤æ°") |
| | | private Integer onlineCount = 0; |
| | | |
| | | @Schema(description = "æè¿æåééæ¶é´") |
| | | private String lastSuccessAt; |
| | | |
| | | @Schema(description = "å·²å½éæ°æ®èµ·å§æ¥æ") |
| | | private String dataStart; |
| | | |
| | | @Schema(description = "å·²å½éæ°æ®ç»ææ¥æ") |
| | | private String dataEnd; |
| | | |
| | | @Schema(description = "æ°æ®æªæ¢æ¥å·²å½éå°ç¨éçè®¾å¤æ°") |
| | | private Integer latestDayMeters = 0; |
| | | |
| | | @Schema(description = "è¿ 7 æ¥ææ°æ®ç天æ°") |
| | | private Integer coveredDays = 0; |
| | | |
| | | @Schema(description = "ç»è®¡å¤©æ°") |
| | | private Integer expectedDays = 7; |
| | | |
| | | @Schema(description = "è¿ 7 æ¥æ°æ®è¦çç 0-100") |
| | | private BigDecimal coverageRate; |
| | | |
| | | @Schema(description = "ééç¶æ OK/PARTIAL/STALE/EMPTY/NO_DEVICE") |
| | | private String status; |
| | | |
| | | @Schema(description = "ééç¶æææ¡") |
| | | private String statusText; |
| | | } |
| | | |
| | | @Data |
| | | @Schema(description = "æè¿ééæ¹æ¬¡") |
| | | public static class RunItem implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | private Long id; |
| | | |
| | | private String runKey; |
| | | |
| | | @Schema(description = "SCHEDULED/MANUAL/BACKFILL") |
| | | private String triggerType; |
| | | |
| | | private String triggerTypeName; |
| | | |
| | | @Schema(description = "æ¹æ¬¡ç¶æ") |
| | | private String status; |
| | | |
| | | private String statusText; |
| | | |
| | | @Schema(description = "忥å¼å§æ¥æ") |
| | | private String rangeStart; |
| | | |
| | | @Schema(description = "åæ¥ç»ææ¥æ") |
| | | private String rangeEnd; |
| | | |
| | | private Integer totalTasks; |
| | | |
| | | private Integer successTasks; |
| | | |
| | | private Integer emptyTasks; |
| | | |
| | | private Integer failedTasks; |
| | | |
| | | private String startedAt; |
| | | |
| | | private String finishedAt; |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serializable; |
| | | import java.math.BigDecimal; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * ç¨è½æ¦è§ï¼å¡çãæåº¦ææ¥ã年度ææãééç¶æã |
| | | * |
| | | * <p>è´¹ç¨å¨å£å¾æªç¡®è®¤åä¿æ nullï¼å端æ¾ç¤º {@code --}ï¼ä¸ä¼ç»å¶æ 0ã</p> |
| | | */ |
| | | @Data |
| | | @Schema(description = "æ°´çµè¡¨ç¨è½æ¦è§") |
| | | public class EnergyMeterOverviewVO implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | private String meterType; |
| | | |
| | | @Schema(description = "ç»è®¡ææ ç¼ç ") |
| | | private String metricCode; |
| | | |
| | | @Schema(description = "åä½ m3 / kWh") |
| | | private String unit; |
| | | |
| | | @Schema(description = "éä¸ç设å¤IDï¼å
¨é¨è®¾å¤æ¶ä¸ºç©º") |
| | | private Long meterId; |
| | | |
| | | @Schema(description = "æ°æ®èå´è¯´æ") |
| | | private String scopeLabel; |
| | | |
| | | @Schema(description = "åä¸ç»è®¡çè®¾å¤æ°é") |
| | | private Integer deviceCount; |
| | | |
| | | @Schema(description = "æ¯å¦æ¼ç¤ºæ°æ®æ¨¡å¼") |
| | | private Boolean mockMode; |
| | | |
| | | @Schema(description = "é䏿份 yyyy-MM") |
| | | private String selectedMonth; |
| | | |
| | | @Schema(description = "éä¸å¹´ä»½ yyyy") |
| | | private String selectedYear; |
| | | |
| | | @Schema(description = "éä¸æç´¯è®¡ç¨é") |
| | | private BigDecimal monthTotal; |
| | | |
| | | @Schema(description = "䏿åæç´¯è®¡ç¨é") |
| | | private BigDecimal monthPreviousTotal; |
| | | |
| | | @Schema(description = "éä¸å¹´ç´¯è®¡ç¨é") |
| | | private BigDecimal yearTotal; |
| | | |
| | | @Schema(description = "å»å¹´åæç´¯è®¡ç¨éï¼å¹´åº¦å¯¹æ¯ï¼") |
| | | private BigDecimal yearPreviousTotal; |
| | | |
| | | @Schema(description = "éä¸æè´¹ç¨ï¼å£å¾æªç¡®è®¤æ¶ä¸º null") |
| | | private BigDecimal monthCost; |
| | | |
| | | @Schema(description = "éä¸å¹´è´¹ç¨ï¼å£å¾æªç¡®è®¤æ¶ä¸º null") |
| | | private BigDecimal yearCost; |
| | | |
| | | @Schema(description = "ææ¥å¯¹æ¯åºå") |
| | | private List<MonthDayPoint> monthSeries = new ArrayList<>(); |
| | | |
| | | @Schema(description = "ææå¯¹æ¯åºå") |
| | | private List<YearMonthPoint> yearSeries = new ArrayList<>(); |
| | | |
| | | @Schema(description = "æè¿æåééæ¶é´") |
| | | private String lastSuccessAt; |
| | | |
| | | @Schema(description = "å·²ééæ°æ®èµ·å§æ¥æ") |
| | | private String dataStart; |
| | | |
| | | @Schema(description = "å·²ééæ°æ®ç»ææ¥æ") |
| | | private String dataEnd; |
| | | |
| | | @Schema(description = "æ°æ®æªè³è¯´æ") |
| | | private String dataThrough; |
| | | |
| | | @Schema(description = "æ¬æå·²éé天æ°") |
| | | private Integer collectedDays; |
| | | |
| | | @Schema(description = "æ¬æåºéé天æ°") |
| | | private Integer expectedDays; |
| | | |
| | | @Schema(description = "æ¬ææ°æ®è¦çç 0-100") |
| | | private BigDecimal coverageRate; |
| | | |
| | | @Schema(description = "ééç¶æ OK/PARTIAL/STALE/EMPTY") |
| | | private String syncStatus; |
| | | |
| | | @Schema(description = "ééç¶æææ¡") |
| | | private String syncStatusText; |
| | | |
| | | @Schema(description = "æ¯å¦ææ°æ®") |
| | | private Boolean hasData; |
| | | |
| | | @Schema(description = "æéæä»½æ¯å¦ææ°æ®") |
| | | private Boolean monthHasData; |
| | | |
| | | @Schema(description = "æé年份æ¯å¦ææ°æ®") |
| | | private Boolean yearHasData; |
| | | |
| | | @Data |
| | | public static class MonthDayPoint implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | @Schema(description = "æ¥ï¼yyyy-MM-dd") |
| | | private String day; |
| | | |
| | | @Schema(description = "彿彿¥ç¨é") |
| | | private BigDecimal current; |
| | | |
| | | @Schema(description = "䏿忥ç¨é") |
| | | private BigDecimal previous; |
| | | } |
| | | |
| | | @Data |
| | | public static class YearMonthPoint implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | @Schema(description = "æï¼yyyy-MM") |
| | | private String month; |
| | | |
| | | @Schema(description = "å½å¹´å½æç¨é") |
| | | private BigDecimal current; |
| | | |
| | | @Schema(description = "å»å¹´åæç¨é") |
| | | private BigDecimal previous; |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serializable; |
| | | import java.math.BigDecimal; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * è½è宿¶çæ§ï¼ä¸ç±»ä»è´¨ææ°ç¨éãè´è·ç¶æãè¿ 7 æ¥è¶å¿ä¸çµè¡¨ 15 åé宿¶æ²çº¿ã |
| | | * |
| | | * <p>水表ãè¸æ±½è¡¨åªææ¥å»ç»æ°æ®ï¼å±ç¤ºçæ¯æè¿ä¸ä¸ªææ°æ®çä¸å¡æ¥ï¼çµè¡¨é¢å¤æä¾å½æ¥ 15 åé宿¶çµéä¸åçã</p> |
| | | */ |
| | | @Data |
| | | @Schema(description = "è½è宿¶çæ§") |
| | | public class EnergyRealtimeVO implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | private String generatedAt; |
| | | |
| | | @Schema(description = "ä¸å¡æ¥æ yyyy-MM-dd") |
| | | private String today; |
| | | |
| | | private Boolean mockMode; |
| | | |
| | | @Schema(description = "æ°æ®èå´è¯´æ") |
| | | private String scopeLabel; |
| | | |
| | | @Schema(description = "åå°è®¾å¤IDï¼å
¨é¨è®¾å¤æ¶ä¸ºç©º") |
| | | private Long meterId; |
| | | |
| | | @Schema(description = "ä¸ç±»ä»è´¨å®æ¶æ¦è§") |
| | | private List<Medium> media = new ArrayList<>(); |
| | | |
| | | @Schema(description = "è¿ 7 æ¥ä¸ç±»ä»è´¨ç¨éè¶å¿") |
| | | private List<TrendPoint> trend = new ArrayList<>(); |
| | | |
| | | @Schema(description = "çµè¡¨å®æ¶æ°æ®") |
| | | private Electric electric; |
| | | |
| | | @Schema(description = "è¿è¡æç¤º") |
| | | private List<Alert> alerts = new ArrayList<>(); |
| | | |
| | | @Data |
| | | @Schema(description = "åç±»ä»è´¨å®æ¶æ¦è§") |
| | | public static class Medium implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | private String meterType; |
| | | |
| | | @Schema(description = "ä»è´¨åç§°ï¼æ°´è¡¨ / çµè¡¨ / è¸æ±½è¡¨") |
| | | private String meterName; |
| | | |
| | | @Schema(description = "åä½ m3 / kWh") |
| | | private String unit; |
| | | |
| | | private Integer deviceCount = 0; |
| | | |
| | | private Integer onlineCount = 0; |
| | | |
| | | @Schema(description = "æè¿ä¸ä¸ªææ°æ®çä¸å¡æ¥ç¨é") |
| | | private BigDecimal latestUsage; |
| | | |
| | | @Schema(description = "æè¿ç¨éä¸å¡æ¥æ yyyy-MM-dd") |
| | | private String latestUsageDate; |
| | | |
| | | @Schema(description = "ä¸ä¸ä¸ªææ°æ®çä¸å¡æ¥ç¨é") |
| | | private BigDecimal previousUsage; |
| | | |
| | | @Schema(description = "ä¸ä¸ç¨éä¸å¡æ¥æ yyyy-MM-dd") |
| | | private String previousUsageDate; |
| | | |
| | | @Schema(description = "è¾ä¸ä¸ä¸å¡æ¥ååç¾åæ¯") |
| | | private BigDecimal compareRate; |
| | | |
| | | @Schema(description = "æ¬æç´¯è®¡ç¨é") |
| | | private BigDecimal monthTotal; |
| | | |
| | | @Schema(description = "è¿ 7 æ¥æ¥åç¨é") |
| | | private BigDecimal avgDaily; |
| | | |
| | | @Schema(description = "è¿ 7 æ¥å³°å¼ç¨é") |
| | | private BigDecimal peakDaily; |
| | | |
| | | @Schema(description = "æè¿è¡¨ç ") |
| | | private BigDecimal latestReading; |
| | | |
| | | @Schema(description = "æè¿è¡¨ç æ¶é´") |
| | | private String latestReadingTime; |
| | | |
| | | @Schema(description = "æè¿æåééæ¶é´") |
| | | private String lastSuccessAt; |
| | | |
| | | @Schema(description = "å½åæååç kWï¼ä»
çµè¡¨") |
| | | private BigDecimal currentPower; |
| | | |
| | | @Schema(description = "åçå æ° 0-1ï¼ä»
çµè¡¨") |
| | | private BigDecimal powerFactor; |
| | | |
| | | @Schema(description = "ç¶æ OK/STALE/EMPTY/NO_DEVICE") |
| | | private String status; |
| | | |
| | | private String statusText; |
| | | } |
| | | |
| | | @Data |
| | | @Schema(description = "ææ¥è¶å¿") |
| | | public static class TrendPoint implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | private String day; |
| | | |
| | | private BigDecimal water; |
| | | |
| | | private BigDecimal electric; |
| | | |
| | | private BigDecimal gas; |
| | | } |
| | | |
| | | @Data |
| | | @Schema(description = "çµè¡¨å®æ¶æ°æ®") |
| | | public static class Electric implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | @Schema(description = "彿¥æ°æ®èµ·å§ï¼å¦ 00:00") |
| | | private String rangeStart; |
| | | |
| | | @Schema(description = "彿¥æ°æ®æªæ¢ï¼å¦ 17:58") |
| | | private String rangeEnd; |
| | | |
| | | @Schema(description = "仿¥ç´¯è®¡ç¨çµé kWh") |
| | | private BigDecimal todayTotal; |
| | | |
| | | @Schema(description = "æ¨æ¥åæç´¯è®¡ç¨çµé kWh") |
| | | private BigDecimal yesterdaySamePeriodTotal; |
| | | |
| | | @Schema(description = "å½åæååç kW") |
| | | private BigDecimal currentPower; |
| | | |
| | | @Schema(description = "å½ååçå æ°") |
| | | private BigDecimal powerFactor; |
| | | |
| | | @Schema(description = "仿¥ 15 åéæ²çº¿") |
| | | private List<CurvePoint> series = new ArrayList<>(); |
| | | } |
| | | |
| | | @Data |
| | | @Schema(description = "çµè¡¨ 15 åéç¹") |
| | | public static class CurvePoint implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | @Schema(description = "æ¶é´çç»ææ¶é´ HH:mm") |
| | | private String time; |
| | | |
| | | @Schema(description = "æ¶é´çæåçµé kWh") |
| | | private BigDecimal active; |
| | | |
| | | @Schema(description = "æç®æååç kW") |
| | | private BigDecimal power; |
| | | } |
| | | |
| | | @Data |
| | | @Schema(description = "è¿è¡æç¤º") |
| | | public static class Alert implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | @Schema(description = "info/warning") |
| | | private String level; |
| | | |
| | | private String text; |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serializable; |
| | | import java.math.BigDecimal; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * è½èç»è®¡åææ¥è¡¨ï¼ææ¥/æä¸æä»è´¨/设å¤ä¸¤ä¸ªç»´åº¦æ±æ»æ°´ãçµãè¸æ±½ç¨éã |
| | | */ |
| | | @Data |
| | | @Schema(description = "è½èç»è®¡æ¥è¡¨") |
| | | public class EnergyReportVO implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | private String generatedAt; |
| | | |
| | | @Schema(description = "æ¯å¦æ¼ç¤ºæ°æ®æ¨¡å¼") |
| | | private Boolean mockMode; |
| | | |
| | | private String start; |
| | | |
| | | private String end; |
| | | |
| | | @Schema(description = "DAY / MONTH") |
| | | private String granularity; |
| | | |
| | | @Schema(description = "MEDIUM / DEVICE") |
| | | private String dimension; |
| | | |
| | | @Schema(description = "ALL / WATER / ELECTRIC / GAS") |
| | | private String meterType; |
| | | |
| | | @Schema(description = "ç»è®¡å¨æå表") |
| | | private List<String> periods = new ArrayList<>(); |
| | | |
| | | @Schema(description = "æä»è´¨æ±æ»çå¨ææ°æ®") |
| | | private List<PeriodRow> rows = new ArrayList<>(); |
| | | |
| | | @Schema(description = "æè®¾å¤æ±æ»çæ°æ®") |
| | | private List<DeviceRow> devices = new ArrayList<>(); |
| | | |
| | | @Schema(description = "åä»è´¨å计") |
| | | private List<MediumTotal> totals = new ArrayList<>(); |
| | | |
| | | @Schema(description = "ææ°æ®ç卿æ°") |
| | | private Integer coveredPeriods = 0; |
| | | |
| | | @Schema(description = "ç»è®¡å¨ææ»æ°") |
| | | private Integer totalPeriods = 0; |
| | | |
| | | @Schema(description = "ç»è®¡å£å¾è¯´æ") |
| | | private String note; |
| | | |
| | | @Data |
| | | @Schema(description = "å个ç»è®¡å¨æçä¸ç±»ä»è´¨ç¨é") |
| | | public static class PeriodRow implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | private String period; |
| | | |
| | | private BigDecimal water; |
| | | |
| | | private BigDecimal electric; |
| | | |
| | | private BigDecimal gas; |
| | | } |
| | | |
| | | @Data |
| | | @Schema(description = "åå°è®¾å¤æé´ç¨é") |
| | | public static class DeviceRow implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | private Long meterId; |
| | | |
| | | private String meterName; |
| | | |
| | | private String meterAddress; |
| | | |
| | | private String meterType; |
| | | |
| | | @Schema(description = "ä»è´¨åç§°ï¼æ°´è¡¨ / çµè¡¨ / è¸æ±½è¡¨") |
| | | private String meterTypeName; |
| | | |
| | | private String sourceTypeName; |
| | | |
| | | private String unit; |
| | | |
| | | @Schema(description = "æé´ç¨é") |
| | | private BigDecimal total; |
| | | |
| | | @Schema(description = "å æ¬ä»è´¨æ¯ä¾ 0-100") |
| | | private BigDecimal share; |
| | | } |
| | | |
| | | @Data |
| | | @Schema(description = "åç±»ä»è´¨å计") |
| | | public static class MediumTotal implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | private String meterType; |
| | | |
| | | private String meterName; |
| | | |
| | | private String unit; |
| | | |
| | | private BigDecimal total; |
| | | |
| | | private Integer deviceCount = 0; |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serializable; |
| | | |
| | | /** |
| | | * æ¡£æ¡éªè¯ç»æã |
| | | */ |
| | | @Data |
| | | @Schema(description = "ç¬¬ä¸æ¹æ¡£æ¡éªè¯ç»æ") |
| | | public class MeterArchiveVO implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | private String meterType; |
| | | |
| | | private String meterAddress; |
| | | |
| | | private String providerMeterId; |
| | | |
| | | private String providerName; |
| | | |
| | | private Long areaId; |
| | | |
| | | private String areaName; |
| | | |
| | | private Integer onlineStatus; |
| | | |
| | | private String parentProviderId; |
| | | |
| | | @Schema(description = "æ¯å¦å¯ä»¥ç»å®") |
| | | private Boolean bindable; |
| | | |
| | | @Schema(description = "å·²åå¨çæ¬å°è®¾å¤IDï¼éå¤ç»å®æ¶è¿åï¼") |
| | | private Long existingDeviceId; |
| | | |
| | | @Schema(description = "å·²åå¨è®¾å¤æ¯å¦å¯ç¨") |
| | | private Boolean existingEnabled; |
| | | |
| | | @Schema(description = "æç¤ºä¿¡æ¯") |
| | | private String message; |
| | | |
| | | @Schema(description = "æ¯å¦å¤äºæ¼ç¤ºæ°æ®æ¨¡å¼") |
| | | private Boolean mockMode; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.energymeter.vo; |
| | | |
| | | import com.fasterxml.jackson.annotation.JsonFormat; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serializable; |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * æå·¥å½è¡¨ç»æã |
| | | */ |
| | | @Data |
| | | @Schema(description = "æå·¥å½è¡¨ç»æ") |
| | | public class MeterReadingResultVO implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | @Schema(description = "表ç è®°å½ID") |
| | | private Long id; |
| | | |
| | | @Schema(description = "设å¤ID") |
| | | private Long meterId; |
| | | |
| | | @Schema(description = "æè¡¨æ¶é´") |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private LocalDateTime measureTime; |
| | | |
| | | @Schema(description = "æ¬æ¬¡è¡¨ç ") |
| | | private BigDecimal readingValue; |
| | | |
| | | @Schema(description = "ä¸æè¡¨ç ") |
| | | private BigDecimal previousReading; |
| | | |
| | | @Schema(description = "æ¬æç¨é") |
| | | private BigDecimal usage; |
| | | |
| | | @Schema(description = "åä½") |
| | | private String unit; |
| | | } |
| | |
| | | compress: true # æ¯å¦å缩 |
| | | needCompressSize: 10MB # å缩éå¼ |
| | | compressQuality: 0.5 # å缩质é(0.0-1.0) |
| | | |
| | | # ==================== æ°´çµè¡¨æ¥å
¥ ==================== |
| | | energy-meter: |
| | | provider: |
| | | # åºç¡å°å |
| | | base-url: http://nhapi.yunjichaobiao.com/WebApi |
| | | # ææç |
| | | api-key: 62F19BF685484594B57FE97FC7444AF3 |
| | | mock-enabled: false |
| | | # 两次请æ±çæå°é´éï¼æ¯«ç§ï¼ |
| | | min-interval-ms: 500 |
| | | connect-timeout-seconds: 5 |
| | | read-timeout-seconds: 30 |
| | | # æ¯å¤© 08:00 忥æ¶å§ç»åæ¥æè¿ 3 天 |
| | | lookback-days: 3 |
| | | # åå²è¡¥éå个åçæå¤§èªç¶æ¥ï¼ç¨éæ¥å£éå¶ 31 å¤©è·¨åº¦ï¼ |
| | | max-shard-days: 30 |
| | | # ç¤ºå¼æ¥å£å个åçæå¤§èªç¶æ¥ï¼éç¤¾äº GetWaterRawData éå¶ 15 å¤©è·¨åº¦ï¼ |
| | | max-reading-shard-days: 15 |
| | | # ç¬¬ä¸æ¹æå¤§å¹¶åæ°ä¸å¤±è´¥éè¯æ¬¡æ°ï¼1ã5ã15 åéï¼ |
| | | concurrency: 2 |
| | | max-attempts: 3 |
| | | # RUNNING ä»»å¡è¶
æ¶éå¼ï¼åéï¼ |
| | | running-timeout-minutes: 30 |
| | | # 水表åå§ç¤ºå¼ä»»å¡å¼å
³ï¼å页è½å确认åå¯å
³éï¼ |
| | | raw-reading-enabled: true |
| | | # æ¯å¦æ³¨å 08:00 èªå¨åæ¥ä¸ 10 å鿢å¤ä½ä¸ |
| | | scheduler-enabled: true |
| | | sync-cron: "0 0 8 * * ?" |
| | | recovery-cron: "0 0/10 * * * ?" |
| | |
| | | compress: true # æ¯å¦å缩 |
| | | needCompressSize: 10MB # å缩éå¼ |
| | | compressQuality: 0.5 # å缩质é(0.0-1.0) |
| | | |
| | | # ==================== æ°´çµè¡¨æ¥å
¥ ==================== |
| | | energy-meter: |
| | | provider: |
| | | # åºç¡å°å |
| | | base-url: http://nhapi.yunjichaobiao.com/WebApi |
| | | # ææç |
| | | api-key: 62F19BF685484594B57FE97FC7444AF3 |
| | | mock-enabled: false |
| | | # 两次请æ±çæå°é´éï¼æ¯«ç§ï¼ |
| | | min-interval-ms: 500 |
| | | connect-timeout-seconds: 5 |
| | | read-timeout-seconds: 30 |
| | | # æ¯å¤© 08:00 忥æ¶å§ç»åæ¥æè¿ 3 天 |
| | | lookback-days: 3 |
| | | # åå²è¡¥éå个åçæå¤§èªç¶æ¥ï¼ç¨éæ¥å£éå¶ 31 å¤©è·¨åº¦ï¼ |
| | | max-shard-days: 30 |
| | | # ç¤ºå¼æ¥å£å个åçæå¤§èªç¶æ¥ï¼éç¤¾äº GetWaterRawData éå¶ 15 å¤©è·¨åº¦ï¼ |
| | | max-reading-shard-days: 15 |
| | | # ç¬¬ä¸æ¹æå¤§å¹¶åæ°ä¸å¤±è´¥éè¯æ¬¡æ°ï¼1ã5ã15 åéï¼ |
| | | concurrency: 2 |
| | | max-attempts: 3 |
| | | # RUNNING ä»»å¡è¶
æ¶éå¼ï¼åéï¼ |
| | | running-timeout-minutes: 30 |
| | | # 水表åå§ç¤ºå¼ä»»å¡å¼å
³ï¼å页è½å确认åå¯å
³éï¼ |
| | | raw-reading-enabled: true |
| | | # æ¯å¦æ³¨å 08:00 èªå¨åæ¥ä¸ 10 å鿢å¤ä½ä¸ |
| | | scheduler-enabled: true |
| | | sync-cron: "0 0 8 * * ?" |
| | | recovery-cron: "0 0/10 * * * ?" |
| | |
| | | model-name: "deepseek-r1:1.5b" |
| | | log-requests: true |
| | | log-responses: true |
| | | knowledge: |
| | | one: D:\æ°ç大ç½ç´ ä¼ä¸äº§åä½ç³»è¯´æææ¡£.md |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <?xml version="1.0" encoding="UTF-8" ?> |
| | | <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
| | | <mapper namespace="com.ruoyi.energymeter.mapper.EnergyMeterMeasurementMapper"> |
| | | |
| | | <sql id="meterIdIn"> |
| | | <if test="meterIds != null and meterIds.size() > 0"> |
| | | AND meter_id IN |
| | | <foreach collection="meterIds" item="id" open="(" separator="," close=")"> |
| | | #{id} |
| | | </foreach> |
| | | </if> |
| | | <if test="meterIds == null or meterIds.size() == 0"> |
| | | AND 1 = 0 |
| | | </if> |
| | | </sql> |
| | | |
| | | <select id="sumDailyUsage" resultType="com.ruoyi.energymeter.dto.DailyUsageRow"> |
| | | SELECT DATE_FORMAT(measure_time, '%Y-%m-%d') AS day, |
| | | COALESCE(SUM(metric_value), 0) AS total |
| | | FROM energy_meter_measurement |
| | | WHERE metric_code = #{metricCode} |
| | | AND granularity = 'D' |
| | | AND measure_time >= #{start} |
| | | AND measure_time < #{end} |
| | | <include refid="meterIdIn"/> |
| | | GROUP BY DATE_FORMAT(measure_time, '%Y-%m-%d') |
| | | ORDER BY day |
| | | </select> |
| | | |
| | | <select id="sumUsageByMeter" resultType="com.ruoyi.energymeter.dto.MeterUsageRow"> |
| | | SELECT meter_id AS meter_id, |
| | | COALESCE(SUM(metric_value), 0) AS total |
| | | FROM energy_meter_measurement |
| | | WHERE metric_code = #{metricCode} |
| | | AND granularity = 'D' |
| | | AND measure_time >= #{start} |
| | | AND measure_time < #{end} |
| | | <include refid="meterIdIn"/> |
| | | GROUP BY meter_id |
| | | </select> |
| | | |
| | | <select id="sumMonthlyUsage" resultType="com.ruoyi.energymeter.dto.MonthlyUsageRow"> |
| | | SELECT DATE_FORMAT(measure_time, '%Y-%m') AS month, |
| | | COALESCE(SUM(metric_value), 0) AS total |
| | | FROM energy_meter_measurement |
| | | WHERE metric_code = #{metricCode} |
| | | AND granularity = 'D' |
| | | AND measure_time >= #{start} |
| | | AND measure_time < #{end} |
| | | <include refid="meterIdIn"/> |
| | | GROUP BY DATE_FORMAT(measure_time, '%Y-%m') |
| | | ORDER BY month |
| | | </select> |
| | | |
| | | <select id="selectExistingPoints" resultType="com.ruoyi.energymeter.pojo.EnergyMeterMeasurement"> |
| | | SELECT id, tenant_id, meter_id, metric_code, granularity, measure_time, metric_value, unit, |
| | | source_api, source_record_time, collected_at |
| | | FROM energy_meter_measurement |
| | | WHERE meter_id = #{meterId} |
| | | AND metric_code = #{metricCode} |
| | | AND granularity = #{granularity} |
| | | AND measure_time >= #{start} |
| | | AND measure_time < #{end} |
| | | </select> |
| | | |
| | | <insert id="upsertBatch"> |
| | | INSERT INTO energy_meter_measurement |
| | | (tenant_id, meter_id, metric_code, granularity, measure_time, metric_value, unit, |
| | | source_api, source_record_time, collected_at) |
| | | VALUES |
| | | <foreach collection="list" item="it" separator=","> |
| | | (#{it.tenantId}, #{it.meterId}, #{it.metricCode}, #{it.granularity}, #{it.measureTime}, |
| | | #{it.metricValue}, #{it.unit}, #{it.sourceApi}, #{it.sourceRecordTime}, #{it.collectedAt}) |
| | | </foreach> |
| | | ON DUPLICATE KEY UPDATE |
| | | metric_value = VALUES(metric_value), |
| | | unit = VALUES(unit), |
| | | source_api = VALUES(source_api), |
| | | source_record_time = VALUES(source_record_time), |
| | | collected_at = VALUES(collected_at) |
| | | </insert> |
| | | |
| | | <select id="selectDataRange" resultType="com.ruoyi.energymeter.dto.DataRangeRow"> |
| | | SELECT MIN(measure_time) AS min_time, MAX(measure_time) AS max_time |
| | | FROM energy_meter_measurement |
| | | WHERE metric_code = #{metricCode} |
| | | AND granularity = 'D' |
| | | <include refid="meterIdIn"/> |
| | | </select> |
| | | |
| | | <select id="countMetersWithUsage" resultType="java.lang.Integer"> |
| | | SELECT COUNT(DISTINCT meter_id) |
| | | FROM energy_meter_measurement |
| | | WHERE metric_code = #{metricCode} |
| | | AND granularity = 'D' |
| | | AND measure_time >= #{start} |
| | | AND measure_time < #{end} |
| | | <include refid="meterIdIn"/> |
| | | </select> |
| | | |
| | | <select id="sumTotal" resultType="java.math.BigDecimal"> |
| | | SELECT COALESCE(SUM(metric_value), 0) |
| | | FROM energy_meter_measurement |
| | | WHERE metric_code = #{metricCode} |
| | | AND granularity = 'D' |
| | | AND measure_time >= #{start} |
| | | AND measure_time < #{end} |
| | | <include refid="meterIdIn"/> |
| | | </select> |
| | | |
| | | </mapper> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <?xml version="1.0" encoding="UTF-8" ?> |
| | | <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
| | | <mapper namespace="com.ruoyi.energymeter.mapper.EnergyMeterSyncCheckpointMapper"> |
| | | |
| | | <insert id="upsert"> |
| | | INSERT INTO energy_meter_sync_checkpoint |
| | | (tenant_id, meter_id, source_api, granularity, last_complete_date, last_success_at, last_run_id, create_time, update_time) |
| | | VALUES |
| | | (#{cp.tenantId}, #{cp.meterId}, #{cp.sourceApi}, #{cp.granularity}, #{cp.lastCompleteDate}, |
| | | #{cp.lastSuccessAt}, #{cp.lastRunId}, NOW(3), NOW(3)) |
| | | ON DUPLICATE KEY UPDATE |
| | | last_complete_date = GREATEST(COALESCE(last_complete_date, VALUES(last_complete_date)), VALUES(last_complete_date)), |
| | | last_success_at = VALUES(last_success_at), |
| | | last_run_id = VALUES(last_run_id), |
| | | update_time = NOW(3) |
| | | </insert> |
| | | |
| | | </mapper> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <?xml version="1.0" encoding="UTF-8" ?> |
| | | <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
| | | <mapper namespace="com.ruoyi.energymeter.mapper.EnergyMeterSyncRunMapper"> |
| | | |
| | | <update id="refreshTotals"> |
| | | UPDATE energy_meter_sync_run r |
| | | JOIN ( |
| | | SELECT run_id, |
| | | COUNT(*) AS total_cnt, |
| | | COALESCE(SUM(status = 'SUCCESS'), 0) AS success_cnt, |
| | | COALESCE(SUM(status = 'EMPTY'), 0) AS empty_cnt, |
| | | COALESCE(SUM(status = 'FAILED'), 0) AS failed_cnt |
| | | FROM energy_meter_sync_task |
| | | WHERE run_id = #{runId} |
| | | GROUP BY run_id |
| | | ) t ON t.run_id = r.id |
| | | SET r.total_tasks = t.total_cnt, |
| | | r.success_tasks = t.success_cnt, |
| | | r.empty_tasks = t.empty_cnt, |
| | | r.failed_tasks = t.failed_cnt |
| | | WHERE r.id = #{runId} |
| | | </update> |
| | | |
| | | </mapper> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <?xml version="1.0" encoding="UTF-8" ?> |
| | | <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
| | | <mapper namespace="com.ruoyi.energymeter.mapper.EnergyMeterSyncTaskMapper"> |
| | | |
| | | <insert id="insertIgnore"> |
| | | INSERT IGNORE INTO energy_meter_sync_task |
| | | (run_id, tenant_id, meter_id, source_api, granularity, range_start, range_end, status, |
| | | attempt_count, fetched_count, inserted_count, updated_count, create_time, update_time) |
| | | VALUES |
| | | (#{task.runId}, #{task.tenantId}, #{task.meterId}, #{task.sourceApi}, #{task.granularity}, |
| | | #{task.rangeStart}, #{task.rangeEnd}, #{task.status}, 0, 0, 0, 0, NOW(3), NOW(3)) |
| | | </insert> |
| | | |
| | | <update id="claim"> |
| | | UPDATE energy_meter_sync_task |
| | | SET status = 'RUNNING', |
| | | attempt_count = attempt_count + 1, |
| | | started_at = #{now}, |
| | | finished_at = NULL, |
| | | next_retry_at = NULL, |
| | | error_code = NULL, |
| | | error_message = NULL |
| | | WHERE id = #{id} |
| | | AND status IN ('PENDING', 'RETRY') |
| | | </update> |
| | | |
| | | <select id="selectDueRetry" resultType="com.ruoyi.energymeter.pojo.EnergyMeterSyncTask"> |
| | | SELECT * FROM energy_meter_sync_task |
| | | WHERE status = 'RETRY' |
| | | AND next_retry_at IS NOT NULL |
| | | AND next_retry_at <= #{now} |
| | | ORDER BY next_retry_at |
| | | LIMIT #{limit} |
| | | </select> |
| | | |
| | | <select id="selectStaleRunning" resultType="com.ruoyi.energymeter.pojo.EnergyMeterSyncTask"> |
| | | SELECT * FROM energy_meter_sync_task |
| | | WHERE status = 'RUNNING' |
| | | AND started_at IS NOT NULL |
| | | AND started_at < #{deadline} |
| | | ORDER BY started_at |
| | | LIMIT #{limit} |
| | | </select> |
| | | |
| | | <update id="resetToRetry"> |
| | | UPDATE energy_meter_sync_task |
| | | SET status = 'RETRY', |
| | | next_retry_at = #{nextRetryAt}, |
| | | error_code = 'UPSTREAM_TIMEOUT', |
| | | error_message = #{reason}, |
| | | update_time = #{now} |
| | | WHERE id = #{id} |
| | | AND status = 'RUNNING' |
| | | </update> |
| | | |
| | | <select id="selectByRunId" resultType="com.ruoyi.energymeter.pojo.EnergyMeterSyncTask"> |
| | | SELECT t.*, d.display_name AS meter_name, d.meter_type, d.meter_address |
| | | FROM energy_meter_sync_task t |
| | | LEFT JOIN energy_meter_device d ON d.id = t.meter_id |
| | | WHERE t.run_id = #{runId} |
| | | ORDER BY t.id |
| | | </select> |
| | | |
| | | <select id="selectLatestByMeterIds" resultType="com.ruoyi.energymeter.pojo.EnergyMeterSyncTask"> |
| | | SELECT * FROM ( |
| | | SELECT t.*, ROW_NUMBER() OVER (PARTITION BY t.meter_id ORDER BY t.id DESC) AS rn |
| | | FROM energy_meter_sync_task t |
| | | WHERE t.meter_id IN |
| | | <foreach collection="meterIds" item="id" open="(" separator="," close=")"> |
| | | #{id} |
| | | </foreach> |
| | | ) x |
| | | WHERE x.rn = 1 |
| | | </select> |
| | | |
| | | <select id="countByRunId" resultType="com.ruoyi.energymeter.dto.TaskStatusCount"> |
| | | SELECT COUNT(*) AS `total`, |
| | | COALESCE(SUM(status = 'SUCCESS'), 0) AS `success`, |
| | | COALESCE(SUM(status = 'EMPTY'), 0) AS `empty`, |
| | | COALESCE(SUM(status = 'FAILED'), 0) AS `failed`, |
| | | COALESCE(SUM(status = 'RETRY'), 0) AS `retry`, |
| | | COALESCE(SUM(status = 'PENDING'), 0) AS `pending`, |
| | | COALESCE(SUM(status = 'RUNNING'), 0) AS `running` |
| | | FROM energy_meter_sync_task |
| | | WHERE run_id = #{runId} |
| | | </select> |
| | | |
| | | </mapper> |