Commit 2e65db9b by gujiulin

init

parents
Device, 5GV
Type, PPV peak
MAC, 2b0652
Cal Date, 2022-05-15T00:00:00.000+01:00
Man Date, 2022-05-15T00:00:00.000+01:00
H/W, 5.0
Main F/W, 5.3.15
Orient. (g), -0.033,0.999,0.011
Bat,0.00
PPA units,G
PPV units,MM/S
PPD units,MM
Filter,ISEE
Time,PPV X,Sec X,Hz X,PPV Y,Sec Y,Hz Y,PPV Z,Sec Z,Hz Z,PVS,Sec PVS,PPA X,PPA Y,PPA Z,PPD X,PPD Y,PPD Z
2025-05-26T08:00:00.000+08:00, 0.685,2025-05-26T07:59:53.379+08:00, 2.590, 0.782,2025-05-26T07:59:52.989+08:00, 3.378, 1.332,2025-05-26T07:59:06.824+08:00,16.666, 1.411,2025-05-26T07:59:06.824+08:00, 0.010, 0.014, 0.019, 0.049, 0.039, 0.042
2025-05-26T08:01:00.000+08:00, 0.751,2025-05-26T08:00:57.377+08:00, 4.587, 0.842,2025-05-26T08:00:59.040+08:00, 3.759, 1.548,2025-05-26T08:00:57.319+08:00,11.363, 1.728,2025-05-26T08:00:57.415+08:00, 0.010, 0.012, 0.014, 0.048, 0.059, 0.030
2025-05-26T08:02:00.000+08:00, 1.011,2025-05-26T08:01:02.593+08:00, 8.474, 1.129,2025-05-26T08:01:02.573+08:00, 4.347, 2.092,2025-05-26T08:01:02.475+08:00,10.869, 2.378,2025-05-26T08:01:02.475+08:00, 0.013, 0.012, 0.017, 0.063, 0.056, 0.066
2025-05-26T08:03:00.000+08:00, 0.937,2025-05-26T08:02:57.589+08:00, 2.551, 0.824,2025-05-26T08:02:13.778+08:00, 3.676, 2.600,2025-05-26T08:02:31.502+08:00, 9.259, 2.728,2025-05-26T08:02:31.502+08:00, 0.011, 0.021, 0.024, 0.074, 0.040, 0.040
2025-05-26T08:04:00.000+08:00, 1.156,2025-05-26T08:03:25.006+08:00, 2.762, 0.522,2025-05-26T08:03:28.405+08:00, 2.380, 0.906,2025-05-26T08:03:39.386+08:00,17.241, 1.172,2025-05-26T08:03:25.006+08:00, 0.012, 0.012, 0.016, 0.085, 0.035, 0.029
2025-05-26T08:05:00.000+08:00, 0.492,2025-05-26T08:04:28.139+08:00, 8.620, 0.639,2025-05-26T08:04:26.399+08:00, 5.952, 1.501,2025-05-26T08:04:29.000+08:00, 7.246, 1.568,2025-05-26T08:04:29.000+08:00, 0.009, 0.006, 0.016, 0.030, 0.029, 0.030
2025-05-26T08:06:00.000+08:00, 0.694,2025-05-26T08:05:08.730+08:00, 5.813, 0.673,2025-05-26T08:05:18.481+08:00, 9.433, 1.682,2025-05-26T08:05:32.569+08:00,14.705, 1.799,2025-05-26T08:05:32.569+08:00, 0.013, 0.015, 0.020, 0.058, 0.034, 0.060
2025-05-26T08:07:00.000+08:00, 0.509,2025-05-26T08:06:18.986+08:00, 6.493, 0.631,2025-05-26T08:06:39.264+08:00, 7.812, 1.197,2025-05-26T08:06:15.978+08:00,10.204, 1.268,2025-05-26T08:06:15.978+08:00, 0.012, 0.011, 0.017, 0.041, 0.025, 0.037
2025-05-26T08:08:00.000+08:00, 0.761,2025-05-26T08:07:12.297+08:00, 1.960, 0.551,2025-05-26T08:07:11.654+08:00, 9.433, 1.571,2025-05-26T08:07:12.298+08:00,11.627, 1.756,2025-05-26T08:07:12.298+08:00, 0.012, 0.010, 0.020, 0.045, 0.031, 0.041
2025-05-26T08:09:00.000+08:00, 0.928,2025-05-26T08:08:44.554+08:00, 2.538, 1.198,2025-05-26T08:08:44.498+08:00, 2.976, 1.850,2025-05-26T08:08:36.228+08:00,12.500, 1.978,2025-05-26T08:08:36.228+08:00, 0.012, 0.011, 0.020, 0.073, 0.055, 0.066
2025-05-26T08:10:00.000+08:00, 0.551,2025-05-26T08:09:51.266+08:00, 5.882, 0.643,2025-05-26T08:09:51.833+08:00, 3.937, 1.805,2025-05-26T08:09:02.706+08:00, 4.065, 1.868,2025-05-26T08:09:02.706+08:00, 0.010, 0.009, 0.017, 0.033, 0.032, 0.033
2025-05-26T08:11:00.000+08:00, 0.779,2025-05-26T08:10:43.664+08:00, 5.376, 0.532,2025-05-26T08:10:44.250+08:00, 7.462, 1.145,2025-05-26T08:10:47.901+08:00,10.869, 1.290,2025-05-26T08:10:44.954+08:00, 0.011, 0.016, 0.018, 0.052, 0.034, 0.037
2025-05-26T08:12:00.000+08:00, 1.047,2025-05-26T08:11:21.541+08:00, 2.659, 0.679,2025-05-26T08:11:21.328+08:00, 3.184, 1.179,2025-05-26T08:11:22.383+08:00, 9.803, 1.328,2025-05-26T08:11:21.330+08:00, 0.009, 0.015, 0.013, 0.073, 0.039, 0.034
2025-05-26T08:13:00.000+08:00, 0.420,2025-05-26T08:12:04.250+08:00, 3.703, 0.821,2025-05-26T08:12:57.191+08:00, 4.672, 1.241,2025-05-26T08:12:57.190+08:00, 5.102, 1.457,2025-05-26T08:12:57.190+08:00, 0.013, 0.014, 0.015, 0.027, 0.040, 0.041
2025-05-26T08:14:00.000+08:00, 0.704,2025-05-26T08:13:34.993+08:00, 8.196, 0.807,2025-05-26T08:13:34.192+08:00, 8.333, 1.692,2025-05-26T08:13:34.192+08:00,27.777, 1.902,2025-05-26T08:13:34.192+08:00, 0.012, 0.011, 0.016, 0.046, 0.043, 0.053
2025-05-26T08:15:00.000+08:00, 0.597,2025-05-26T08:14:48.452+08:00, 2.941, 0.689,2025-05-26T08:14:29.386+08:00, 4.132, 1.423,2025-05-26T08:14:28.566+08:00, 9.433, 1.589,2025-05-26T08:14:28.566+08:00, 0.010, 0.011, 0.014, 0.051, 0.035, 0.056
2025-05-26T08:16:00.000+08:00, 0.913,2025-05-26T08:15:26.492+08:00, 2.762, 0.945,2025-05-26T08:15:26.550+08:00, 5.882, 1.463,2025-05-26T08:15:25.692+08:00,10.869, 1.803,2025-05-26T08:15:25.889+08:00, 0.020, 0.015, 0.021, 0.061, 0.054, 0.054
2025-05-26T08:17:00.000+08:00, 0.942,2025-05-26T08:16:29.595+08:00, 3.333, 0.840,2025-05-26T08:16:34.310+08:00, 3.968, 1.178,2025-05-26T08:16:54.059+08:00, 3.937, 1.265,2025-05-26T08:16:54.059+08:00, 0.008, 0.007, 0.013, 0.070, 0.073, 0.038
2025-05-26T08:18:00.000+08:00, 0.593,2025-05-26T08:17:09.492+08:00, 8.771, 0.607,2025-05-26T08:17:30.244+08:00, 9.259, 1.321,2025-05-26T08:17:17.525+08:00,12.500, 1.388,2025-05-26T08:17:17.525+08:00, 0.009, 0.008, 0.016, 0.045, 0.045, 0.039
2025-05-26T08:19:00.000+08:00, 0.813,2025-05-26T08:18:23.233+08:00, 3.164, 0.618,2025-05-26T08:18:22.080+08:00, 3.086, 0.989,2025-05-26T08:18:21.456+08:00, 5.747, 1.043,2025-05-26T08:18:24.914+08:00, 0.016, 0.013, 0.020, 0.061, 0.046, 0.051
2025-05-26T08:20:00.000+08:00, 0.543,2025-05-26T08:19:20.849+08:00, 2.645, 0.489,2025-05-26T08:19:10.823+08:00, 4.032, 0.664,2025-05-26T08:19:10.725+08:00,20.000, 0.811,2025-05-26T08:19:10.725+08:00, 0.009, 0.008, 0.011, 0.053, 0.036, 0.024
2025-05-26T08:21:00.000+08:00, 0.967,2025-05-26T08:20:41.905+08:00, 3.086, 0.916,2025-05-26T08:20:56.738+08:00, 3.597, 1.888,2025-05-26T08:20:56.738+08:00, 3.649, 2.120,2025-05-26T08:20:56.738+08:00, 0.017, 0.013, 0.018, 0.059, 0.063, 0.053
2025-05-26T08:22:00.000+08:00, 0.736,2025-05-26T08:21:31.694+08:00, 4.950, 0.759,2025-05-26T08:21:35.443+08:00, 4.273, 1.915,2025-05-26T08:21:35.775+08:00, 5.681, 1.997,2025-05-26T08:21:35.774+08:00, 0.010, 0.014, 0.022, 0.055, 0.041, 0.046
2025-05-26T08:23:00.000+08:00, 0.617,2025-05-26T08:22:46.707+08:00, 5.494, 0.617,2025-05-26T08:22:34.556+08:00, 7.575, 1.313,2025-05-26T08:22:34.363+08:00, 5.681, 1.423,2025-05-26T08:22:34.539+08:00, 0.008, 0.009, 0.011, 0.050, 0.039, 0.053
2025-05-26T08:24:00.000+08:00, 0.689,2025-05-26T08:23:38.375+08:00, 2.873, 0.502,2025-05-26T08:23:16.440+08:00, 4.166, 1.294,2025-05-26T08:23:30.839+08:00, 7.352, 1.387,2025-05-26T08:23:30.839+08:00, 0.012, 0.012, 0.017, 0.044, 0.031, 0.028
2025-05-26T08:25:00.000+08:00, 0.964,2025-05-26T08:24:02.760+08:00, 3.311, 0.601,2025-05-26T08:24:08.698+08:00, 7.352, 1.349,2025-05-26T08:24:59.495+08:00,11.904, 1.467,2025-05-26T08:24:59.495+08:00, 0.008, 0.009, 0.013, 0.104, 0.039, 0.041
2025-05-26T08:26:00.000+08:00, 0.920,2025-05-26T08:25:53.302+08:00, 3.968, 0.866,2025-05-26T08:25:53.341+08:00, 3.968, 1.230,2025-05-26T08:25:52.948+08:00, 7.246, 1.453,2025-05-26T08:25:53.341+08:00, 0.011, 0.011, 0.016, 0.074, 0.056, 0.039
2025-05-26T08:27:00.000+08:00, 0.759,2025-05-26T08:26:24.224+08:00, 3.067, 0.816,2025-05-26T08:26:24.536+08:00, 4.201, 1.958,2025-05-26T08:26:24.242+08:00, 5.154, 2.139,2025-05-26T08:26:24.243+08:00, 0.013, 0.015, 0.017, 0.040, 0.043, 0.050
2025-05-26T08:28:00.000+08:00, 0.608,2025-05-26T08:27:06.947+08:00,12.195, 0.935,2025-05-26T08:27:27.739+08:00, 4.587, 1.709,2025-05-26T08:27:23.070+08:00,11.627, 1.740,2025-05-26T08:27:23.070+08:00, 0.010, 0.015, 0.017, 0.051, 0.037, 0.053
2025-05-26T08:29:00.000+08:00, 0.796,2025-05-26T08:28:09.080+08:00, 2.564, 0.847,2025-05-26T08:28:46.100+08:00, 5.747, 1.227,2025-05-26T08:28:02.396+08:00,14.285, 1.405,2025-05-26T08:28:45.847+08:00, 0.010, 0.015, 0.016, 0.055, 0.054, 0.039
2025-05-26T08:30:00.000+08:00, 0.876,2025-05-26T08:29:07.297+08:00, 3.355, 0.796,2025-05-26T08:29:09.914+08:00, 4.854, 1.246,2025-05-26T08:29:08.879+08:00, 8.196, 1.272,2025-05-26T08:29:08.879+08:00, 0.015, 0.011, 0.018, 0.048, 0.067, 0.047
2025-05-26T08:31:00.000+08:00, 0.532,2025-05-26T08:30:33.305+08:00, 8.620, 0.513,2025-05-26T08:30:33.479+08:00, 8.771, 1.465,2025-05-26T08:30:51.732+08:00,17.241, 1.503,2025-05-26T08:30:51.732+08:00, 0.014, 0.011, 0.017, 0.038, 0.033, 0.042
2025-05-26T08:32:00.000+08:00, 1.120,2025-05-26T08:31:44.185+08:00, 3.472, 1.167,2025-05-26T08:31:48.462+08:00, 3.906, 1.801,2025-05-26T08:31:48.796+08:00,13.157, 1.904,2025-05-26T08:31:48.796+08:00, 0.011, 0.011, 0.022, 0.094, 0.070, 0.064
2025-05-26T08:33:00.000+08:00, 0.606,2025-05-26T08:32:25.765+08:00, 4.032, 0.805,2025-05-26T08:32:35.495+08:00, 3.816, 1.291,2025-05-26T08:32:25.180+08:00, 4.273, 1.403,2025-05-26T08:32:25.180+08:00, 0.009, 0.008, 0.016, 0.040, 0.048, 0.045
2025-05-26T08:34:00.000+08:00, 0.544,2025-05-26T08:33:29.243+08:00, 2.232, 0.940,2025-05-26T08:33:20.392+08:00, 3.030, 1.428,2025-05-26T08:33:20.297+08:00, 7.042, 1.686,2025-05-26T08:33:20.297+08:00, 0.019, 0.016, 0.023, 0.038, 0.036, 0.045
2025-05-26T08:35:00.000+08:00, 0.639,2025-05-26T08:34:53.684+08:00, 3.937, 0.743,2025-05-26T08:34:56.439+08:00, 5.050, 1.680,2025-05-26T08:34:07.132+08:00, 5.000, 1.794,2025-05-26T08:34:07.132+08:00, 0.010, 0.012, 0.018, 0.052, 0.037, 0.042
2025-05-26T08:36:00.000+08:00, 0.563,2025-05-26T08:35:51.437+08:00, 2.358, 0.682,2025-05-26T08:35:51.144+08:00, 4.464, 2.024,2025-05-26T08:35:17.032+08:00, 4.201, 2.128,2025-05-26T08:35:17.033+08:00, 0.014, 0.013, 0.025, 0.035, 0.035, 0.064
2025-05-26T08:37:00.000+08:00, 0.901,2025-05-26T08:36:53.027+08:00, 3.937, 0.556,2025-05-26T08:36:55.683+08:00, 4.032, 1.146,2025-05-26T08:36:06.771+08:00, 9.090, 1.296,2025-05-26T08:36:06.771+08:00, 0.012, 0.017, 0.019, 0.080, 0.039, 0.029
2025-05-26T08:38:00.000+08:00, 0.492,2025-05-26T08:37:00.585+08:00, 4.000, 0.641,2025-05-26T08:37:42.021+08:00, 3.333, 1.230,2025-05-26T08:37:35.126+08:00, 8.474, 1.270,2025-05-26T08:37:35.126+08:00, 0.010, 0.007, 0.016, 0.030, 0.026, 0.034
2025-05-26T08:39:00.000+08:00, 0.961,2025-05-26T08:38:34.398+08:00, 2.092, 0.814,2025-05-26T08:38:55.183+08:00, 9.090, 1.882,2025-05-26T08:38:55.166+08:00, 8.928, 2.041,2025-05-26T08:38:55.166+08:00, 0.013, 0.012, 0.020, 0.051, 0.038, 0.056
2025-05-26T08:40:00.000+08:00, 0.896,2025-05-26T08:39:02.781+08:00, 3.448, 0.700,2025-05-26T08:39:02.021+08:00, 3.906, 1.112,2025-05-26T08:39:51.819+08:00, 4.587, 1.216,2025-05-26T08:39:51.819+08:00, 0.012, 0.010, 0.021, 0.084, 0.066, 0.038
2025-05-26T08:41:00.000+08:00, 1.012,2025-05-26T08:40:15.750+08:00, 5.208, 0.931,2025-05-26T08:40:20.261+08:00, 4.587, 1.492,2025-05-26T08:40:19.541+08:00, 8.474, 1.573,2025-05-26T08:40:19.541+08:00, 0.013, 0.014, 0.022, 0.064, 0.059, 0.044
2025-05-26T08:42:00.000+08:00, 0.653,2025-05-26T08:41:22.740+08:00, 3.164, 0.672,2025-05-26T08:41:26.882+08:00, 4.385, 1.226,2025-05-26T08:41:26.882+08:00, 5.154, 1.400,2025-05-26T08:41:26.882+08:00, 0.009, 0.012, 0.015, 0.051, 0.046, 0.040
2025-05-26T08:43:00.000+08:00, 0.909,2025-05-26T08:42:34.578+08:00, 3.703, 0.775,2025-05-26T08:42:31.510+08:00, 3.144, 1.251,2025-05-26T08:42:24.632+08:00, 4.672, 1.499,2025-05-26T08:42:31.510+08:00, 0.014, 0.011, 0.017, 0.075, 0.042, 0.073
2025-05-26T08:44:00.000+08:00, 0.766,2025-05-26T08:43:13.665+08:00, 2.525, 0.808,2025-05-26T08:43:13.978+08:00, 4.347, 1.518,2025-05-26T08:43:25.677+08:00, 5.000, 1.713,2025-05-26T08:43:25.678+08:00, 0.015, 0.012, 0.016, 0.046, 0.035, 0.042
2025-05-26T08:45:00.000+08:00, 0.550,2025-05-26T08:44:32.236+08:00,10.869, 0.769,2025-05-26T08:44:52.827+08:00, 5.102, 1.470,2025-05-26T08:44:47.611+08:00, 7.352, 1.665,2025-05-26T08:44:52.828+08:00, 0.009, 0.011, 0.017, 0.041, 0.045, 0.049
2025-05-26T08:46:00.000+08:00, 0.600,2025-05-26T08:45:23.611+08:00, 2.906, 0.876,2025-05-26T08:45:58.410+08:00, 4.901, 1.605,2025-05-26T08:45:59.759+08:00, 5.494, 1.701,2025-05-26T08:45:59.759+08:00, 0.012, 0.020, 0.019, 0.060, 0.068, 0.066
2025-05-26T08:47:00.000+08:00, 0.973,2025-05-26T08:46:03.256+08:00, 4.237, 0.696,2025-05-26T08:46:16.638+08:00, 3.546, 1.646,2025-05-26T08:46:56.472+08:00, 4.950, 1.893,2025-05-26T08:46:56.435+08:00, 0.011, 0.015, 0.022, 0.094, 0.057, 0.051
2025-05-26T08:48:00.000+08:00, 0.835,2025-05-26T08:47:51.257+08:00, 3.759, 0.987,2025-05-26T08:47:46.566+08:00, 3.472, 1.488,2025-05-26T08:47:46.917+08:00, 8.064, 1.637,2025-05-26T08:47:46.917+08:00, 0.011, 0.012, 0.017, 0.057, 0.042, 0.036
2025-05-26T08:49:00.000+08:00, 0.743,2025-05-26T08:48:14.582+08:00, 3.496, 0.884,2025-05-26T08:48:58.279+08:00, 4.166, 1.750,2025-05-26T08:48:56.735+08:00, 4.629, 1.812,2025-05-26T08:48:56.735+08:00, 0.017, 0.015, 0.024, 0.070, 0.052, 0.070
2025-05-26T08:50:00.000+08:00, 0.771,2025-05-26T08:49:33.499+08:00, 3.906, 0.886,2025-05-26T08:49:38.423+08:00, 3.448, 1.296,2025-05-26T08:49:07.714+08:00, 7.462, 1.384,2025-05-26T08:49:38.404+08:00, 0.011, 0.013, 0.017, 0.047, 0.046, 0.045
2025-05-26T08:51:00.000+08:00, 0.982,2025-05-26T08:50:49.604+08:00, 4.000, 0.800,2025-05-26T08:50:02.726+08:00, 3.703, 1.594,2025-05-26T08:50:30.364+08:00, 5.952, 1.688,2025-05-26T08:50:30.364+08:00, 0.013, 0.013, 0.021, 0.092, 0.058, 0.060
2025-05-26T08:52:00.000+08:00, 0.846,2025-05-26T08:51:32.049+08:00, 5.434, 0.525,2025-05-26T08:51:41.797+08:00, 3.846, 1.478,2025-05-26T08:51:45.041+08:00, 8.771, 1.503,2025-05-26T08:51:45.041+08:00, 0.010, 0.011, 0.018, 0.060, 0.042, 0.030
2025-05-26T08:53:00.000+08:00, 0.666,2025-05-26T08:52:45.260+08:00, 3.086, 0.996,2025-05-26T08:52:54.328+08:00, 3.846, 1.384,2025-05-26T08:52:34.399+08:00, 3.703, 1.688,2025-05-26T08:52:53.742+08:00, 0.011, 0.019, 0.016, 0.037, 0.054, 0.059
2025-05-26T08:54:00.000+08:00, 0.657,2025-05-26T08:53:39.166+08:00, 3.649, 0.671,2025-05-26T08:53:37.719+08:00, 3.875, 1.415,2025-05-26T08:53:38.050+08:00,14.705, 1.449,2025-05-26T08:53:38.050+08:00, 0.010, 0.011, 0.016, 0.054, 0.053, 0.044
2025-05-26T08:55:00.000+08:00, 1.584,2025-05-26T08:54:12.399+08:00,11.904, 0.945,2025-05-26T08:54:43.968+08:00, 3.676, 2.290,2025-05-26T08:54:43.968+08:00,16.666, 2.470,2025-05-26T08:54:43.968+08:00, 0.014, 0.017, 0.019, 0.151, 0.068, 0.071
2025-05-26T08:56:00.000+08:00, 0.801,2025-05-26T08:55:09.990+08:00, 3.846, 0.882,2025-05-26T08:55:09.696+08:00, 5.208, 1.877,2025-05-26T08:55:08.779+08:00, 5.434, 2.071,2025-05-26T08:55:08.779+08:00, 0.013, 0.009, 0.017, 0.081, 0.054, 0.051
2025-05-26T08:57:00.000+08:00, 0.835,2025-05-26T08:56:52.649+08:00, 3.333, 0.792,2025-05-26T08:56:46.300+08:00, 4.273, 1.434,2025-05-26T08:56:24.246+08:00,13.157, 1.474,2025-05-26T08:56:24.246+08:00, 0.011, 0.014, 0.016, 0.093, 0.038, 0.039
2025-05-26T08:58:00.000+08:00, 0.815,2025-05-26T08:57:34.708+08:00, 4.201, 0.834,2025-05-26T08:57:09.158+08:00,12.500, 1.520,2025-05-26T08:57:01.953+08:00,10.638, 1.614,2025-05-26T08:57:01.953+08:00, 0.015, 0.015, 0.018, 0.072, 0.048, 0.048
2025-05-26T08:59:00.000+08:00, 0.559,2025-05-26T08:58:15.950+08:00, 3.289, 0.665,2025-05-26T08:58:40.844+08:00, 2.873, 1.508,2025-05-26T08:58:03.173+08:00,14.285, 1.640,2025-05-26T08:58:03.173+08:00, 0.007, 0.007, 0.013, 0.034, 0.043, 0.031
2025-05-26T09:00:00.000+08:00, 1.042,2025-05-26T08:59:51.989+08:00, 6.944, 1.191,2025-05-26T08:59:52.243+08:00, 3.496, 1.995,2025-05-26T08:59:49.346+08:00, 4.098, 2.111,2025-05-26T08:59:49.346+08:00, 0.011, 0.012, 0.023, 0.089, 0.097, 0.060
2025-05-26T09:01:00.000+08:00, 0.637,2025-05-26T09:00:58.873+08:00, 3.937, 0.666,2025-05-26T09:00:15.006+08:00, 4.065, 1.063,2025-05-26T09:00:15.553+08:00,12.500, 1.142,2025-05-26T09:00:15.007+08:00, 0.011, 0.016, 0.021, 0.034, 0.033, 0.040
2025-05-26T09:02:00.000+08:00, 1.186,2025-05-26T09:01:21.658+08:00, 3.289, 1.041,2025-05-26T09:01:38.498+08:00, 3.937, 2.155,2025-05-26T09:01:13.311+08:00,11.111, 2.163,2025-05-26T09:01:13.311+08:00, 0.011, 0.010, 0.020, 0.088, 0.054, 0.050
2025-05-26T09:03:00.000+08:00, 0.910,2025-05-26T09:02:11.501+08:00, 4.310, 0.716,2025-05-26T09:02:27.150+08:00, 4.672, 1.460,2025-05-26T09:02:54.448+08:00, 7.692, 1.525,2025-05-26T09:02:54.448+08:00, 0.010, 0.014, 0.017, 0.086, 0.050, 0.042
2025-05-26T09:04:00.000+08:00, 0.734,2025-05-26T09:03:59.103+08:00, 2.923, 0.756,2025-05-26T09:03:04.569+08:00, 4.424, 1.537,2025-05-26T09:03:10.018+08:00, 8.928, 1.601,2025-05-26T09:03:08.964+08:00, 0.015, 0.016, 0.017, 0.048, 0.048, 0.038
2025-05-26T09:05:00.000+08:00, 0.738,2025-05-26T09:04:44.489+08:00, 3.676, 0.756,2025-05-26T09:04:01.427+08:00, 3.311, 2.136,2025-05-26T09:04:53.344+08:00, 6.493, 2.245,2025-05-26T09:04:53.344+08:00, 0.014, 0.016, 0.020, 0.063, 0.036, 0.033
2025-05-26T09:06:00.000+08:00, 0.668,2025-05-26T09:05:27.449+08:00, 5.434, 0.717,2025-05-26T09:05:31.845+08:00, 4.273, 1.442,2025-05-26T09:05:13.952+08:00,14.285, 1.519,2025-05-26T09:05:30.985+08:00, 0.009, 0.011, 0.017, 0.046, 0.039, 0.048
2025-05-26T09:07:00.000+08:00, 0.892,2025-05-26T09:06:06.467+08:00, 4.132, 0.593,2025-05-26T09:06:55.777+08:00, 4.424, 1.596,2025-05-26T09:06:54.799+08:00, 7.352, 1.645,2025-05-26T09:06:54.722+08:00, 0.011, 0.010, 0.017, 0.063, 0.041, 0.045
2025-05-26T09:08:00.000+08:00, 1.194,2025-05-26T09:07:19.258+08:00, 5.208, 0.828,2025-05-26T09:07:47.627+08:00, 6.756, 1.379,2025-05-26T09:07:03.206+08:00,13.157, 1.581,2025-05-26T09:07:48.663+08:00, 0.014, 0.011, 0.015, 0.111, 0.063, 0.054
2025-05-26T09:09:00.000+08:00, 1.161,2025-05-26T09:08:32.621+08:00, 3.225, 0.873,2025-05-26T09:08:19.372+08:00, 2.717, 1.916,2025-05-26T09:08:19.372+08:00,13.888, 2.104,2025-05-26T09:08:19.372+08:00, 0.012, 0.015, 0.018, 0.083, 0.047, 0.068
2025-05-26T09:10:00.000+08:00, 0.875,2025-05-26T09:09:16.703+08:00, 4.273, 0.916,2025-05-26T09:09:57.404+08:00, 4.098, 1.734,2025-05-26T09:09:16.703+08:00, 5.494, 1.978,2025-05-26T09:09:16.703+08:00, 0.009, 0.008, 0.018, 0.042, 0.047, 0.045
2025-05-26T09:11:00.000+08:00, 0.730,2025-05-26T09:10:26.962+08:00, 3.246, 0.832,2025-05-26T09:10:19.366+08:00,10.869, 1.441,2025-05-26T09:10:51.662+08:00, 8.620, 1.585,2025-05-26T09:10:51.662+08:00, 0.011, 0.011, 0.018, 0.049, 0.060, 0.046
2025-05-26T09:12:00.000+08:00, 0.687,2025-05-26T09:11:42.214+08:00, 2.538, 0.633,2025-05-26T09:11:44.129+08:00, 2.941, 1.352,2025-05-26T09:11:42.879+08:00,18.518, 1.465,2025-05-26T09:11:42.879+08:00, 0.011, 0.009, 0.017, 0.043, 0.038, 0.028
2025-05-26T09:13:00.000+08:00, 1.270,2025-05-26T09:12:15.025+08:00, 3.289, 1.034,2025-05-26T09:12:08.244+08:00, 4.000, 3.414,2025-05-26T09:12:15.042+08:00,25.000, 3.726,2025-05-26T09:12:15.042+08:00, 0.016, 0.015, 0.029, 0.074, 0.054, 0.077
2025-05-26T09:14:00.000+08:00, 1.049,2025-05-26T09:13:51.650+08:00, 3.048, 0.654,2025-05-26T09:13:51.667+08:00, 5.681, 1.265,2025-05-26T09:13:15.694+08:00,20.000, 1.403,2025-05-26T09:13:22.203+08:00, 0.011, 0.010, 0.019, 0.076, 0.046, 0.036
2025-05-26T09:15:00.000+08:00, 0.757,2025-05-26T09:15:00.373+08:00, 4.310, 0.885,2025-05-26T09:14:41.845+08:00, 3.816, 1.425,2025-05-26T09:14:20.841+08:00,10.416, 1.501,2025-05-26T09:14:20.841+08:00, 0.014, 0.013, 0.016, 0.043, 0.054, 0.065
2025-05-26T09:16:00.000+08:00, 1.072,2025-05-26T09:15:03.070+08:00, 3.875, 0.958,2025-05-26T09:15:27.879+08:00, 4.237, 1.433,2025-05-26T09:15:27.879+08:00, 9.615, 1.723,2025-05-26T09:15:27.879+08:00, 0.010, 0.007, 0.016, 0.050, 0.047, 0.060
2025-05-26T09:17:00.000+08:00, 0.939,2025-05-26T09:16:39.971+08:00, 2.762, 0.915,2025-05-26T09:16:34.033+08:00, 2.857, 1.937,2025-05-26T09:16:34.345+08:00, 4.310, 2.017,2025-05-26T09:16:34.345+08:00, 0.010, 0.010, 0.019, 0.063, 0.044, 0.055
2025-05-26T09:18:00.000+08:00, 0.604,2025-05-26T09:17:19.734+08:00, 2.617, 0.590,2025-05-26T09:17:23.779+08:00, 3.703, 1.294,2025-05-26T09:17:30.579+08:00,13.513, 1.402,2025-05-26T09:17:30.579+08:00, 0.011, 0.010, 0.019, 0.055, 0.034, 0.039
2025-05-26T09:19:00.000+08:00, 0.991,2025-05-26T09:18:00.281+08:00, 7.692, 0.890,2025-05-26T09:18:39.493+08:00, 3.816, 1.806,2025-05-26T09:18:51.198+08:00,10.638, 1.917,2025-05-26T09:18:51.198+08:00, 0.012, 0.015, 0.018, 0.101, 0.060, 0.043
2025-05-26T09:20:00.000+08:00, 1.191,2025-05-26T09:19:12.045+08:00, 3.571, 0.857,2025-05-26T09:19:12.338+08:00, 4.504, 1.624,2025-05-26T09:19:19.940+08:00, 9.433, 1.746,2025-05-26T09:19:19.940+08:00, 0.011, 0.014, 0.017, 0.096, 0.048, 0.053
2025-05-26T09:21:00.000+08:00, 0.624,2025-05-26T09:20:58.793+08:00, 2.688, 0.866,2025-05-26T09:20:16.552+08:00, 3.333, 1.779,2025-05-26T09:20:26.009+08:00, 5.813, 1.909,2025-05-26T09:20:26.009+08:00, 0.011, 0.012, 0.016, 0.048, 0.055, 0.060
2025-05-26T09:22:00.000+08:00, 0.675,2025-05-26T09:21:50.066+08:00, 4.273, 0.871,2025-05-26T09:21:21.660+08:00, 3.787, 1.628,2025-05-26T09:21:27.053+08:00, 9.090, 1.744,2025-05-26T09:21:27.071+08:00, 0.010, 0.013, 0.020, 0.048, 0.056, 0.060
2025-05-26T09:23:00.000+08:00, 2.031,2025-05-26T09:22:29.791+08:00, 4.273, 0.760,2025-05-26T09:22:30.804+08:00, 4.504, 1.415,2025-05-26T09:22:37.273+08:00, 4.065, 2.078,2025-05-26T09:22:29.791+08:00, 0.011, 0.010, 0.020, 0.207, 0.084, 0.052
2025-05-26T09:24:00.000+08:00, 0.915,2025-05-26T09:23:33.458+08:00, 3.333, 0.887,2025-05-26T09:23:35.704+08:00, 3.125, 1.285,2025-05-26T09:23:44.576+08:00, 3.816, 1.464,2025-05-26T09:23:45.025+08:00, 0.011, 0.011, 0.017, 0.086, 0.058, 0.051
2025-05-26T09:25:00.000+08:00, 0.766,2025-05-26T09:24:36.207+08:00, 4.385, 0.990,2025-05-26T09:24:30.208+08:00, 3.378, 1.217,2025-05-26T09:24:30.012+08:00,17.241, 1.543,2025-05-26T09:24:30.091+08:00, 0.009, 0.016, 0.012, 0.053, 0.045, 0.056
2025-05-26T09:26:00.000+08:00, 1.036,2025-05-26T09:25:56.983+08:00, 2.941, 0.623,2025-05-26T09:25:59.367+08:00, 4.545, 1.373,2025-05-26T09:25:12.250+08:00, 7.692, 1.382,2025-05-26T09:25:12.250+08:00, 0.012, 0.014, 0.015, 0.098, 0.053, 0.077
2025-05-26T09:27:00.000+08:00, 0.941,2025-05-26T09:26:45.570+08:00, 3.144, 0.871,2025-05-26T09:26:27.237+08:00, 4.065, 1.598,2025-05-26T09:26:27.240+08:00, 4.504, 1.812,2025-05-26T09:26:27.240+08:00, 0.016, 0.020, 0.020, 0.070, 0.065, 0.081
2025-05-26T09:28:00.000+08:00, 1.099,2025-05-26T09:27:10.760+08:00, 9.259, 0.770,2025-05-26T09:27:44.023+08:00, 3.521, 1.509,2025-05-26T09:27:36.363+08:00, 9.259, 1.569,2025-05-26T09:27:36.363+08:00, 0.017, 0.015, 0.026, 0.073, 0.052, 0.060
2025-05-26T09:29:00.000+08:00, 0.898,2025-05-26T09:28:05.756+08:00, 3.289, 0.684,2025-05-26T09:28:06.949+08:00, 3.086, 1.602,2025-05-26T09:28:17.796+08:00, 8.928, 1.631,2025-05-26T09:28:17.796+08:00, 0.009, 0.008, 0.022, 0.069, 0.039, 0.049
2025-05-26T09:30:00.000+08:00, 0.735,2025-05-26T09:29:16.569+08:00, 2.173, 1.036,2025-05-26T09:29:14.283+08:00, 4.132, 1.488,2025-05-26T09:29:13.697+08:00,13.513, 1.750,2025-05-26T09:29:14.284+08:00, 0.013, 0.023, 0.018, 0.049, 0.043, 0.052
2025-05-26T09:31:00.000+08:00, 0.683,2025-05-26T09:30:41.376+08:00, 2.793, 0.754,2025-05-26T09:30:41.748+08:00, 9.803, 1.415,2025-05-26T09:30:41.376+08:00,19.230, 1.585,2025-05-26T09:30:41.376+08:00, 0.010, 0.010, 0.016, 0.041, 0.036, 0.033
2025-05-26T09:32:00.000+08:00, 1.455,2025-05-26T09:31:09.573+08:00, 8.620, 1.003,2025-05-26T09:31:43.307+08:00, 3.816, 2.216,2025-05-26T09:31:43.034+08:00,25.000, 2.699,2025-05-26T09:31:43.034+08:00, 0.017, 0.014, 0.022, 0.147, 0.075, 0.064
2025-05-26T09:33:00.000+08:00, 0.784,2025-05-26T09:32:35.296+08:00, 2.840, 0.991,2025-05-26T09:32:47.825+08:00,12.500, 1.972,2025-05-26T09:32:35.356+08:00,17.857, 2.109,2025-05-26T09:32:34.321+08:00, 0.013, 0.014, 0.019, 0.045, 0.040, 0.053
2025-05-26T09:34:00.000+08:00, 0.869,2025-05-26T09:33:28.753+08:00, 2.525, 1.050,2025-05-26T09:33:37.018+08:00, 4.310, 1.977,2025-05-26T09:33:37.000+08:00, 4.545, 2.233,2025-05-26T09:33:37.001+08:00, 0.017, 0.011, 0.027, 0.070, 0.041, 0.048
2025-05-26T09:35:00.000+08:00, 1.001,2025-05-26T09:34:43.058+08:00, 3.571, 1.018,2025-05-26T09:34:31.567+08:00, 4.237, 1.635,2025-05-26T09:34:31.470+08:00,11.904, 1.772,2025-05-26T09:34:31.470+08:00, 0.013, 0.012, 0.020, 0.082, 0.052, 0.060
2025-05-26T09:36:00.000+08:00, 0.853,2025-05-26T09:35:06.410+08:00, 3.448, 1.042,2025-05-26T09:35:05.568+08:00, 6.849, 1.590,2025-05-26T09:35:13.213+08:00, 8.928, 1.698,2025-05-26T09:35:13.213+08:00, 0.011, 0.015, 0.017, 0.053, 0.058, 0.037
2025-05-26T09:37:00.000+08:00, 0.931,2025-05-26T09:36:58.906+08:00, 3.355, 1.024,2025-05-26T09:36:59.200+08:00, 3.597, 1.529,2025-05-26T09:36:59.103+08:00, 6.329, 1.713,2025-05-26T09:36:59.103+08:00, 0.010, 0.012, 0.017, 0.076, 0.050, 0.057
2025-05-26T09:38:00.000+08:00, 1.024,2025-05-26T09:37:01.526+08:00, 5.434, 0.813,2025-05-26T09:37:02.072+08:00, 4.132, 1.725,2025-05-26T09:37:20.505+08:00,16.666, 1.727,2025-05-26T09:37:18.235+08:00, 0.011, 0.011, 0.015, 0.069, 0.040, 0.054
2025-05-26T09:39:00.000+08:00, 0.961,2025-05-26T09:38:45.047+08:00, 4.065, 0.783,2025-05-26T09:38:43.209+08:00, 3.759, 1.303,2025-05-26T09:38:44.225+08:00, 7.352, 1.635,2025-05-26T09:38:44.225+08:00, 0.011, 0.015, 0.019, 0.083, 0.055, 0.066
2025-05-26T09:40:00.000+08:00, 0.667,2025-05-26T09:39:23.945+08:00, 4.098, 0.745,2025-05-26T09:39:58.813+08:00, 3.906, 1.359,2025-05-26T09:39:20.369+08:00, 5.050, 1.465,2025-05-26T09:39:20.370+08:00, 0.014, 0.015, 0.018, 0.052, 0.049, 0.040
2025-05-26T09:41:00.000+08:00, 2.071,2025-05-26T09:40:10.853+08:00, 3.030, 1.104,2025-05-26T09:40:09.600+08:00,11.627, 1.055,2025-05-26T09:40:03.736+08:00,19.230, 2.085,2025-05-26T09:40:10.853+08:00, 0.014, 0.018, 0.027, 0.187, 0.062, 0.046
2025-05-26T09:42:00.000+08:00, 0.831,2025-05-26T09:41:42.822+08:00, 3.030, 0.678,2025-05-26T09:41:31.560+08:00, 3.012, 1.510,2025-05-26T09:41:51.501+08:00, 4.237, 1.547,2025-05-26T09:41:51.481+08:00, 0.014, 0.009, 0.018, 0.050, 0.050, 0.042
2025-05-26T09:43:00.000+08:00, 0.890,2025-05-26T09:42:10.422+08:00, 3.012, 1.034,2025-05-26T09:42:09.522+08:00, 3.225, 1.380,2025-05-26T09:42:10.383+08:00,20.833, 1.568,2025-05-26T09:42:09.796+08:00, 0.010, 0.008, 0.017, 0.059, 0.069, 0.064
2025-05-26T09:44:00.000+08:00, 1.266,2025-05-26T09:43:40.906+08:00, 4.000, 0.893,2025-05-26T09:43:07.347+08:00, 4.237, 2.834,2025-05-26T09:43:07.563+08:00, 4.310, 2.892,2025-05-26T09:43:07.563+08:00, 0.015, 0.018, 0.030, 0.131, 0.045, 0.060
2025-05-26T09:45:00.000+08:00, 0.695,2025-05-26T09:44:20.567+08:00, 3.759, 0.922,2025-05-26T09:44:32.356+08:00, 3.267, 1.621,2025-05-26T09:44:42.755+08:00, 4.098, 1.712,2025-05-26T09:44:42.756+08:00, 0.008, 0.007, 0.016, 0.049, 0.054, 0.059
2025-05-26T09:46:00.000+08:00, 0.747,2025-05-26T09:45:49.887+08:00, 2.475, 1.078,2025-05-26T09:45:47.756+08:00, 3.378, 1.926,2025-05-26T09:45:18.608+08:00,11.627, 2.053,2025-05-26T09:45:18.608+08:00, 0.017, 0.016, 0.024, 0.065, 0.078, 0.065
2025-05-26T09:47:00.000+08:00, 0.740,2025-05-26T09:46:26.892+08:00, 2.873, 0.794,2025-05-26T09:46:28.320+08:00, 3.649, 1.349,2025-05-26T09:46:26.501+08:00, 4.098, 1.445,2025-05-26T09:46:26.501+08:00, 0.008, 0.008, 0.016, 0.060, 0.049, 0.047
2025-05-26T09:48:00.000+08:00, 0.877,2025-05-26T09:47:17.891+08:00, 5.208, 0.927,2025-05-26T09:47:17.636+08:00, 4.310, 1.229,2025-05-26T09:47:33.219+08:00,11.904, 1.261,2025-05-26T09:47:20.276+08:00, 0.010, 0.014, 0.022, 0.061, 0.072, 0.055
2025-05-26T09:49:00.000+08:00, 0.466,2025-05-26T09:48:30.337+08:00, 5.376, 0.808,2025-05-26T09:48:17.359+08:00, 4.672, 1.171,2025-05-26T09:48:43.879+08:00,21.739, 1.217,2025-05-26T09:48:43.879+08:00, 0.009, 0.010, 0.012, 0.038, 0.056, 0.071
2025-05-26T09:50:00.000+08:00, 1.171,2025-05-26T09:49:17.559+08:00, 3.571, 1.107,2025-05-26T09:49:46.139+08:00, 3.759, 1.987,2025-05-26T09:49:46.161+08:00,17.241, 2.146,2025-05-26T09:49:46.161+08:00, 0.016, 0.013, 0.020, 0.095, 0.089, 0.050
2025-05-26T09:51:00.000+08:00, 0.807,2025-05-26T09:50:02.366+08:00, 4.587, 0.889,2025-05-26T09:50:03.949+08:00, 4.273, 1.592,2025-05-26T09:50:03.968+08:00, 5.208, 1.811,2025-05-26T09:50:03.968+08:00, 0.010, 0.010, 0.018, 0.043, 0.037, 0.054
2025-05-26T09:52:00.000+08:00, 0.685,2025-05-26T09:51:12.402+08:00, 3.521, 1.171,2025-05-26T09:51:32.124+08:00, 4.464, 1.696,2025-05-26T09:51:31.735+08:00,14.285, 1.975,2025-05-26T09:51:31.735+08:00, 0.011, 0.009, 0.017, 0.046, 0.066, 0.054
2025-05-26T09:53:00.000+08:00, 1.050,2025-05-26T09:52:14.543+08:00, 3.378, 0.806,2025-05-26T09:52:06.959+08:00, 4.545, 1.220,2025-05-26T09:52:45.040+08:00,17.241, 1.287,2025-05-26T09:52:04.479+08:00, 0.013, 0.013, 0.016, 0.064, 0.054, 0.078
2025-05-26T09:54:00.000+08:00, 0.811,2025-05-26T09:53:30.493+08:00, 2.590, 0.977,2025-05-26T09:53:30.200+08:00, 3.906, 1.789,2025-05-26T09:53:29.416+08:00, 4.273, 2.017,2025-05-26T09:53:29.416+08:00, 0.010, 0.013, 0.023, 0.076, 0.053, 0.063
2025-05-26T09:55:00.000+08:00, 1.343,2025-05-26T09:54:38.646+08:00, 4.672, 0.907,2025-05-26T09:54:39.093+08:00, 4.065, 1.708,2025-05-26T09:54:38.626+08:00, 4.854, 1.822,2025-05-26T09:54:38.626+08:00, 0.014, 0.014, 0.019, 0.072, 0.074, 0.067
2025-05-26T09:56:00.000+08:00, 0.657,2025-05-26T09:55:05.588+08:00, 3.267, 0.726,2025-05-26T09:55:45.980+08:00, 3.875, 1.558,2025-05-26T09:55:48.618+08:00,13.513, 1.643,2025-05-26T09:55:05.667+08:00, 0.014, 0.010, 0.019, 0.042, 0.040, 0.046
2025-05-26T09:57:00.000+08:00, 0.866,2025-05-26T09:56:43.653+08:00, 4.065, 0.709,2025-05-26T09:56:48.071+08:00, 3.937, 1.280,2025-05-26T09:56:22.851+08:00, 9.259, 1.381,2025-05-26T09:56:22.851+08:00, 0.013, 0.013, 0.022, 0.082, 0.053, 0.040
2025-05-26T09:58:00.000+08:00, 0.607,2025-05-26T09:57:44.989+08:00, 7.246, 0.885,2025-05-26T09:57:34.801+08:00, 3.521, 1.552,2025-05-26T09:57:33.980+08:00, 6.493, 1.634,2025-05-26T09:57:33.980+08:00, 0.014, 0.011, 0.022, 0.041, 0.055, 0.063
2025-05-26T09:59:00.000+08:00, 0.641,2025-05-26T09:58:38.403+08:00,12.820, 0.822,2025-05-26T09:58:37.952+08:00,16.129, 1.234,2025-05-26T09:58:55.233+08:00,17.241, 1.414,2025-05-26T09:58:38.402+08:00, 0.010, 0.010, 0.025, 0.029, 0.035, 0.042
2025-05-26T10:00:00.000+08:00, 0.838,2025-05-26T09:59:36.329+08:00, 5.813, 1.226,2025-05-26T09:59:45.183+08:00, 3.875, 1.644,2025-05-26T09:59:44.500+08:00, 4.545, 1.967,2025-05-26T09:59:45.183+08:00, 0.011, 0.011, 0.017, 0.056, 0.068, 0.070
2025-05-26T10:01:00.000+08:00, 1.094,2025-05-26T10:00:58.912+08:00, 5.102, 0.997,2025-05-26T10:00:44.835+08:00, 4.273, 1.987,2025-05-26T10:00:58.912+08:00,16.666, 2.375,2025-05-26T10:00:58.912+08:00, 0.015, 0.016, 0.021, 0.081, 0.067, 0.045
2025-05-26T10:02:00.000+08:00, 0.756,2025-05-26T10:01:49.260+08:00, 4.132, 1.006,2025-05-26T10:01:50.747+08:00, 3.496, 1.489,2025-05-26T10:01:50.141+08:00, 4.424, 1.589,2025-05-26T10:01:50.141+08:00, 0.011, 0.009, 0.023, 0.052, 0.069, 0.068
2025-05-26T10:03:00.000+08:00, 0.805,2025-05-26T10:02:38.000+08:00,16.666, 0.624,2025-05-26T10:02:59.943+08:00, 4.310, 1.112,2025-05-26T10:02:59.747+08:00, 5.102, 1.242,2025-05-26T10:02:59.747+08:00, 0.015, 0.008, 0.017, 0.090, 0.036, 0.036
2025-05-26T10:04:00.000+08:00, 0.964,2025-05-26T10:03:58.463+08:00, 6.097, 1.017,2025-05-26T10:03:12.591+08:00, 5.319, 1.852,2025-05-26T10:03:47.006+08:00,11.627, 2.039,2025-05-26T10:03:47.006+08:00, 0.012, 0.013, 0.021, 0.060, 0.078, 0.076
2025-05-26T10:05:00.000+08:00, 0.661,2025-05-26T10:04:00.770+08:00, 3.496, 0.887,2025-05-26T10:04:31.550+08:00, 3.012, 1.247,2025-05-26T10:04:04.876+08:00, 4.385, 1.347,2025-05-26T10:04:04.876+08:00, 0.013, 0.012, 0.016, 0.048, 0.061, 0.030
2025-05-26T10:06:00.000+08:00, 0.713,2025-05-26T10:05:40.394+08:00, 3.164, 0.804,2025-05-26T10:05:09.506+08:00, 3.787, 1.568,2025-05-26T10:05:09.778+08:00, 8.474, 1.682,2025-05-26T10:05:09.505+08:00, 0.011, 0.019, 0.019, 0.058, 0.034, 0.040
2025-05-26T10:07:00.000+08:00, 0.755,2025-05-26T10:06:33.932+08:00,12.500, 0.748,2025-05-26T10:06:12.951+08:00, 9.615, 1.305,2025-05-26T10:06:42.768+08:00,16.666, 1.391,2025-05-26T10:06:42.768+08:00, 0.012, 0.011, 0.016, 0.041, 0.045, 0.070
2025-05-26T10:08:00.000+08:00, 1.007,2025-05-26T10:07:32.354+08:00, 7.142, 0.834,2025-05-26T10:07:14.695+08:00, 3.401, 1.359,2025-05-26T10:07:14.990+08:00, 8.771, 1.540,2025-05-26T10:07:14.990+08:00, 0.011, 0.009, 0.016, 0.069, 0.052, 0.047
2025-05-26T10:09:00.000+08:00, 0.821,2025-05-26T10:08:44.881+08:00, 6.250, 0.723,2025-05-26T10:08:47.519+08:00, 6.172, 1.372,2025-05-26T10:08:12.975+08:00, 9.803, 1.478,2025-05-26T10:08:12.975+08:00, 0.012, 0.011, 0.013, 0.065, 0.051, 0.038
2025-05-26T10:10:00.000+08:00, 0.995,2025-05-26T10:09:09.338+08:00, 3.030, 1.551,2025-05-26T10:09:09.457+08:00, 5.617, 1.941,2025-05-26T10:09:09.259+08:00, 5.319, 2.076,2025-05-26T10:09:09.338+08:00, 0.011, 0.009, 0.021, 0.058, 0.073, 0.063
2025-05-26T10:11:00.000+08:00, 1.053,2025-05-26T10:10:26.232+08:00, 2.857, 1.029,2025-05-26T10:10:56.010+08:00, 3.816, 1.548,2025-05-26T10:10:56.086+08:00, 4.950, 1.775,2025-05-26T10:10:56.009+08:00, 0.014, 0.012, 0.020, 0.056, 0.043, 0.062
2025-05-26T10:12:00.000+08:00, 1.004,2025-05-26T10:11:07.427+08:00, 2.976, 0.837,2025-05-26T10:11:05.299+08:00, 3.401, 1.152,2025-05-26T10:11:33.802+08:00,16.129, 1.302,2025-05-26T10:11:33.707+08:00, 0.012, 0.012, 0.015, 0.063, 0.062, 0.041
2025-05-26T10:13:00.000+08:00, 0.803,2025-05-26T10:12:41.694+08:00, 4.065, 0.693,2025-05-26T10:12:04.403+08:00, 3.968, 1.043,2025-05-26T10:12:05.518+08:00, 9.803, 1.262,2025-05-26T10:12:04.404+08:00, 0.015, 0.013, 0.016, 0.079, 0.037, 0.049
2025-05-26T10:14:00.000+08:00, 0.646,2025-05-26T10:13:38.635+08:00,11.904, 1.098,2025-05-26T10:13:35.976+08:00,12.195, 1.815,2025-05-26T10:13:35.331+08:00,11.627, 1.926,2025-05-26T10:13:35.331+08:00, 0.010, 0.010, 0.015, 0.040, 0.062, 0.098
2025-05-26T10:15:00.000+08:00, 0.765,2025-05-26T10:14:24.898+08:00, 3.496, 0.962,2025-05-26T10:14:24.096+08:00, 3.731, 1.441,2025-05-26T10:14:34.321+08:00, 4.201, 1.543,2025-05-26T10:14:34.321+08:00, 0.011, 0.011, 0.019, 0.045, 0.068, 0.046
2025-05-26T10:16:00.000+08:00, 1.107,2025-05-26T10:15:43.854+08:00, 5.494, 0.872,2025-05-26T10:15:51.557+08:00, 9.259, 1.458,2025-05-26T10:15:31.478+08:00, 9.803, 1.517,2025-05-26T10:15:31.478+08:00, 0.011, 0.012, 0.025, 0.078, 0.044, 0.042
2025-05-26T10:17:00.000+08:00, 0.846,2025-05-26T10:16:28.736+08:00,13.157, 0.729,2025-05-26T10:16:02.725+08:00, 4.166, 1.822,2025-05-26T10:16:44.868+08:00, 7.462, 1.901,2025-05-26T10:16:44.868+08:00, 0.008, 0.007, 0.017, 0.074, 0.056, 0.051
2025-05-26T10:18:00.000+08:00, 0.664,2025-05-26T10:17:31.426+08:00, 3.311, 0.864,2025-05-26T10:17:50.356+08:00, 3.225, 1.802,2025-05-26T10:17:49.653+08:00, 4.504, 1.895,2025-05-26T10:17:49.653+08:00, 0.010, 0.012, 0.017, 0.064, 0.055, 0.049
2025-05-26T10:19:00.000+08:00, 0.807,2025-05-26T10:18:58.929+08:00, 2.840, 0.774,2025-05-26T10:18:23.476+08:00, 4.132, 1.815,2025-05-26T10:18:58.988+08:00,10.000, 1.862,2025-05-26T10:18:58.988+08:00, 0.012, 0.013, 0.018, 0.050, 0.049, 0.046
2025-05-26T10:20:00.000+08:00, 1.902,2025-05-26T10:19:55.547+08:00, 2.890, 0.939,2025-05-26T10:19:00.806+08:00, 4.347, 1.380,2025-05-26T10:18:59.848+08:00,21.739, 1.938,2025-05-26T10:19:55.547+08:00, 0.012, 0.012, 0.020, 0.193, 0.055, 0.053
2025-05-26T10:21:00.000+08:00, 0.772,2025-05-26T10:20:43.088+08:00, 6.024, 1.011,2025-05-26T10:20:44.632+08:00, 2.659, 1.239,2025-05-26T10:20:52.082+08:00,11.111, 1.362,2025-05-26T10:20:45.570+08:00, 0.012, 0.012, 0.019, 0.068, 0.071, 0.058
2025-05-26T10:22:00.000+08:00, 0.835,2025-05-26T10:21:26.833+08:00, 5.319, 0.707,2025-05-26T10:21:03.171+08:00, 3.937, 1.347,2025-05-26T10:21:03.170+08:00, 4.237, 1.520,2025-05-26T10:21:03.170+08:00, 0.016, 0.017, 0.018, 0.073, 0.050, 0.050
2025-05-26T10:23:00.000+08:00, 0.820,2025-05-26T10:22:53.153+08:00, 3.759, 1.065,2025-05-26T10:22:23.386+08:00, 4.000, 1.408,2025-05-26T10:22:24.129+08:00,11.627, 1.621,2025-05-26T10:22:24.052+08:00, 0.008, 0.014, 0.012, 0.058, 0.076, 0.079
2025-05-26T10:24:00.000+08:00, 0.752,2025-05-26T10:23:44.842+08:00, 2.976, 0.871,2025-05-26T10:23:59.391+08:00, 3.623, 1.768,2025-05-26T10:23:49.634+08:00, 3.496, 1.789,2025-05-26T10:23:49.634+08:00, 0.011, 0.018, 0.017, 0.052, 0.056, 0.076
2025-05-26T10:25:00.000+08:00, 0.813,2025-05-26T10:24:11.574+08:00, 3.205, 0.807,2025-05-26T10:24:25.992+08:00, 3.787, 1.359,2025-05-26T10:24:00.958+08:00, 5.494, 1.521,2025-05-26T10:24:00.958+08:00, 0.010, 0.007, 0.015, 0.077, 0.058, 0.043
2025-05-26T10:26:00.000+08:00, 0.728,2025-05-26T10:25:31.243+08:00, 2.336, 0.777,2025-05-26T10:25:53.874+08:00, 3.378, 1.993,2025-05-26T10:25:31.084+08:00, 3.378, 2.084,2025-05-26T10:25:31.084+08:00, 0.010, 0.007, 0.023, 0.036, 0.053, 0.068
2025-05-26T10:27:00.000+08:00, 0.848,2025-05-26T10:26:18.946+08:00, 3.355, 1.154,2025-05-26T10:26:17.949+08:00,11.363, 1.663,2025-05-26T10:26:47.076+08:00,12.500, 2.052,2025-05-26T10:26:17.950+08:00, 0.010, 0.009, 0.020, 0.046, 0.059, 0.057
2025-05-26T10:28:00.000+08:00, 1.020,2025-05-26T10:27:24.727+08:00, 3.472, 0.645,2025-05-26T10:27:07.260+08:00, 3.676, 1.383,2025-05-26T10:27:05.539+08:00,15.625, 1.478,2025-05-26T10:27:05.051+08:00, 0.013, 0.013, 0.019, 0.065, 0.041, 0.064
2025-05-26T10:29:00.000+08:00, 0.908,2025-05-26T10:28:32.473+08:00, 6.944, 1.074,2025-05-26T10:28:34.273+08:00, 3.676, 2.066,2025-05-26T10:28:31.533+08:00,31.250, 2.172,2025-05-26T10:28:31.533+08:00, 0.010, 0.012, 0.025, 0.068, 0.071, 0.062
2025-05-26T10:30:00.000+08:00, 1.160,2025-05-26T10:29:16.446+08:00, 3.424, 0.916,2025-05-26T10:29:16.818+08:00, 3.571, 1.395,2025-05-26T10:29:08.132+08:00,20.833, 1.626,2025-05-26T10:29:16.448+08:00, 0.016, 0.012, 0.019, 0.101, 0.054, 0.051
2025-05-26T10:31:00.000+08:00, 0.909,2025-05-26T10:30:08.284+08:00, 5.376, 0.805,2025-05-26T10:30:45.485+08:00, 3.816, 2.636,2025-05-26T10:30:17.534+08:00, 5.747, 2.762,2025-05-26T10:30:17.534+08:00, 0.013, 0.008, 0.025, 0.079, 0.036, 0.047
2025-05-26T10:32:00.000+08:00, 0.680,2025-05-26T10:31:54.782+08:00, 5.000, 0.776,2025-05-26T10:31:53.903+08:00, 3.906, 1.535,2025-05-26T10:31:54.254+08:00,12.500, 1.556,2025-05-26T10:31:54.254+08:00, 0.011, 0.013, 0.016, 0.059, 0.036, 0.041
2025-05-26T10:33:00.000+08:00, 0.826,2025-05-26T10:32:38.263+08:00, 4.065, 0.614,2025-05-26T10:32:43.369+08:00, 4.098, 1.475,2025-05-26T10:32:22.456+08:00, 5.376, 1.579,2025-05-26T10:32:22.359+08:00, 0.010, 0.012, 0.018, 0.072, 0.041, 0.034
2025-05-26T10:34:00.000+08:00, 0.823,2025-05-26T10:33:41.683+08:00, 8.771, 0.564,2025-05-26T10:33:16.876+08:00, 4.098, 1.321,2025-05-26T10:33:16.113+08:00,10.869, 1.397,2025-05-26T10:33:16.113+08:00, 0.010, 0.016, 0.015, 0.078, 0.041, 0.037
2025-05-26T10:35:00.000+08:00, 1.341,2025-05-26T10:34:09.026+08:00, 3.649, 0.974,2025-05-26T10:34:12.805+08:00, 3.048, 1.669,2025-05-26T10:34:32.526+08:00, 4.310, 1.854,2025-05-26T10:34:32.526+08:00, 0.010, 0.013, 0.018, 0.063, 0.072, 0.064
2025-05-26T10:36:00.000+08:00, 0.669,2025-05-26T10:35:08.656+08:00, 2.525, 0.922,2025-05-26T10:35:11.707+08:00, 3.676, 1.489,2025-05-26T10:35:18.340+08:00,14.705, 1.559,2025-05-26T10:35:18.340+08:00, 0.017, 0.010, 0.019, 0.045, 0.048, 0.041
2025-05-26T10:37:00.000+08:00, 1.151,2025-05-26T10:36:55.135+08:00, 4.166, 1.233,2025-05-26T10:36:56.543+08:00, 4.504, 1.498,2025-05-26T10:36:56.250+08:00, 4.545, 1.717,2025-05-26T10:36:56.543+08:00, 0.013, 0.011, 0.017, 0.069, 0.049, 0.045
2025-05-26T10:38:00.000+08:00, 0.756,2025-05-26T10:37:32.633+08:00, 5.494, 0.909,2025-05-26T10:37:14.168+08:00, 8.064, 1.294,2025-05-26T10:37:13.819+08:00,12.500, 1.423,2025-05-26T10:37:53.823+08:00, 0.013, 0.016, 0.018, 0.039, 0.066, 0.056
2025-05-26T10:39:00.000+08:00, 0.705,2025-05-26T10:38:23.085+08:00, 3.333, 0.638,2025-05-26T10:38:20.895+08:00, 4.807, 1.572,2025-05-26T10:38:32.050+08:00, 9.615, 1.613,2025-05-26T10:38:32.050+08:00, 0.011, 0.011, 0.024, 0.074, 0.035, 0.036
2025-05-26T10:40:00.000+08:00, 0.863,2025-05-26T10:39:55.701+08:00, 3.731, 1.093,2025-05-26T10:39:55.916+08:00, 3.846, 1.691,2025-05-26T10:39:01.259+08:00, 3.521, 1.865,2025-05-26T10:39:01.259+08:00, 0.014, 0.014, 0.023, 0.081, 0.088, 0.071
2025-05-26T10:41:00.000+08:00, 0.578,2025-05-26T10:40:18.315+08:00, 3.378, 1.023,2025-05-26T10:40:33.592+08:00, 4.000, 1.770,2025-05-26T10:40:33.592+08:00,12.820, 2.040,2025-05-26T10:40:33.592+08:00, 0.017, 0.010, 0.019, 0.058, 0.036, 0.051
2025-05-26T10:42:00.000+08:00, 0.787,2025-05-26T10:41:10.093+08:00,14.705, 0.872,2025-05-26T10:41:05.400+08:00,11.627, 1.493,2025-05-26T10:41:06.024+08:00,13.513, 1.718,2025-05-26T10:41:06.025+08:00, 0.013, 0.012, 0.020, 0.087, 0.055, 0.052
2025-05-26T10:43:00.000+08:00, 0.940,2025-05-26T10:42:31.821+08:00, 3.787, 0.637,2025-05-26T10:42:33.308+08:00, 4.000, 1.481,2025-05-26T10:42:50.856+08:00, 7.352, 1.621,2025-05-26T10:42:50.856+08:00, 0.018, 0.011, 0.019, 0.078, 0.061, 0.036
2025-05-26T10:44:00.000+08:00, 1.035,2025-05-26T10:43:21.253+08:00, 5.555, 0.998,2025-05-26T10:43:15.875+08:00, 5.050, 1.335,2025-05-26T10:42:59.912+08:00, 5.494, 1.571,2025-05-26T10:43:16.109+08:00, 0.010, 0.008, 0.015, 0.064, 0.055, 0.064
2025-05-26T10:45:00.000+08:00, 0.776,2025-05-26T10:44:21.873+08:00, 4.201, 0.780,2025-05-26T10:44:32.222+08:00, 4.132, 1.712,2025-05-26T10:44:05.418+08:00,14.705, 1.871,2025-05-26T10:44:05.418+08:00, 0.014, 0.011, 0.019, 0.057, 0.048, 0.052
2025-05-26T10:46:00.000+08:00, 2.117,2025-05-26T10:45:43.905+08:00, 2.840, 1.153,2025-05-26T10:45:43.903+08:00,10.416, 1.582,2025-05-26T10:45:01.138+08:00,13.157, 2.383,2025-05-26T10:45:43.904+08:00, 0.011, 0.015, 0.025, 0.262, 0.120, 0.061
2025-05-26T10:47:00.000+08:00, 0.870,2025-05-26T10:46:20.839+08:00, 5.555, 0.974,2025-05-26T10:46:08.319+08:00, 7.142, 1.521,2025-05-26T10:46:58.262+08:00, 5.681, 1.658,2025-05-26T10:46:58.262+08:00, 0.009, 0.012, 0.018, 0.062, 0.055, 0.053
2025-05-26T10:48:00.000+08:00, 1.054,2025-05-26T10:47:37.287+08:00, 3.875, 1.028,2025-05-26T10:47:37.815+08:00, 3.424, 1.478,2025-05-26T10:47:55.892+08:00, 7.462, 1.684,2025-05-26T10:47:55.893+08:00, 0.014, 0.011, 0.020, 0.052, 0.073, 0.063
2025-05-26T10:49:00.000+08:00, 0.733,2025-05-26T10:48:17.098+08:00, 3.401, 0.740,2025-05-26T10:48:56.461+08:00, 3.968, 1.342,2025-05-26T10:48:20.957+08:00, 5.263, 1.370,2025-05-26T10:48:04.229+08:00, 0.012, 0.017, 0.018, 0.053, 0.039, 0.050
2025-05-26T10:50:00.000+08:00, 0.947,2025-05-26T10:49:32.102+08:00, 3.759, 0.732,2025-05-26T10:49:23.868+08:00, 3.649, 2.016,2025-05-26T10:49:40.593+08:00, 4.424, 2.042,2025-05-26T10:49:40.593+08:00, 0.012, 0.016, 0.019, 0.070, 0.045, 0.046
2025-05-26T10:51:00.000+08:00, 0.752,2025-05-26T10:50:56.898+08:00, 4.716, 1.088,2025-05-26T10:50:56.567+08:00, 4.065, 1.638,2025-05-26T10:50:58.815+08:00, 4.098, 1.753,2025-05-26T10:50:58.815+08:00, 0.011, 0.013, 0.019, 0.048, 0.069, 0.059
2025-05-26T10:52:00.000+08:00, 0.649,2025-05-26T10:51:47.681+08:00, 3.759, 0.761,2025-05-26T10:51:25.203+08:00, 4.385, 1.629,2025-05-26T10:51:25.204+08:00, 7.692, 1.789,2025-05-26T10:51:25.204+08:00, 0.013, 0.015, 0.020, 0.050, 0.044, 0.055
2025-05-26T10:53:00.000+08:00, 0.834,2025-05-26T10:52:42.889+08:00,13.513, 1.011,2025-05-26T10:52:43.457+08:00,12.195, 1.600,2025-05-26T10:52:42.791+08:00,16.666, 1.726,2025-05-26T10:52:42.948+08:00, 0.017, 0.014, 0.032, 0.069, 0.059, 0.055
2025-05-26T10:54:00.000+08:00, 0.706,2025-05-26T10:53:43.729+08:00, 6.250, 0.861,2025-05-26T10:53:54.154+08:00, 3.164, 2.210,2025-05-26T10:53:53.156+08:00, 3.846, 2.346,2025-05-26T10:53:53.156+08:00, 0.010, 0.008, 0.018, 0.046, 0.045, 0.069
2025-05-26T10:55:00.000+08:00, 0.928,2025-05-26T10:54:34.300+08:00, 3.937, 0.977,2025-05-26T10:54:14.968+08:00, 4.716, 1.696,2025-05-26T10:54:18.293+08:00, 6.849, 1.735,2025-05-26T10:54:18.293+08:00, 0.009, 0.014, 0.019, 0.073, 0.049, 0.058
2025-05-26T10:56:00.000+08:00, 0.812,2025-05-26T10:55:23.384+08:00, 3.759, 0.771,2025-05-26T10:55:19.159+08:00, 4.807, 1.524,2025-05-26T10:55:14.639+08:00,16.129, 1.673,2025-05-26T10:55:19.375+08:00, 0.015, 0.013, 0.027, 0.058, 0.047, 0.051
2025-05-26T10:57:00.000+08:00, 1.662,2025-05-26T10:56:48.232+08:00, 5.813, 0.771,2025-05-26T10:56:49.719+08:00, 3.703, 1.031,2025-05-26T10:56:03.881+08:00, 8.064, 1.947,2025-05-26T10:56:48.213+08:00, 0.010, 0.012, 0.020, 0.143, 0.062, 0.044
2025-05-26T10:58:00.000+08:00, 0.906,2025-05-26T10:57:05.487+08:00, 4.761, 0.686,2025-05-26T10:57:57.896+08:00, 4.504, 1.514,2025-05-26T10:57:59.598+08:00, 5.208, 1.707,2025-05-26T10:57:57.896+08:00, 0.010, 0.013, 0.016, 0.089, 0.042, 0.041
2025-05-26T10:59:00.000+08:00, 1.089,2025-05-26T10:58:56.709+08:00, 2.304, 0.633,2025-05-26T10:58:17.148+08:00, 2.923, 1.272,2025-05-26T10:58:46.280+08:00, 5.434, 1.339,2025-05-26T10:58:46.280+08:00, 0.011, 0.019, 0.021, 0.093, 0.036, 0.044
2025-05-26T11:00:00.000+08:00, 0.858,2025-05-26T10:59:19.053+08:00, 2.840, 0.898,2025-05-26T10:59:39.129+08:00, 4.587, 1.342,2025-05-26T10:59:03.676+08:00, 8.474, 1.581,2025-05-26T10:59:39.146+08:00, 0.021, 0.014, 0.028, 0.073, 0.054, 0.048
2025-05-26T11:01:00.000+08:00, 0.652,2025-05-26T11:00:43.261+08:00, 2.645, 0.731,2025-05-26T11:00:28.938+08:00, 3.597, 1.517,2025-05-26T11:00:41.519+08:00,10.204, 1.554,2025-05-26T11:00:41.519+08:00, 0.013, 0.012, 0.020, 0.041, 0.038, 0.052
2025-05-26T11:02:00.000+08:00, 0.587,2025-05-26T11:01:33.680+08:00,71.428, 0.603,2025-05-26T11:01:57.427+08:00, 4.950, 1.451,2025-05-26T11:01:37.473+08:00,26.315, 1.539,2025-05-26T11:01:37.473+08:00, 0.012, 0.009, 0.020, 0.048, 0.033, 0.042
2025-05-26T11:03:00.000+08:00, 0.941,2025-05-26T11:02:36.128+08:00, 2.857, 0.716,2025-05-26T11:02:40.903+08:00, 3.267, 1.119,2025-05-26T11:02:39.552+08:00,11.363, 1.360,2025-05-26T11:02:39.513+08:00, 0.013, 0.009, 0.020, 0.077, 0.047, 0.058
2025-05-26T11:04:00.000+08:00, 0.925,2025-05-26T11:03:55.156+08:00, 3.906, 0.684,2025-05-26T11:03:25.729+08:00, 2.873, 1.186,2025-05-26T11:03:41.849+08:00, 4.950, 1.217,2025-05-26T11:03:41.849+08:00, 0.015, 0.019, 0.023, 0.071, 0.038, 0.043
2025-05-26T11:05:00.000+08:00, 0.892,2025-05-26T11:04:12.081+08:00, 4.424, 0.944,2025-05-26T11:04:16.931+08:00, 8.196, 1.672,2025-05-26T11:04:16.306+08:00, 9.615, 1.755,2025-05-26T11:04:06.114+08:00, 0.013, 0.014, 0.023, 0.066, 0.068, 0.066
2025-05-26T11:06:00.000+08:00, 1.361,2025-05-26T11:05:18.911+08:00, 4.166, 1.070,2025-05-26T11:05:15.232+08:00, 5.617, 1.908,2025-05-26T11:05:15.056+08:00, 9.433, 2.150,2025-05-26T11:05:15.056+08:00, 0.012, 0.012, 0.020, 0.128, 0.043, 0.047
2025-05-26T11:07:00.000+08:00, 0.763,2025-05-26T11:06:14.376+08:00, 2.164, 1.210,2025-05-26T11:06:11.462+08:00, 3.521, 1.690,2025-05-26T11:06:50.578+08:00,12.195, 1.976,2025-05-26T11:06:51.142+08:00, 0.010, 0.011, 0.017, 0.050, 0.094, 0.052
2025-05-26T11:08:00.000+08:00, 0.919,2025-05-26T11:07:41.177+08:00, 3.125, 0.720,2025-05-26T11:07:36.482+08:00, 3.703, 1.778,2025-05-26T11:07:01.417+08:00,12.500, 1.823,2025-05-26T11:07:01.417+08:00, 0.013, 0.013, 0.020, 0.058, 0.038, 0.052
2025-05-26T11:09:00.000+08:00, 0.900,2025-05-26T11:08:19.097+08:00, 4.310, 0.968,2025-05-26T11:08:20.038+08:00, 3.649, 2.278,2025-05-26T11:08:55.122+08:00, 4.629, 2.398,2025-05-26T11:08:55.122+08:00, 0.010, 0.012, 0.022, 0.066, 0.057, 0.043
2025-05-26T11:10:00.000+08:00, 0.687,2025-05-26T11:09:08.564+08:00, 4.098, 0.975,2025-05-26T11:09:12.871+08:00, 3.448, 2.099,2025-05-26T11:09:12.774+08:00,27.777, 2.280,2025-05-26T11:09:12.774+08:00, 0.011, 0.017, 0.022, 0.040, 0.040, 0.057
2025-05-26T11:11:00.000+08:00, 0.718,2025-05-26T11:10:19.215+08:00, 9.090, 0.889,2025-05-26T11:10:30.526+08:00, 5.882, 1.465,2025-05-26T11:10:30.525+08:00, 9.615, 1.704,2025-05-26T11:10:30.525+08:00, 0.012, 0.011, 0.019, 0.041, 0.035, 0.044
2025-05-26T11:12:00.000+08:00, 0.828,2025-05-26T11:11:09.114+08:00, 3.703, 0.746,2025-05-26T11:11:46.105+08:00, 3.649, 1.824,2025-05-26T11:11:46.085+08:00,13.513, 2.051,2025-05-26T11:11:46.085+08:00, 0.010, 0.012, 0.018, 0.068, 0.041, 0.034
2025-05-26T11:13:00.000+08:00, 0.702,2025-05-26T11:12:12.935+08:00, 2.645, 0.771,2025-05-26T11:12:03.524+08:00, 4.761, 1.392,2025-05-26T11:12:05.950+08:00, 9.803, 1.534,2025-05-26T11:12:03.524+08:00, 0.014, 0.016, 0.023, 0.060, 0.052, 0.054
2025-05-26T11:14:00.000+08:00, 1.070,2025-05-26T11:13:05.753+08:00, 4.132, 0.739,2025-05-26T11:13:26.107+08:00, 4.065, 1.439,2025-05-26T11:13:20.863+08:00, 8.196, 1.656,2025-05-26T11:13:20.863+08:00, 0.011, 0.011, 0.019, 0.092, 0.046, 0.030
2025-05-26T11:15:00.000+08:00, 2.184,2025-05-26T11:14:46.419+08:00, 2.747, 0.718,2025-05-26T11:14:44.872+08:00, 2.824, 1.397,2025-05-26T11:14:25.655+08:00,23.809, 2.228,2025-05-26T11:14:46.419+08:00, 0.016, 0.012, 0.019, 0.169, 0.050, 0.050
2025-05-26T11:16:00.000+08:00, 0.755,2025-05-26T11:15:24.382+08:00, 4.000, 0.758,2025-05-26T11:15:41.521+08:00, 4.901, 1.481,2025-05-26T11:15:56.789+08:00, 8.771, 1.642,2025-05-26T11:15:56.789+08:00, 0.013, 0.014, 0.022, 0.072, 0.051, 0.049
2025-05-26T11:17:00.000+08:00, 0.867,2025-05-26T11:16:38.314+08:00, 7.462, 0.960,2025-05-26T11:16:36.476+08:00, 6.493, 1.915,2025-05-26T11:16:33.247+08:00,23.809, 2.081,2025-05-26T11:16:33.247+08:00, 0.010, 0.009, 0.018, 0.067, 0.062, 0.077
2025-05-26T11:18:00.000+08:00, 0.984,2025-05-26T11:17:12.124+08:00, 3.289, 1.034,2025-05-26T11:17:07.525+08:00, 4.098, 2.239,2025-05-26T11:17:07.625+08:00, 3.968, 2.436,2025-05-26T11:17:07.625+08:00, 0.013, 0.014, 0.024, 0.063, 0.055, 0.077
2025-05-26T11:19:00.000+08:00, 0.821,2025-05-26T11:18:47.501+08:00, 3.424, 1.224,2025-05-26T11:18:44.940+08:00, 3.649, 1.444,2025-05-26T11:18:18.480+08:00,11.363, 1.854,2025-05-26T11:18:44.940+08:00, 0.013, 0.016, 0.027, 0.052, 0.057, 0.053
2025-05-26T11:20:00.000+08:00, 1.079,2025-05-26T11:19:21.381+08:00, 7.812, 0.895,2025-05-26T11:19:01.595+08:00, 7.812, 1.295,2025-05-26T11:19:53.282+08:00,15.625, 1.418,2025-05-26T11:19:01.927+08:00, 0.011, 0.012, 0.020, 0.070, 0.047, 0.056
2025-05-26T11:21:00.000+08:00, 1.037,2025-05-26T11:20:58.681+08:00, 2.762, 0.972,2025-05-26T11:20:25.360+08:00,11.111, 1.560,2025-05-26T11:20:35.203+08:00,20.000, 1.660,2025-05-26T11:20:35.808+08:00, 0.014, 0.012, 0.024, 0.093, 0.078, 0.047
2025-05-26T11:22:00.000+08:00, 1.324,2025-05-26T11:21:44.084+08:00, 3.048, 0.857,2025-05-26T11:21:45.726+08:00, 4.310, 1.446,2025-05-26T11:21:45.845+08:00, 8.196, 1.638,2025-05-26T11:21:45.845+08:00, 0.011, 0.013, 0.020, 0.109, 0.060, 0.055
2025-05-26T11:23:00.000+08:00, 0.791,2025-05-26T11:22:18.584+08:00, 5.555, 0.674,2025-05-26T11:22:34.690+08:00, 4.132, 1.401,2025-05-26T11:22:01.365+08:00, 4.424, 1.491,2025-05-26T11:22:01.365+08:00, 0.019, 0.017, 0.028, 0.078, 0.040, 0.054
2025-05-26T11:24:00.000+08:00, 1.077,2025-05-26T11:23:55.652+08:00, 3.521, 1.127,2025-05-26T11:23:59.294+08:00, 4.672, 1.743,2025-05-26T11:23:59.294+08:00, 5.681, 2.084,2025-05-26T11:23:59.294+08:00, 0.010, 0.018, 0.018, 0.074, 0.068, 0.055
2025-05-26T11:25:00.000+08:00, 0.713,2025-05-26T11:24:15.577+08:00, 3.401, 0.829,2025-05-26T11:24:45.418+08:00, 4.065, 1.586,2025-05-26T11:24:48.569+08:00, 2.994, 1.717,2025-05-26T11:24:44.617+08:00, 0.012, 0.015, 0.019, 0.063, 0.057, 0.059
2025-05-26T11:26:00.000+08:00, 0.846,2025-05-26T11:25:04.285+08:00, 3.472, 0.945,2025-05-26T11:25:57.911+08:00, 4.385, 1.434,2025-05-26T11:25:58.009+08:00, 5.208, 1.660,2025-05-26T11:25:58.009+08:00, 0.015, 0.018, 0.018, 0.051, 0.053, 0.066
2025-05-26T11:27:00.000+08:00, 0.907,2025-05-26T11:26:14.745+08:00, 7.936, 0.752,2025-05-26T11:26:46.435+08:00, 7.575, 1.346,2025-05-26T11:26:42.795+08:00, 8.771, 1.488,2025-05-26T11:26:10.753+08:00, 0.013, 0.013, 0.024, 0.063, 0.046, 0.045
2025-05-26T11:28:00.000+08:00, 1.011,2025-05-26T11:27:11.329+08:00, 3.787, 0.838,2025-05-26T11:27:11.115+08:00, 4.273, 1.632,2025-05-26T11:27:10.469+08:00, 8.333, 1.785,2025-05-26T11:27:11.114+08:00, 0.011, 0.011, 0.022, 0.105, 0.059, 0.040
2025-05-26T11:29:00.000+08:00, 0.737,2025-05-26T11:28:23.575+08:00, 4.000, 0.923,2025-05-26T11:28:19.876+08:00, 4.672, 1.241,2025-05-26T11:28:22.304+08:00, 5.617, 1.435,2025-05-26T11:28:22.304+08:00, 0.012, 0.023, 0.025, 0.054, 0.054, 0.048
2025-05-26T11:30:00.000+08:00, 0.857,2025-05-26T11:29:07.926+08:00, 3.355, 0.942,2025-05-26T11:29:08.084+08:00,10.638, 1.546,2025-05-26T11:29:18.087+08:00,11.904, 1.699,2025-05-26T11:29:18.087+08:00, 0.013, 0.014, 0.021, 0.046, 0.051, 0.046
2025-05-26T11:31:00.000+08:00, 0.915,2025-05-26T11:30:40.860+08:00, 4.237, 0.851,2025-05-26T11:30:36.396+08:00, 3.846, 1.262,2025-05-26T11:30:35.909+08:00, 4.587, 1.404,2025-05-26T11:30:57.044+08:00, 0.013, 0.015, 0.018, 0.070, 0.056, 0.042
2025-05-26T11:32:00.000+08:00, 0.751,2025-05-26T11:31:32.256+08:00, 2.192, 0.880,2025-05-26T11:31:32.256+08:00, 3.937, 1.412,2025-05-26T11:31:32.256+08:00, 9.259, 1.818,2025-05-26T11:31:32.256+08:00, 0.013, 0.010, 0.022, 0.082, 0.036, 0.045
2025-05-26T11:33:00.000+08:00, 1.011,2025-05-26T11:32:32.623+08:00, 3.731, 1.101,2025-05-26T11:32:16.689+08:00, 4.098, 1.547,2025-05-26T11:32:02.129+08:00,18.518, 1.639,2025-05-26T11:32:02.129+08:00, 0.012, 0.012, 0.017, 0.105, 0.045, 0.054
2025-05-26T11:34:00.000+08:00, 1.017,2025-05-26T11:33:18.992+08:00, 3.105, 1.235,2025-05-26T11:33:30.794+08:00, 3.424, 1.907,2025-05-26T11:33:18.971+08:00, 7.936, 2.063,2025-05-26T11:33:19.324+08:00, 0.017, 0.015, 0.023, 0.049, 0.052, 0.050
2025-05-26T11:35:00.000+08:00, 0.708,2025-05-26T11:34:05.949+08:00, 3.597, 0.601,2025-05-26T11:34:55.995+08:00, 3.875, 1.088,2025-05-26T11:34:55.604+08:00,20.833, 1.230,2025-05-26T11:34:05.560+08:00, 0.008, 0.013, 0.012, 0.048, 0.049, 0.036
2025-05-26T11:36:00.000+08:00, 0.614,2025-05-26T11:35:24.534+08:00,16.129, 0.752,2025-05-26T11:35:57.240+08:00, 4.807, 1.353,2025-05-26T11:35:57.337+08:00,19.230, 1.461,2025-05-26T11:35:57.337+08:00, 0.012, 0.011, 0.017, 0.048, 0.037, 0.034
2025-05-26T11:37:00.000+08:00, 0.706,2025-05-26T11:36:20.860+08:00, 3.816, 0.893,2025-05-26T11:36:43.978+08:00, 3.311, 1.226,2025-05-26T11:36:29.376+08:00,27.777, 1.363,2025-05-26T11:36:29.376+08:00, 0.007, 0.010, 0.015, 0.065, 0.048, 0.056
2025-05-26T11:38:00.000+08:00, 0.789,2025-05-26T11:37:52.729+08:00, 3.012, 0.775,2025-05-26T11:37:52.534+08:00, 3.424, 1.145,2025-05-26T11:37:48.070+08:00,15.151, 1.294,2025-05-26T11:37:48.286+08:00, 0.012, 0.012, 0.016, 0.064, 0.054, 0.053
2025-05-26T11:39:00.000+08:00, 1.141,2025-05-26T11:38:47.661+08:00, 4.201, 0.885,2025-05-26T11:38:48.228+08:00, 4.901, 1.372,2025-05-26T11:38:47.330+08:00,17.241, 1.803,2025-05-26T11:38:47.465+08:00, 0.010, 0.010, 0.020, 0.087, 0.066, 0.058
2025-05-26T11:40:00.000+08:00, 1.021,2025-05-26T11:39:28.260+08:00,12.195, 1.141,2025-05-26T11:39:08.157+08:00,13.513, 2.845,2025-05-26T11:39:59.153+08:00,13.513, 2.898,2025-05-26T11:39:59.153+08:00, 0.010, 0.010, 0.025, 0.087, 0.065, 0.047
2025-05-26T11:41:00.000+08:00, 1.056,2025-05-26T11:40:37.624+08:00,31.250, 1.072,2025-05-26T11:40:23.115+08:00,10.204, 1.789,2025-05-26T11:40:52.737+08:00,13.157, 1.970,2025-05-26T11:40:52.737+08:00, 0.013, 0.013, 0.027, 0.098, 0.054, 0.053
2025-05-26T11:42:00.000+08:00, 0.985,2025-05-26T11:41:53.429+08:00, 3.030, 0.686,2025-05-26T11:41:53.565+08:00, 3.937, 1.122,2025-05-26T11:41:46.477+08:00,16.666, 1.449,2025-05-26T11:41:53.429+08:00, 0.012, 0.011, 0.017, 0.084, 0.049, 0.043
2025-05-26T11:43:00.000+08:00, 0.973,2025-05-26T11:42:36.659+08:00, 4.310, 0.877,2025-05-26T11:42:49.306+08:00, 4.237, 1.689,2025-05-26T11:42:40.770+08:00, 9.259, 1.711,2025-05-26T11:42:40.770+08:00, 0.012, 0.012, 0.020, 0.062, 0.062, 0.045
2025-05-26T11:44:00.000+08:00, 0.924,2025-05-26T11:43:54.519+08:00, 3.787, 0.798,2025-05-26T11:43:53.991+08:00, 9.615, 1.437,2025-05-26T11:43:00.762+08:00,10.869, 1.580,2025-05-26T11:43:00.762+08:00, 0.011, 0.016, 0.017, 0.090, 0.055, 0.051
2025-05-26T11:45:00.000+08:00, 1.040,2025-05-26T11:44:53.172+08:00, 3.676, 1.004,2025-05-26T11:44:23.747+08:00, 3.289, 1.387,2025-05-26T11:44:01.489+08:00, 3.333, 1.771,2025-05-26T11:44:23.748+08:00, 0.012, 0.013, 0.017, 0.080, 0.073, 0.054
2025-05-26T11:46:00.000+08:00, 0.715,2025-05-26T11:45:30.152+08:00, 2.192, 1.080,2025-05-26T11:45:11.596+08:00, 2.906, 1.847,2025-05-26T11:45:24.710+08:00,12.820, 1.968,2025-05-26T11:45:24.710+08:00, 0.011, 0.010, 0.025, 0.052, 0.049, 0.063
2025-05-26T11:47:00.000+08:00, 1.069,2025-05-26T11:46:53.336+08:00, 3.816, 1.094,2025-05-26T11:46:12.419+08:00, 4.504, 1.548,2025-05-26T11:46:12.322+08:00, 5.102, 1.828,2025-05-26T11:46:12.322+08:00, 0.010, 0.010, 0.021, 0.114, 0.051, 0.060
2025-05-26T11:48:00.000+08:00, 0.835,2025-05-26T11:47:42.101+08:00, 4.761, 0.851,2025-05-26T11:47:46.115+08:00, 4.854, 1.195,2025-05-26T11:47:57.373+08:00, 6.493, 1.292,2025-05-26T11:47:38.617+08:00, 0.011, 0.013, 0.020, 0.072, 0.060, 0.041
2025-05-26T11:49:00.000+08:00, 0.960,2025-05-26T11:48:28.110+08:00, 3.355, 0.941,2025-05-26T11:48:28.089+08:00, 2.645, 1.642,2025-05-26T11:48:27.953+08:00,19.230, 1.861,2025-05-26T11:48:28.090+08:00, 0.011, 0.008, 0.021, 0.059, 0.053, 0.056
2025-05-26T11:50:00.000+08:00, 1.004,2025-05-26T11:49:24.471+08:00, 8.474, 0.638,2025-05-26T11:49:03.524+08:00, 9.259, 1.858,2025-05-26T11:49:55.128+08:00,15.625, 1.931,2025-05-26T11:49:55.128+08:00, 0.014, 0.017, 0.017, 0.101, 0.064, 0.063
2025-05-26T11:51:00.000+08:00, 0.723,2025-05-26T11:50:45.522+08:00, 7.575, 0.617,2025-05-26T11:50:00.726+08:00,10.000, 1.370,2025-05-26T11:50:09.889+08:00,12.500, 1.483,2025-05-26T11:50:09.889+08:00, 0.012, 0.009, 0.021, 0.064, 0.039, 0.068
2025-05-26T11:52:00.000+08:00, 0.812,2025-05-26T11:51:25.576+08:00, 3.597, 0.821,2025-05-26T11:51:35.406+08:00, 3.968, 1.417,2025-05-26T11:51:04.317+08:00,17.857, 1.514,2025-05-26T11:51:04.317+08:00, 0.014, 0.014, 0.020, 0.055, 0.044, 0.048
2025-05-26T11:53:00.000+08:00, 0.788,2025-05-26T11:52:30.093+08:00, 4.000, 0.831,2025-05-26T11:52:31.700+08:00, 4.424, 1.415,2025-05-26T11:52:28.136+08:00, 5.952, 1.528,2025-05-26T11:52:28.136+08:00, 0.009, 0.011, 0.018, 0.054, 0.062, 0.040
2025-05-26T11:54:00.000+08:00, 0.908,2025-05-26T11:53:29.164+08:00, 3.937, 1.233,2025-05-26T11:53:29.614+08:00, 3.546, 1.642,2025-05-26T11:53:34.608+08:00,12.820, 1.760,2025-05-26T11:53:34.608+08:00, 0.011, 0.018, 0.019, 0.045, 0.049, 0.059
2025-05-26T11:55:00.000+08:00, 0.692,2025-05-26T11:54:59.666+08:00, 4.950, 0.705,2025-05-26T11:54:10.535+08:00, 3.623, 1.291,2025-05-26T11:54:45.799+08:00,16.666, 1.378,2025-05-26T11:54:45.799+08:00, 0.011, 0.013, 0.021, 0.040, 0.040, 0.052
2025-05-26T11:56:00.000+08:00, 0.684,2025-05-26T11:55:01.583+08:00, 3.205, 0.871,2025-05-26T11:55:43.120+08:00, 2.512, 1.290,2025-05-26T11:55:43.119+08:00,12.500, 1.539,2025-05-26T11:55:43.119+08:00, 0.008, 0.007, 0.015, 0.036, 0.047, 0.037
2025-05-26T11:57:00.000+08:00, 0.966,2025-05-26T11:56:13.921+08:00, 4.310, 0.881,2025-05-26T11:56:52.633+08:00, 4.672, 1.366,2025-05-26T11:56:13.980+08:00,12.500, 1.429,2025-05-26T11:56:38.575+08:00, 0.010, 0.010, 0.020, 0.080, 0.061, 0.079
2025-05-26T11:58:00.000+08:00, 0.810,2025-05-26T11:57:22.851+08:00, 3.378, 0.972,2025-05-26T11:57:57.941+08:00, 3.676, 1.582,2025-05-26T11:57:07.694+08:00, 5.050, 1.794,2025-05-26T11:57:25.259+08:00, 0.012, 0.013, 0.018, 0.071, 0.052, 0.069
2025-05-26T11:59:00.000+08:00, 1.212,2025-05-26T11:58:21.381+08:00, 5.319, 0.807,2025-05-26T11:58:57.532+08:00, 4.587, 1.935,2025-05-26T11:58:55.554+08:00, 5.747, 2.090,2025-05-26T11:58:55.554+08:00, 0.012, 0.010, 0.015, 0.128, 0.051, 0.068
Device, Razor
Type, tilt beat
MAC, 170058
Cal Date, 2025-04-09T00:00:00.000+01:00
Man Date, 2022-05-15T00:00:00.000+01:00
H/W, 5.0
Main F/W, 5.3.14
Orient. (g), 0.000,0.000,0.000
Bat,0.00
Time,BaseP,BaseR,Pitch,Roll,dPitch,dRoll,degC
2025-05-26T08:00:01.152+08:00,-0.3264,1.2244,-0.2998,1.2273,0.0267,0.0029,24.01
2025-05-26T08:05:00.000+08:00,-0.3264,1.2244,-0.2987,1.2294,0.0278,0.0049,23.90
2025-05-26T08:10:00.000+08:00,-0.3264,1.2244,-0.2998,1.2292,0.0266,0.0047,24.01
2025-05-26T08:15:00.000+08:00,-0.3264,1.2244,-0.2989,1.2283,0.0275,0.0039,24.01
2025-05-26T08:20:00.000+08:00,-0.3264,1.2244,-0.3000,1.2255,0.0264,0.0011,23.90
2025-05-26T08:25:00.000+08:00,-0.3264,1.2244,-0.2998,1.2276,0.0266,0.0032,24.01
2025-05-26T08:30:00.000+08:00,-0.3264,1.2244,-0.2987,1.2292,0.0278,0.0047,23.90
2025-05-26T08:35:00.000+08:00,-0.3264,1.2244,-0.3005,1.2271,0.0260,0.0027,23.90
2025-05-26T08:40:00.000+08:00,-0.3264,1.2244,-0.2987,1.2285,0.0278,0.0041,23.67
2025-05-26T08:45:00.000+08:00,-0.3264,1.2244,-0.2987,1.2276,0.0278,0.0032,23.67
2025-05-26T08:50:00.000+08:00,-0.3264,1.2244,-0.2993,1.2285,0.0271,0.0041,24.23
2025-05-26T08:55:00.000+08:00,-0.3264,1.2244,-0.2996,1.2271,0.0269,0.0027,23.90
2025-05-26T09:00:01.012+08:00,-0.3264,1.2244,-0.2993,1.2235,0.0271,-0.0009,24.12
2025-05-26T09:05:00.000+08:00,-0.3264,1.2244,-0.2996,1.2285,0.0269,0.0041,24.01
2025-05-26T09:10:00.000+08:00,-0.3264,1.2244,-0.2994,1.2296,0.0271,0.0052,24.01
2025-05-26T09:15:00.000+08:00,-0.3264,1.2244,-0.3005,1.2273,0.0260,0.0029,24.34
2025-05-26T09:20:00.000+08:00,-0.3264,1.2244,-0.2991,1.2285,0.0273,0.0040,24.45
2025-05-26T09:25:00.000+08:00,-0.3264,1.2244,-0.2991,1.2289,0.0273,0.0044,24.12
2025-05-26T09:30:00.000+08:00,-0.3264,1.2244,-0.2991,1.2305,0.0273,0.0060,24.12
2025-05-26T09:35:00.000+08:00,-0.3264,1.2244,-0.2987,1.2298,0.0278,0.0053,25.00
2025-05-26T09:40:00.000+08:00,-0.3264,1.2244,-0.2996,1.2302,0.0269,0.0058,24.23
2025-05-26T09:45:00.000+08:00,-0.3264,1.2244,-0.2991,1.2309,0.0273,0.0064,24.89
2025-05-26T09:50:00.000+08:00,-0.3264,1.2244,-0.2993,1.2304,0.0271,0.0060,24.89
2025-05-26T09:55:00.000+08:00,-0.3264,1.2244,-0.2993,1.2285,0.0271,0.0041,24.89
2025-05-26T10:00:00.000+08:00,-0.3264,1.2244,-0.3022,1.2252,0.0242,0.0008,24.89
2025-05-26T10:05:00.000+08:00,-0.3264,1.2244,-0.2995,1.2310,0.0269,0.0066,24.89
2025-05-26T10:10:00.000+08:00,-0.3264,1.2244,-0.2984,1.2312,0.0280,0.0068,24.89
2025-05-26T10:15:00.000+08:00,-0.3264,1.2244,-0.3000,1.2315,0.0265,0.0070,25.22
2025-05-26T10:20:00.000+08:00,-0.3264,1.2244,-0.2993,1.2324,0.0271,0.0079,24.89
2025-05-26T10:25:00.000+08:00,-0.3264,1.2244,-0.3000,1.2301,0.0265,0.0057,25.55
2025-05-26T10:30:00.000+08:00,-0.3264,1.2244,-0.2997,1.2316,0.0267,0.0072,25.33
2025-05-26T10:35:00.000+08:00,-0.3264,1.2244,-0.2993,1.2316,0.0272,0.0072,25.66
2025-05-26T10:40:00.000+08:00,-0.3264,1.2244,-0.3004,1.2321,0.0260,0.0077,25.66
2025-05-26T10:45:00.000+08:00,-0.3264,1.2244,-0.3004,1.2285,0.0260,0.0041,25.77
2025-05-26T10:50:00.000+08:00,-0.3264,1.2244,-0.2988,1.2336,0.0276,0.0092,25.66
2025-05-26T10:55:00.000+08:00,-0.3264,1.2244,-0.3006,1.2330,0.0258,0.0085,25.77
2025-05-26T11:00:00.000+08:00,-0.3264,1.2244,-0.3004,1.2322,0.0260,0.0078,25.77
2025-05-26T11:05:00.000+08:00,-0.3264,1.2244,-0.3009,1.2312,0.0256,0.0067,25.77
2025-05-26T11:10:00.000+08:00,-0.3264,1.2244,-0.2982,1.2345,0.0283,0.0100,25.88
2025-05-26T11:15:00.000+08:00,-0.3264,1.2244,-0.2986,1.2347,0.0278,0.0103,25.77
2025-05-26T11:20:00.000+08:00,-0.3264,1.2244,-0.2995,1.2338,0.0269,0.0094,26.10
2025-05-26T11:25:00.000+08:00,-0.3264,1.2244,-0.2993,1.2328,0.0272,0.0084,26.10
2025-05-26T11:30:00.000+08:00,-0.3264,1.2244,-0.2997,1.2326,0.0267,0.0082,26.22
2025-05-26T11:35:01.224+08:00,-0.3264,1.2244,-0.2986,1.2355,0.0279,0.0111,26.55
2025-05-26T11:40:00.000+08:00,-0.3264,1.2244,-0.2990,1.2337,0.0274,0.0093,26.44
2025-05-26T11:45:00.000+08:00,-0.3264,1.2244,-0.2997,1.2322,0.0267,0.0077,26.66
2025-05-26T11:50:00.000+08:00,-0.3264,1.2244,-0.2984,1.2349,0.0281,0.0105,26.55
2025-05-26T11:55:00.356+08:00,-0.3264,1.2244,-0.2988,1.2355,0.0276,0.0111,26.66
[EMAIL]
SMTP_SERVER = smtp.163.com
SMTP_PORT = 25
SENDER_EMAIL = jiulingu1986@163.com
SENDER_PASSWORD = VVQ7TFS3ZsGQgC3X
RECIPIENTS = 605292529@qq.com,jiulingu1986@163.com
[REPORTTIME]
EMAIL_TIME = 08:40
TILT_REPORT_TIME = 08:30
VIBRATION_REPORT_TIME = 08:35
\ No newline at end of file
import csv
import os
import time
from datetime import datetime
from datetime import datetime
from ftplib import FTP
import socket
import io
import pandas as pd
from io import BytesIO
import paho.mqtt.client as mqtt
import json
# MQTT服务器地址和端口
broker = "iot.raytue.com"
port = 1883
# 客户端ID
client_id = "S&D2367JBEYPY32&157&23"
userName="raytue"
passWord="P14AX03XD7W9G42Z"
# 发布主题
topic = "/157/D2367JBEYPY32/property/post"
# FTP服务器配置
FTP_SERVER = 'iot.raytue.com'
FTP_USER = 'tsensing'
FTP_PASS = 'tsensing!@#123'
FTP_DIR = '/tilt/170091(TM10)' # FTP服务器上的目标目录,根据实际情况修改
def connect_ftp():
try:
ftp = FTP()
ftp.connect(FTP_SERVER) # 设置连接超时
ftp.login(FTP_USER, FTP_PASS)
#ftp.set_pasv(True)
ftp.cwd(FTP_DIR)
print(f"TM10成功连接 {FTP_SERVER}:{21}")
return ftp
except socket.timeout:
print("TM10连接超时,请检查网络或服务器状态")
except Exception as e:
print(f"TM10连接失败: {str(e)}")
def del_file(list_row):
# print(list_row[10])
number_row= len(list_row)
mqttstr=""
print("TM10列表中有",number_row,"行")
j=10
# if list_row[10][0] == "Time":#有的表格第10行不是数据是表头
# j=11
for i in range(number_row):
if list_row[i][0] == "Time":
j=i+1
break
i=0
for i in range(j,number_row):
#格式化mqtt字符串
mqttstr="[{\"id\":\"tiltData_time\",\"remark\":\"\",\"value\":\"%s\"},{\"id\":\"tiltData_dPitch\",\"remark\":\"\",\"value\":\"%s\"},{\"id\":\"tiltData_dRoll\",\"remark\":\"\",\"value\":\"%s\"}]" % (list_row[i][0] ,list_row[i][5] ,list_row[i][6] )
# print(mqttstr)
# payload = json.dumps(mqttstr)
payload = mqttstr
# 发布消息
result = client.publish(topic, payload)
# 检查消息是否成功发布
status = result[0]
if status == 0:
print(f"TM10Send `{payload}` to topic `{topic}`")
else:
print(f"TM10Failed to send message to topic {topic}")
time.sleep(1)
def monitor_directory(known_files,interval=60):
"""
监控指定目录的新增文件
"""
# known_files=[]#首次全部传输完成后注释掉
while True:
ftp = connect_ftp()
ftp.cwd(FTP_DIR)
# 获取当前文件列表
try:
#ftp.set_pasv(True)
current_files = ftp.nlst()#读文件列表
print('TM10当前目录------------>:')
# print(current_files)
# 找出新增文件
#new_files = current_files - known_files
new_files = [item for item in current_files if item not in known_files]
print('TM10新增文件--------->:')
print(new_files)
#new_files = ['44444444.csv']
if new_files:
print(f"[{datetime.now()}] 发现 {len(new_files)} 个新文件:")
for filename in new_files:
#filepath = os.path.join(directory, filename)
print(f"TM10分析文件: {filename}")
#analyze_file(filepath)
for i in range(10): # 从0到4 防止掉线读不出来
# 使用BytesIO作为文件缓冲区
try:
print(f"TM10第{i}次读取")
ftp = connect_ftp()
ftp.cwd(FTP_DIR)
file_data = io.BytesIO()
ftp.retrbinary(f"RETR {filename}", file_data.write)
file_data.seek(0)
csv_data = file_data.read().decode('utf-8')
csv_reader = csv.reader(io.StringIO(csv_data))
#csv_reader = csv.reader(csv_data)
list_row = list(csv_reader)
del_file(list_row)#处理数据
# for row in csv_reader:
# del_file(row)#处理数据
break
except Exception as e:
print(f"TM10读取文件{filename}出错: {e}")
if i == 9:
i = 0
continue
print("--------------------------------全部文件发送完毕------------------------------------------")#首次全部传输完成后,注释掉
#return#首次全部传输完成后,注释掉
# 打印文件内容
#content = file_data.read().decode('utf-8')
#print(content)
# 更新已知文件列表
known_files = current_files
ftp.quit()
except Exception as e:
print(f"TM10读取当前目录出错: {e}")
# 等待下次检查
time.sleep(interval)
def analyze_file(filepath):
"""
分析文件内容
:param filepath: 文件路径
"""
try:
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()
# 这里可以添加你的分析逻辑
print(f"TM10文件大小: {len(content)} 字节")
#print(f"首100字符: {content[:100]}...")
except Exception as e:
print(f"TM10读取文件 {filepath} 出错: {str(e)}")
# 连接回调函数
def on_connect1(client, userdata, flags, reason_code, properties):
if reason_code == 0:
print("TM10Connected to MQTT Broker!")
else:
print(f"TM10Failed to connect, return code {reason_code}")
if __name__ == "__main__":
# 创建MQTT客户端实例
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id)
#client = mqtt.Client(client_id)
client.on_connect = on_connect1
client.username_pw_set(userName, passWord)
# 连接到MQTT服务器
client.connect(broker, port, 60)
# 开始循环
client.loop_start()
# 初始文件列表
while True:
try:
ftp = connect_ftp()
ftp.cwd(FTP_DIR)
#ftp.set_pasv(True)
known_files = ftp.nlst()
print('TM10初始目录:')
#print(known_files)
ftp.quit()
monitor_directory(known_files,10)
except Exception as e:
print(f"TM10读取初始目录出错: {e}")
time.sleep(5)
import csv
import os
import time
from datetime import datetime
from ftplib import FTP
import socket
import io
import pandas as pd
from io import BytesIO
import paho.mqtt.client as mqtt
import json
# MQTT服务器地址和端口
broker = "iot.raytue.com"
port = 1883
# 客户端ID
client_id = "S&D2367JBEYPY32&157&23"
userName="raytue"
passWord="P14AX03XD7W9G42Z"
# 发布主题
topic = "/157/D2367JBEYPY32/property/post"
# FTP服务器配置
FTP_SERVER = 'iot.raytue.com'
FTP_USER = 'tsensing'
FTP_PASS = 'tsensing!@#123'
FTP_DIR = '/tilt/170091(TM10)' # FTP服务器上的目标目录,根据实际情况修改
def connect_ftp():
try:
ftp = FTP()
ftp.connect(FTP_SERVER) # 设置连接超时
ftp.login(FTP_USER, FTP_PASS)
#ftp.set_pasv(True)
ftp.cwd(FTP_DIR)
print(f"TM10成功连接 {FTP_SERVER}:{21}")
return ftp
except socket.timeout:
print("TM10连接超时,请检查网络或服务器状态")
except Exception as e:
print(f"TM10连接失败: {str(e)}")
def del_file(list_row):
# print(list_row[10])
number_row= len(list_row)
mqttstr=""
print("TM10列表中有",number_row,"行数据需处理")
j=10
# if list_row[10][0] == "Time":#有的表格第10行不是数据是表头
# j=11
for i in range(number_row):
if list_row[i][0] == "Time":
j=i+1
break
i=0
for i in range(j,number_row):
#格式化mqtt字符串
if(len(list_row[i])== 8):#防止最后一行有数据缺失!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
iso_str = list_row[i][0]
# 解析字符串,注意要指定时区信息
dt = datetime.fromisoformat(iso_str)
# 格式化为所需的格式
formatted_str = dt.strftime("%Y-%m-%d %H:%M:%S")
mqttstr="[{\"id\":\"tiltData_time\",\"remark\":\"\",\"value\":\"%s\",\"ts\":\"%s\"},\
{\"id\":\"tiltData_dPitch\",\"remark\":\"\",\"value\":\"%s\",\"ts\":\"%s\"},\
{\"id\":\"tiltData_dRoll\",\"remark\":\"\",\"value\":\"%s\",\"ts\":\"%s\"}]" \
% (list_row[i][0], formatted_str ,list_row[i][5], formatted_str ,list_row[i][6], formatted_str)
# print(mqttstr)
# payload = json.dumps(mqttstr)
payload = mqttstr
# 发布消息
result = client.publish(topic, payload)
# 检查消息是否成功发布
status = result[0]
if status == 0:
print(f"TM10Send `{payload}` to topic `{topic}`")
else:
print(f"TM10Failed to send message to topic {topic}")
time.sleep(0.05)#100ms传一次
def monitor_directory(known_files,interval=60):
"""
监控指定目录的新增文件
"""
# known_files=[]#首次全部传输完成后注释掉!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
while True:
ftp = connect_ftp()
ftp.cwd(FTP_DIR)
# 获取当前文件列表
try:
#ftp.set_pasv(True)
current_files = ftp.nlst()#读文件列表
print('获取TM10当前目录------------>:')
# print(current_files)
# 找出新增文件
#new_files = current_files - known_files
new_files = [item for item in current_files if item not in known_files]
print('获取TM10新增文件--------->:')
print(new_files)
#new_files = ['44444444.csv']
if new_files:
print(f"[{datetime.now()}] 发现 {len(new_files)} 个新文件:")
for filename in new_files:
#filepath = os.path.join(directory, filename)
print(f"TM10分析文件: {filename}")
#analyze_file(filepath)
for i in range(10): # 从0到4 防止掉线读不出来
# 使用BytesIO作为文件缓冲区
try:
print(f"TM10第{i}次读取")
ftp = connect_ftp()
ftp.cwd(FTP_DIR)
file_data = io.BytesIO()
ftp.retrbinary(f"RETR {filename}", file_data.write)
file_data.seek(0)
csv_data = file_data.read().decode('utf-8')
csv_reader = csv.reader((io.StringIO(csv_data).getvalue()).splitlines(),delimiter=',')
#csv_reader = csv.reader(csv_data)
list_row = list(csv_reader)
del_file(list_row)#处理数据
# for row in csv_reader:
# del_file(row)#处理数据
break
except Exception as e:
print(f"TM10读取文件{filename}出错: {e}")
# if i == 9:
# i = 0
continue
print("--------------------------------全部文件发送完毕------------------------------------------")#首次全部传输完成后,注释掉
#return#首次全部传输完成后,注释掉
# 打印文件内容
#content = file_data.read().decode('utf-8')
#print(content)
# 更新已知文件列表
known_files = current_files
ftp.quit()
except Exception as e:
print(f"TM10读取当前目录出错: {e}")
# 等待下次检查
time.sleep(interval)
def analyze_file(filepath):
"""
分析文件内容
:param filepath: 文件路径
"""
try:
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()
# 这里可以添加你的分析逻辑
print(f"TM10文件大小: {len(content)} 字节")
#print(f"首100字符: {content[:100]}...")
except Exception as e:
print(f"TM10读取文件 {filepath} 出错: {str(e)}")
# 连接回调函数
def on_connect1(client, userdata, flags, reason_code, properties):
if reason_code == 0:
print("TM10Connected to MQTT Broker!")
else:
print(f"TM10Failed to connect, return code {reason_code}")
if __name__ == "__main__":
# 创建MQTT客户端实例
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id)
#client = mqtt.Client(client_id)
client.on_connect = on_connect1
client.username_pw_set(userName, passWord)
# 连接到MQTT服务器
client.connect(broker, port, 60)
# 开始循环
client.loop_start()
# 初始文件列表
while True:
try:
ftp = connect_ftp()
ftp.cwd(FTP_DIR)
#ftp.set_pasv(True)
known_files = ftp.nlst()
print('获取TM10初始目录:')
#print(known_files)
ftp.quit()
monitor_directory(known_files,10)
except Exception as e:
print(f"TM10获取初始目录出错: {e}")
time.sleep(5)
import csv
import os
import time
from datetime import datetime
from datetime import datetime
from ftplib import FTP
import socket
import io
import pandas as pd
from io import BytesIO
import paho.mqtt.client as mqtt
import json
# MQTT服务器地址和端口
broker = "iot.raytue.com"
port = 1883
# 客户端ID
client_id = "S&D23AFZM72Q620&157&23"
userName="raytue"
passWord="P14AX03XD7W9G42Z"
# 发布主题
topic = "/157/D23AFZM72Q620/property/post"
# FTP服务器配置
FTP_SERVER = 'iot.raytue.com'
FTP_USER = 'tsensing'
FTP_PASS = 'tsensing!@#123'
FTP_DIR = '/tilt/170097(TM10A)/' # FTP服务器上的目标目录,根据实际情况修改
def connect_ftp():
try:
ftp = FTP()
ftp.connect(FTP_SERVER) # 设置连接超时
ftp.login(FTP_USER, FTP_PASS)
#ftp.set_pasv(True)
ftp.cwd(FTP_DIR)
print(f"TM10A成功连接 {FTP_SERVER}:{21}")
return ftp
except socket.timeout:
print("TM10A连接超时,请检查网络或服务器状态")
except Exception as e:
print(f"TM10A连接失败: {str(e)}")
def del_file(list_row):
# print(list_row[10])
number_row= len(list_row)
mqttstr=""
print("TM10A列表中有",number_row,"行")
j=10
# if list_row[10][0] == "Time":#有的表格第10行不是数据是表头
# j=11
for i in range(number_row):
if list_row[i][0] == "Time":
j=i+1
break
i=0
for i in range(j,number_row):
#格式化mqtt字符串
mqttstr="[{\"id\":\"tiltData_time\",\"remark\":\"\",\"value\":\"%s\"},{\"id\":\"tiltData_dPitch\",\"remark\":\"\",\"value\":\"%s\"},{\"id\":\"tiltData_dRoll\",\"remark\":\"\",\"value\":\"%s\"}]" % (list_row[i][0] ,list_row[i][5] ,list_row[i][6] )
# print(mqttstr)
# payload = json.dumps(mqttstr)
payload = mqttstr
# 发布消息
result = client.publish(topic, payload)
# 检查消息是否成功发布
status = result[0]
if status == 0:
print(f"TM10ASend `{payload}` to topic `{topic}`")
else:
print(f"TM10AFailed to send message to topic {topic}")
time.sleep(1)
def monitor_directory(known_files,interval=60):
"""
监控指定目录的新增文件
"""
# known_files=[]#首次全部传输完成后注释掉
while True:
ftp = connect_ftp()
ftp.cwd(FTP_DIR)
# 获取当前文件列表
try:
#ftp.set_pasv(True)
current_files = ftp.nlst()#读文件列表
print('TM10A当前目录------------>:')
# print(current_files)
# 找出新增文件
#new_files = current_files - known_files
new_files = [item for item in current_files if item not in known_files]
print('TM10A新增文件--------->:')
print(new_files)
#new_files = ['44444444.csv']
if new_files:
print(f"[{datetime.now()}] 发现 {len(new_files)} 个新文件:")
for filename in new_files:
#filepath = os.path.join(directory, filename)
print(f"TM10A分析文件: {filename}")
#analyze_file(filepath)
for i in range(10): # 从0到4 防止掉线读不出来
# 使用BytesIO作为文件缓冲区
try:
print(f"TM10B第{i}次读取")
ftp = connect_ftp()
ftp.cwd(FTP_DIR)
file_data = io.BytesIO()
ftp.retrbinary(f"RETR {filename}", file_data.write)
file_data.seek(0)
csv_data = file_data.read().decode('utf-8')
csv_reader = csv.reader((io.StringIO(csv_data).getvalue()).splitlines(),delimiter=',')
#csv_reader = csv.reader(csv_data)
list_row = list(csv_reader)
del_file(list_row)#处理数据
# for row in csv_reader:
# del_file(row)#处理数据
break
except Exception as e:
print(f"TM10A读取文件{filename}出错: {e}")
if i == 9:
i = 0
continue
print("--------------------------------全部文件发送完毕------------------------------------------")#首次全部传输完成后,注释掉
#return#首次全部传输完成后,注释掉
# 打印文件内容
#content = file_data.read().decode('utf-8')
#print(content)
# 更新已知文件列表
known_files = current_files
ftp.quit()
except Exception as e:
print(f"TM10A读取当前目录出错: {e}")
# 等待下次检查
time.sleep(interval)
def analyze_file(filepath):
"""
分析文件内容
:param filepath: 文件路径
"""
try:
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()
# 这里可以添加你的分析逻辑
print(f"TM10A文件大小: {len(content)} 字节")
#print(f"首100字符: {content[:100]}...")
except Exception as e:
print(f"TM10A读取文件 {filepath} 出错: {str(e)}")
# 连接回调函数
def on_connect1(client, userdata, flags, reason_code, properties):
if reason_code == 0:
print("TM10AConnected to MQTT Broker!")
else:
print(f"TM10AFailed to connect, return code {reason_code}")
if __name__ == "__main__":
# 创建MQTT客户端实例
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id)
#client = mqtt.Client(client_id)
client.on_connect = on_connect1
client.username_pw_set(userName, passWord)
# 连接到MQTT服务器
client.connect(broker, port, 60)
# 开始循环
client.loop_start()
# 初始文件列表
while True:
try:
ftp = connect_ftp()
ftp.cwd(FTP_DIR)
#ftp.set_pasv(True)
known_files = ftp.nlst()
print('TM10A初始目录:')
#print(known_files)
ftp.quit()
monitor_directory(known_files,10)
except Exception as e:
print(f"TM10A读取初始目录出错: {e}")
time.sleep(5)
import csv
import os
import time
from datetime import datetime
from ftplib import FTP
import socket
import io
import pandas as pd
from io import BytesIO
import paho.mqtt.client as mqtt
import json
# MQTT服务器地址和端口
broker = "iot.raytue.com"
port = 1883
# 客户端ID
client_id = "S&D23AFZM72Q620&157&23"
userName="raytue"
passWord="P14AX03XD7W9G42Z"
# 发布主题
topic = "/157/D23AFZM72Q620/property/post"
# FTP服务器配置
FTP_SERVER = 'iot.raytue.com'
FTP_USER = 'tsensing'
FTP_PASS = 'tsensing!@#123'
FTP_DIR = '/tilt/170097(TM10A)/' # FTP服务器上的目标目录,根据实际情况修改
def connect_ftp():
try:
ftp = FTP()
ftp.connect(FTP_SERVER) # 设置连接超时
ftp.login(FTP_USER, FTP_PASS)
#ftp.set_pasv(True)
ftp.cwd(FTP_DIR)
print(f"TM10A成功连接 {FTP_SERVER}:{21}")
return ftp
except socket.timeout:
print("TM10A连接超时,请检查网络或服务器状态")
except Exception as e:
print(f"TM10A连接失败: {str(e)}")
def del_file(list_row):
# print(list_row[10])
number_row= len(list_row)
mqttstr=""
print("TM10A列表中有",number_row,"行数据需处理")
j=10
# if list_row[10][0] == "Time":#有的表格第10行不是数据是表头
# j=11
for i in range(number_row):
if list_row[i][0] == "Time":
j=i+1
break
i=0
for i in range(j,number_row):
#格式化mqtt字符串
if(len(list_row[i])== 8):#防止最后一行有数据缺失!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
iso_str = list_row[i][0]
# 解析字符串,注意要指定时区信息
dt = datetime.fromisoformat(iso_str)
# 格式化为所需的格式
formatted_str = dt.strftime("%Y-%m-%d %H:%M:%S")
mqttstr="[{\"id\":\"tiltData_time\",\"remark\":\"\",\"value\":\"%s\",\"ts\":\"%s\"},\
{\"id\":\"tiltData_dPitch\",\"remark\":\"\",\"value\":\"%s\",\"ts\":\"%s\"},\
{\"id\":\"tiltData_dRoll\",\"remark\":\"\",\"value\":\"%s\",\"ts\":\"%s\"}]" \
% (list_row[i][0], formatted_str ,list_row[i][5], formatted_str ,list_row[i][6], formatted_str)
# print(mqttstr)
# payload = json.dumps(mqttstr)
payload = mqttstr
# 发布消息
result = client.publish(topic, payload)
# 检查消息是否成功发布
status = result[0]
if status == 0:
print(f"TM10ASend `{payload}` to topic `{topic}`")
else:
print(f"TM10AFailed to send message to topic {topic}")
time.sleep(0.05)#100ms传一次
def monitor_directory(known_files,interval=60):
"""
监控指定目录的新增文件
"""
# known_files=[]#首次全部传输完成后注释掉!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
while True:
ftp = connect_ftp()
ftp.cwd(FTP_DIR)
# 获取当前文件列表
try:
#ftp.set_pasv(True)
current_files = ftp.nlst()#读文件列表
print('获取TM10A当前目录------------>:')
# print(current_files)
# 找出新增文件
#new_files = current_files - known_files
new_files = [item for item in current_files if item not in known_files]
print('获取TM10A新增文件--------->:')
print(new_files)
#new_files = ['44444444.csv']
if new_files:
print(f"[{datetime.now()}] 发现 {len(new_files)} 个新文件:")
for filename in new_files:
#filepath = os.path.join(directory, filename)
print(f"TM10A分析文件: {filename}")
#analyze_file(filepath)
for i in range(10): # 从0到4 防止掉线读不出来
# 使用BytesIO作为文件缓冲区
try:
print(f"TM10A第{i}次读取")
ftp = connect_ftp()
ftp.cwd(FTP_DIR)
file_data = io.BytesIO()
ftp.retrbinary(f"RETR {filename}", file_data.write)
file_data.seek(0)
csv_data = file_data.read().decode('utf-8')
csv_reader = csv.reader((io.StringIO(csv_data).getvalue()).splitlines(),delimiter=',')
#csv_reader = csv.reader(csv_data)
list_row = list(csv_reader)
del_file(list_row)#处理数据
# for row in csv_reader:
# del_file(row)#处理数据
break
except Exception as e:
print(f"TM10A读取文件{filename}出错: {e}")
# if i == 9:
# i = 0
continue
print("--------------------------------全部文件发送完毕------------------------------------------")#首次全部传输完成后,注释掉
#return#首次全部传输完成后,注释掉
# 打印文件内容
#content = file_data.read().decode('utf-8')
#print(content)
# 更新已知文件列表
known_files = current_files
ftp.quit()
except Exception as e:
print(f"TM10A读取当前目录出错: {e}")
# 等待下次检查
time.sleep(interval)
def analyze_file(filepath):
"""
分析文件内容
:param filepath: 文件路径
"""
try:
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()
# 这里可以添加你的分析逻辑
print(f"TM10A文件大小: {len(content)} 字节")
#print(f"首100字符: {content[:100]}...")
except Exception as e:
print(f"TM10A读取文件 {filepath} 出错: {str(e)}")
# 连接回调函数
def on_connect1(client, userdata, flags, reason_code, properties):
if reason_code == 0:
print("TM10AConnected to MQTT Broker!")
else:
print(f"TM10AFailed to connect, return code {reason_code}")
if __name__ == "__main__":
# 创建MQTT客户端实例
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id)
#client = mqtt.Client(client_id)
client.on_connect = on_connect1
client.username_pw_set(userName, passWord)
# 连接到MQTT服务器
client.connect(broker, port, 60)
# 开始循环
client.loop_start()
# 初始文件列表
while True:
try:
ftp = connect_ftp()
ftp.cwd(FTP_DIR)
#ftp.set_pasv(True)
known_files = ftp.nlst()
print('获取TM10A初始目录:')
#print(known_files)
ftp.quit()
monitor_directory(known_files,10)
except Exception as e:
print(f"TM10A获取初始目录出错: {e}")
time.sleep(5)
import csv
import os
import time
from datetime import datetime
from ftplib import FTP
import socket
import io
import pandas as pd
from io import BytesIO
import paho.mqtt.client as mqtt
import json
# MQTT服务器地址和端口
broker = "iot.raytue.com"
port = 1883
# 客户端ID
client_id = "S&D2368757I1Y4G&157&23"
userName="raytue"
passWord="P14AX03XD7W9G42Z"
# 发布主题
topic = "/157/D2368757I1Y4G/property/post"
# FTP服务器配置
FTP_SERVER = 'iot.raytue.com'
FTP_USER = 'tsensing'
FTP_PASS = 'tsensing!@#123'
FTP_DIR = '/tilt/170098(TM10B)/' # FTP服务器上的目标目录,根据实际情况修改
def connect_ftp():
try:
ftp = FTP()
ftp.connect(FTP_SERVER) # 设置连接超时
ftp.login(FTP_USER, FTP_PASS)
#ftp.set_pasv(True)
ftp.cwd(FTP_DIR)
print(f"TM10B成功连接 {FTP_SERVER}:{21}")
return ftp
except socket.timeout:
print("TM10B连接超时,请检查网络或服务器状态")
except Exception as e:
print(f"TM10B连接失败: {str(e)}")
def del_file(list_row):
# print(list_row[10])
number_row= len(list_row)
mqttstr=""
print("TM10B列表中有",number_row,"行数据需处理")
j=10
# if list_row[10][0] == "Time":#有的表格第10行不是数据是表头
# j=11
for i in range(number_row):
if list_row[i][0] == "Time":
j=i+1
break
i=0
for i in range(j,number_row):
#格式化mqtt字符串
if(len(list_row[i])== 8):#防止最后一行有数据缺失!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
iso_str = list_row[i][0]
# 解析字符串,注意要指定时区信息
dt = datetime.fromisoformat(iso_str)
# 格式化为所需的格式
formatted_str = dt.strftime("%Y-%m-%d %H:%M:%S")
mqttstr="[{\"id\":\"tiltData_time\",\"remark\":\"\",\"value\":\"%s\",\"ts\":\"%s\"},\
{\"id\":\"tiltData_dPitch\",\"remark\":\"\",\"value\":\"%s\",\"ts\":\"%s\"},\
{\"id\":\"tiltData_dRoll\",\"remark\":\"\",\"value\":\"%s\",\"ts\":\"%s\"}]" \
% (list_row[i][0], formatted_str ,list_row[i][5], formatted_str ,list_row[i][6], formatted_str)
# print(mqttstr)
# payload = json.dumps(mqttstr)
payload = mqttstr
# 发布消息
result = client.publish(topic, payload)
# 检查消息是否成功发布
status = result[0]
if status == 0:
print(f"TM10BSend `{payload}` to topic `{topic}`")
else:
print(f"TM10BFailed to send message to topic {topic}")
time.sleep(0.05)#100ms传一次
def monitor_directory(known_files,interval=60):
"""
监控指定目录的新增文件
"""
# known_files=[]#首次全部传输完成后注释掉!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
while True:
ftp = connect_ftp()
ftp.cwd(FTP_DIR)
# 获取当前文件列表
try:
#ftp.set_pasv(True)
current_files = ftp.nlst()#读文件列表
print('获取TM10B当前目录------------>:')
# print(current_files)
# 找出新增文件
#new_files = current_files - known_files
new_files = [item for item in current_files if item not in known_files]
print('获取TM10B新增文件--------->:')
print(new_files)
#new_files = ['44444444.csv']
if new_files:
print(f"[{datetime.now()}] 发现 {len(new_files)} 个新文件:")
for filename in new_files:
#filepath = os.path.join(directory, filename)
print(f"TM10B分析文件: {filename}")
#analyze_file(filepath)
for i in range(10): # 从0到4 防止掉线读不出来
# 使用BytesIO作为文件缓冲区
try:
print(f"TM10B第{i}次读取")
ftp = connect_ftp()
ftp.cwd(FTP_DIR)
file_data = io.BytesIO()
ftp.retrbinary(f"RETR {filename}", file_data.write)
file_data.seek(0)
csv_data = file_data.read().decode('utf-8')
csv_reader = csv.reader((io.StringIO(csv_data).getvalue()).splitlines(),delimiter=',')
#csv_reader = csv.reader(csv_data)
list_row = list(csv_reader)
del_file(list_row)#处理数据
# for row in csv_reader:
# del_file(row)#处理数据
break
except Exception as e:
print(f"TM10B读取文件{filename}出错: {e}")
# if i == 9:
# i = 0
continue
print("--------------------------------全部文件发送完毕------------------------------------------")#首次全部传输完成后,注释掉
#return#首次全部传输完成后,注释掉
# 打印文件内容
#content = file_data.read().decode('utf-8')
#print(content)
# 更新已知文件列表
known_files = current_files
ftp.quit()
except Exception as e:
print(f"TM10B读取当前目录出错: {e}")
# 等待下次检查
time.sleep(interval)
def analyze_file(filepath):
"""
分析文件内容
:param filepath: 文件路径
"""
try:
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()
# 这里可以添加你的分析逻辑
print(f"TM10B文件大小: {len(content)} 字节")
#print(f"首100字符: {content[:100]}...")
except Exception as e:
print(f"TM10B读取文件 {filepath} 出错: {str(e)}")
# 连接回调函数
def on_connect1(client, userdata, flags, reason_code, properties):
if reason_code == 0:
print("TM10BConnected to MQTT Broker!")
else:
print(f"TM10BFailed to connect, return code {reason_code}")
if __name__ == "__main__":
# 创建MQTT客户端实例
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id)
#client = mqtt.Client(client_id)
client.on_connect = on_connect1
client.username_pw_set(userName, passWord)
# 连接到MQTT服务器
client.connect(broker, port, 60)
# 开始循环
client.loop_start()
# 初始文件列表
while True:
try:
ftp = connect_ftp()
ftp.cwd(FTP_DIR)
#ftp.set_pasv(True)
known_files = ftp.nlst()
print('获取TM10B初始目录:')
#print(known_files)
ftp.quit()
monitor_directory(known_files,10)
except Exception as e:
print(f"TM10B获取初始目录出错: {e}")
time.sleep(5)
import csv
import os
import time
from datetime import datetime
from datetime import datetime
from ftplib import FTP
import socket
import io
import pandas as pd
from io import BytesIO
import paho.mqtt.client as mqtt
import json
# MQTT服务器地址和端口
broker = "iot.raytue.com"
port = 1883
# 客户端ID
client_id = "S&D23ANR8041JQI&157&23"
userName="raytue"
passWord="P14AX03XD7W9G42Z"
# 发布主题
topic = "/157/D23ANR8041JQI/property/post"
# FTP服务器配置
FTP_SERVER = 'iot.raytue.com'
FTP_USER = 'tsensing'
FTP_PASS = 'tsensing!@#123'
FTP_DIR = '/tilt/170058(TM9)/' # FTP服务器上的目标目录,根据实际情况修改
def connect_ftp():
try:
ftp = FTP()
ftp.connect(FTP_SERVER) # 设置连接超时
ftp.login(FTP_USER, FTP_PASS)
#ftp.set_pasv(True)
ftp.cwd(FTP_DIR)
print(f"TM9成功连接 {FTP_SERVER}:{21}")
return ftp
except socket.timeout:
print("TM9连接超时,请检查网络或服务器状态")
except Exception as e:
print(f"TM9连接失败: {str(e)}")
def del_file(list_row):
# print(list_row[10])
number_row= len(list_row)
mqttstr=""
print("TM9列表中有",number_row,"行")
j=10
# if list_row[10][0] == "Time":#有的表格第10行不是数据是表头
# j=11
for i in range(number_row):
if list_row[i][0] == "Time":
j=i+1
break
i=0
for i in range(j,number_row):
#格式化mqtt字符串
mqttstr="[{\"id\":\"tiltData_time\",\"remark\":\"\",\"value\":\"%s\"},{\"id\":\"tiltData_dPitch\",\"remark\":\"\",\"value\":\"%s\"},{\"id\":\"tiltData_dRoll\",\"remark\":\"\",\"value\":\"%s\"}]" % (list_row[i][0] ,list_row[i][5] ,list_row[i][6] )
# print(mqttstr)
# payload = json.dumps(mqttstr)
payload = mqttstr
# 发布消息
result = client.publish(topic, payload)
# 检查消息是否成功发布
status = result[0]
if status == 0:
print(f"TM9Send `{payload}` to topic `{topic}`")
else:
print(f"TM9Failed to send message to topic {topic}")
time.sleep(1)
def monitor_directory(known_files,interval=60):
"""
监控指定目录的新增文件
"""
#known_files=[]#首次全部传输完成后注释掉
while True:
ftp = connect_ftp()
ftp.cwd(FTP_DIR)
# 获取当前文件列表
try:
#ftp.set_pasv(True)
current_files = ftp.nlst()#读文件列表
print('TM9当前目录------------>:')
# print(current_files)
# 找出新增文件
#new_files = current_files - known_files
new_files = [item for item in current_files if item not in known_files]
print('TM9新增文件--------->:')
print(new_files)
#new_files = ['44444444.csv']
if new_files:
print(f"[{datetime.now()}] 发现 {len(new_files)} 个新文件:")
for filename in new_files:
#filepath = os.path.join(directory, filename)
print(f"TM9分析文件: {filename}")
#analyze_file(filepath)
for i in range(10): # 从0到4 防止掉线读不出来
# 使用BytesIO作为文件缓冲区
try:
print(f"TM9第{i}次读取")
ftp = connect_ftp()
ftp.cwd(FTP_DIR)
file_data = io.BytesIO()
ftp.retrbinary(f"RETR {filename}", file_data.write)
file_data.seek(0)
csv_data = file_data.read().decode('utf-8')
csv_reader = csv.reader(io.StringIO(csv_data))
#csv_reader = csv.reader(csv_data)
list_row = list(csv_reader)
del_file(list_row)#处理数据
# for row in csv_reader:
# del_file(row)#处理数据
break
except Exception as e:
print(f"TM9读取文件{filename}出错: {e}")
if i == 9:
i = 0
continue
print("--------------------------------全部文件发送完毕------------------------------------------")#首次全部传输完成后,注释掉
#return#首次全部传输完成后,注释掉
# 打印文件内容
#content = file_data.read().decode('utf-8')
#print(content)
# 更新已知文件列表
known_files = current_files
ftp.quit()
except Exception as e:
print(f"TM9读取当前目录出错: {e}")
# 等待下次检查
time.sleep(interval)
def analyze_file(filepath):
"""
分析文件内容
:param filepath: 文件路径
"""
try:
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()
# 这里可以添加你的分析逻辑
print(f"TM9文件大小: {len(content)} 字节")
#print(f"首100字符: {content[:100]}...")
except Exception as e:
print(f"TM9读取文件 {filepath} 出错: {str(e)}")
# 连接回调函数
def on_connect1(client, userdata, flags, reason_code, properties):
if reason_code == 0:
print("TM9Connected to MQTT Broker!")
else:
print(f"TM9Failed to connect, return code {reason_code}")
if __name__ == "__main__":
# 创建MQTT客户端实例
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id)
#client = mqtt.Client(client_id)
client.on_connect = on_connect1
client.username_pw_set(userName, passWord)
# 连接到MQTT服务器
client.connect(broker, port, 60)
# 开始循环
client.loop_start()
# 初始文件列表
while True:
try:
ftp = connect_ftp()
ftp.cwd(FTP_DIR)
#ftp.set_pasv(True)
known_files = ftp.nlst()
print('TM9初始目录:')
#print(known_files)
ftp.quit()
monitor_directory(known_files,10)
except Exception as e:
print(f"TM9读取初始目录出错: {e}")
time.sleep(5)
import csv
import os
import time
from datetime import datetime
from ftplib import FTP
import socket
import io
import pandas as pd
from io import BytesIO
import paho.mqtt.client as mqtt
import json
# MQTT服务器地址和端口
broker = "iot.raytue.com"
port = 1883
# 客户端ID
client_id = "S&D23ANR8041JQI&157&23"
userName="raytue"
passWord="P14AX03XD7W9G42Z"
# 发布主题
topic = "/157/D23ANR8041JQI/property/post"
# FTP服务器配置
FTP_SERVER = 'iot.raytue.com'
FTP_USER = 'tsensing'
FTP_PASS = 'tsensing!@#123'
FTP_DIR = '/tilt/170058(TM9)/' # FTP服务器上的目标目录,根据实际情况修改
def connect_ftp():
try:
ftp = FTP()
ftp.connect(FTP_SERVER) # 设置连接超时
ftp.login(FTP_USER, FTP_PASS)
#ftp.set_pasv(True)
ftp.cwd(FTP_DIR)
print(f"TM9成功连接 {FTP_SERVER}:{21}")
return ftp
except socket.timeout:
print("TM9连接超时,请检查网络或服务器状态")
except Exception as e:
print(f"TM9连接失败: {str(e)}")
def del_file(list_row):
# print(list_row[10])
number_row= len(list_row)
mqttstr=""
print("TM9列表中有",number_row,"行数据需处理")
j=10
# if list_row[10][0] == "Time":#有的表格第10行不是数据是表头
# j=11
for i in range(number_row):
if list_row[i][0] == "Time":
j=i+1
break
i=0
for i in range(j,number_row):
#格式化mqtt字符串
if(len(list_row[i])== 8):#防止最后一行有数据缺失!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
iso_str = list_row[i][0]
# 解析字符串,注意要指定时区信息
dt = datetime.fromisoformat(iso_str)
# 格式化为所需的格式
formatted_str = dt.strftime("%Y-%m-%d %H:%M:%S")
mqttstr="[{\"id\":\"tiltData_time\",\"remark\":\"\",\"value\":\"%s\",\"ts\":\"%s\"},\
{\"id\":\"tiltData_dPitch\",\"remark\":\"\",\"value\":\"%s\",\"ts\":\"%s\"},\
{\"id\":\"tiltData_dRoll\",\"remark\":\"\",\"value\":\"%s\",\"ts\":\"%s\"}]" \
% (list_row[i][0], formatted_str ,list_row[i][5], formatted_str ,list_row[i][6], formatted_str)
# print(mqttstr)
# payload = json.dumps(mqttstr)
payload = mqttstr
# 发布消息
result = client.publish(topic, payload)
# 检查消息是否成功发布
status = result[0]
if status == 0:
print(f"TM9Send `{payload}` to topic `{topic}`")
else:
print(f"TM9Failed to send message to topic {topic}")
time.sleep(0.05)#100ms传一次
def monitor_directory(known_files,interval=60):
"""
监控指定目录的新增文件
"""
# known_files=[]#首次全部传输完成后注释掉!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
while True:
ftp = connect_ftp()
ftp.cwd(FTP_DIR)
# 获取当前文件列表
try:
#ftp.set_pasv(True)
current_files = ftp.nlst()#读文件列表
print('获取TM9当前目录------------>:')
# print(current_files)
# 找出新增文件
#new_files = current_files - known_files
new_files = [item for item in current_files if item not in known_files]
print('获取TM9新增文件--------->:')
print(new_files)
#new_files = ['44444444.csv']
if new_files:
print(f"[{datetime.now()}] 发现 {len(new_files)} 个新文件:")
for filename in new_files:
#filepath = os.path.join(directory, filename)
print(f"TM9分析文件: {filename}")
#analyze_file(filepath)
for i in range(10): # 从0到4 防止掉线读不出来
# 使用BytesIO作为文件缓冲区
try:
print(f"TM9第{i}次读取")
ftp = connect_ftp()
ftp.cwd(FTP_DIR)
file_data = io.BytesIO()
ftp.retrbinary(f"RETR {filename}", file_data.write)
file_data.seek(0)
csv_data = file_data.read().decode('utf-8')
csv_reader = csv.reader((io.StringIO(csv_data).getvalue()).splitlines(),delimiter=',')
#csv_reader = csv.reader(csv_data)
list_row = list(csv_reader)
del_file(list_row)#处理数据
# for row in csv_reader:
# del_file(row)#处理数据
break
except Exception as e:
print(f"TM9读取文件{filename}出错: {e}")
# if i == 9:
# i = 0
continue
print("--------------------------------全部文件发送完毕------------------------------------------")#首次全部传输完成后,注释掉
#return#首次全部传输完成后,注释掉
# 打印文件内容
#content = file_data.read().decode('utf-8')
#print(content)
# 更新已知文件列表
known_files = current_files
ftp.quit()
except Exception as e:
print(f"TM9读取当前目录出错: {e}")
# 等待下次检查
time.sleep(interval)
def analyze_file(filepath):
"""
分析文件内容
:param filepath: 文件路径
"""
try:
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()
# 这里可以添加你的分析逻辑
print(f"TM9文件大小: {len(content)} 字节")
#print(f"首100字符: {content[:100]}...")
except Exception as e:
print(f"TM9读取文件 {filepath} 出错: {str(e)}")
# 连接回调函数
def on_connect1(client, userdata, flags, reason_code, properties):
if reason_code == 0:
print("TM9Connected to MQTT Broker!")
else:
print(f"TM9Failed to connect, return code {reason_code}")
if __name__ == "__main__":
# 创建MQTT客户端实例
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id)
#client = mqtt.Client(client_id)
client.on_connect = on_connect1
client.username_pw_set(userName, passWord)
# 连接到MQTT服务器
client.connect(broker, port, 60)
# 开始循环
client.loop_start()
# 初始文件列表
while True:
try:
ftp = connect_ftp()
ftp.cwd(FTP_DIR)
#ftp.set_pasv(True)
known_files = ftp.nlst()
print('获取TM9初始目录:')
#print(known_files)
ftp.quit()
monitor_directory(known_files,10)
except Exception as e:
print(f"TM9获取初始目录出错: {e}")
time.sleep(5)
import csv
import os
import time
from datetime import datetime
from ftplib import FTP
import socket
import io
import pandas as pd
from io import BytesIO
import paho.mqtt.client as mqtt
import json
# MQTT服务器地址和端口
broker = "iot.raytue.com"
port = 1883
# 客户端ID
client_id = "S&D23538EQB38P9&158&23"
userName="raytue"
passWord="P3S856X7622UJX15"
# 发布主题
topic = "/158/D23538EQB38P9/property/post"
# FTP服务器配置
FTP_SERVER = 'iot.raytue.com'
FTP_USER = 'tsensing'
FTP_PASS = 'tsensing!@#123'
FTP_DIR = '/vibration/2b0653(VC104)/' # FTP服务器上的目标目录,根据实际情况修改
def connect_ftp():
try:
ftp = FTP()
ftp.connect(FTP_SERVER) # 设置连接超时
ftp.login(FTP_USER, FTP_PASS)
#ftp.set_pasv(True)
ftp.cwd(FTP_DIR)
print(f"VC104成功连接 {FTP_SERVER}:{21}")
return ftp
except socket.timeout:
print("VC104连接超时,请检查网络或服务器状态")
except Exception as e:
print(f"VC104连接失败: {str(e)}")
def del_file(list_row):
# print(list_row[10])
number_row= len(list_row)
mqttstr=""
print("VC104列表中有",number_row,"行数据需处理")
j=10
# if list_row[10][0] == "Time":#有的表格第10行不是数据是表头
# j=11
for i in range(number_row):
if list_row[i][0] == "Time":
j=i+1
break
i=0
for i in range(j,number_row):
#格式化mqtt字符串
if(len(list_row[i])== 18):#防止最后一行有数据缺失!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
iso_str = list_row[i][0]
# 解析字符串,注意要指定时区信息
dt = datetime.fromisoformat(iso_str)
# 格式化为所需的格式
formatted_str = dt.strftime("%Y-%m-%d %H:%M:%S")
mqttstr="[{\"id\":\"vibrationData_time\",\"remark\":\"\",\"value\":\"%s\",\"ts\":\"%s\"},\
{\"id\":\"vibrationData_PPVX\",\"remark\":\"\",\"value\":\"%s\",\"ts\":\"%s\"},\
{\"id\":\"vibrationData_PPVY\",\"remark\":\"\",\"value\":\"%s\",\"ts\":\"%s\"},\
{\"id\":\"vibrationData_PPVZ\",\"remark\":\"\",\"value\":\"%s\",\"ts\":\"%s\"},\
{\"id\":\"vibrationData_PVS\",\"remark\":\"\",\"value\":\"%s\",\"ts\":\"%s\"}]" \
% (list_row[i][0], formatted_str ,list_row[i][1], formatted_str ,list_row[i][4], formatted_str,list_row[i][7] , formatted_str,list_row[i][10], formatted_str )
# print(mqttstr)
# payload = json.dumps(mqttstr)
payload = mqttstr
# 发布消息
result = client.publish(topic, payload)
# 检查消息是否成功发布
status = result[0]
if status == 0:
print(f"VC104Send `{payload}` to topic `{topic}`")
else:
print(f"VC104Failed to send message to topic {topic}")
time.sleep(0.05)#100ms传一次
def monitor_directory(known_files,interval=60):
"""
监控指定目录的新增文件
"""
# known_files=[]#首次全部传输完成后注释掉!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
while True:
ftp = connect_ftp()
ftp.cwd(FTP_DIR)
# 获取当前文件列表
try:
#ftp.set_pasv(True)
current_files = ftp.nlst()#读文件列表
print('获取VC104当前目录------------>:')
# print(current_files)
# 找出新增文件
#new_files = current_files - known_files
new_files = [item for item in current_files if item not in known_files]
print('获取VC104新增文件--------->:')
print(new_files)
#new_files = ['44444444.csv']
if new_files:
print(f"[{datetime.now()}] 发现 {len(new_files)} 个新文件:")
for filename in new_files:
#filepath = os.path.join(directory, filename)
print(f"VC104分析文件: {filename}")
#analyze_file(filepath)
for i in range(10): # 从0到4 防止掉线读不出来
# 使用BytesIO作为文件缓冲区
try:
print(f"VC104第{i}次读取")
ftp = connect_ftp()
ftp.cwd(FTP_DIR)
file_data = io.BytesIO()
ftp.retrbinary(f"RETR {filename}", file_data.write)
file_data.seek(0)
csv_data = file_data.read().decode('utf-8')
csv_reader = csv.reader((io.StringIO(csv_data).getvalue()).splitlines(),delimiter=',')
#csv_reader = csv.reader(csv_data)
list_row = list(csv_reader)
del_file(list_row)#处理数据
# for row in csv_reader:
# del_file(row)#处理数据
break
except Exception as e:
print(f"VC104读取文件{filename}出错: {e}")
# if i == 9:
# i = 0
continue
print("--------------------------------全部文件发送完毕------------------------------------------")#首次全部传输完成后,注释掉
#return#首次全部传输完成后,注释掉
# 打印文件内容
#content = file_data.read().decode('utf-8')
#print(content)
# 更新已知文件列表
known_files = current_files
ftp.quit()
except Exception as e:
print(f"VC104读取当前目录出错: {e}")
# 等待下次检查
time.sleep(interval)
def analyze_file(filepath):
"""
分析文件内容
:param filepath: 文件路径
"""
try:
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()
# 这里可以添加你的分析逻辑
print(f"VC104文件大小: {len(content)} 字节")
#print(f"首100字符: {content[:100]}...")
except Exception as e:
print(f"VC104读取文件 {filepath} 出错: {str(e)}")
# 连接回调函数
def on_connect1(client, userdata, flags, reason_code, properties):
if reason_code == 0:
print("VC104Connected to MQTT Broker!")
else:
print(f"VC104Failed to connect, return code {reason_code}")
if __name__ == "__main__":
# 创建MQTT客户端实例
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id)
#client = mqtt.Client(client_id)
client.on_connect = on_connect1
client.username_pw_set(userName, passWord)
# 连接到MQTT服务器
client.connect(broker, port, 60)
# 开始循环
client.loop_start()
# 初始文件列表
while True:
try:
ftp = connect_ftp()
ftp.cwd(FTP_DIR)
#ftp.set_pasv(True)
known_files = ftp.nlst()
print('获取VC104初始目录:')
#print(known_files)
ftp.quit()
monitor_directory(known_files,10)
except Exception as e:
print(f"VC104获取初始目录出错: {e}")
time.sleep(5)
\ No newline at end of file
import csv
import os
import time
from datetime import datetime
from ftplib import FTP
import socket
import io
import pandas as pd
from io import BytesIO
import paho.mqtt.client as mqtt
import json
# MQTT服务器地址和端口
broker = "iot.raytue.com"
port = 1883
# 客户端ID
client_id = "S&D239F9D04LVM9&158&23"
userName="raytue"
passWord="P3S856X7622UJX15"
# 发布主题
topic = "/158/D239F9D04LVM9/property/post"
# FTP服务器配置
FTP_SERVER = 'iot.raytue.com'
FTP_USER = 'tsensing'
FTP_PASS = 'tsensing!@#123'
FTP_DIR = '/vibration/2b0652(VC22)/' # FTP服务器上的目标目录,根据实际情况修改
def connect_ftp():
try:
ftp = FTP()
ftp.connect(FTP_SERVER) # 设置连接超时
ftp.login(FTP_USER, FTP_PASS)
#ftp.set_pasv(True)
ftp.cwd(FTP_DIR)
print(f"VC22成功连接 {FTP_SERVER}:{21}")
return ftp
except socket.timeout:
print("VC22连接超时,请检查网络或服务器状态")
except Exception as e:
print(f"VC22连接失败: {str(e)}")
def del_file(list_row):
# print(list_row[10])
number_row= len(list_row)
mqttstr=""
print("VC22列表中有",number_row,"行数据需处理")
j=10
# if list_row[10][0] == "Time":#有的表格第10行不是数据是表头
# j=11
for i in range(number_row):
if list_row[i][0] == "Time":
j=i+1
break
i=0
for i in range(j,number_row):
#格式化mqtt字符串
if(len(list_row[i])== 18):#防止最后一行有数据缺失!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
iso_str = list_row[i][0]
# 解析字符串,注意要指定时区信息
dt = datetime.fromisoformat(iso_str)
# 格式化为所需的格式
formatted_str = dt.strftime("%Y-%m-%d %H:%M:%S")
mqttstr="[{\"id\":\"vibrationData_time\",\"remark\":\"\",\"value\":\"%s\",\"ts\":\"%s\"},\
{\"id\":\"vibrationData_PPVX\",\"remark\":\"\",\"value\":\"%s\",\"ts\":\"%s\"},\
{\"id\":\"vibrationData_PPVY\",\"remark\":\"\",\"value\":\"%s\",\"ts\":\"%s\"},\
{\"id\":\"vibrationData_PPVZ\",\"remark\":\"\",\"value\":\"%s\",\"ts\":\"%s\"},\
{\"id\":\"vibrationData_PVS\",\"remark\":\"\",\"value\":\"%s\",\"ts\":\"%s\"}]" \
% (list_row[i][0], formatted_str ,list_row[i][1], formatted_str ,list_row[i][4], formatted_str,list_row[i][7] , formatted_str,list_row[i][10], formatted_str )
# print(mqttstr)
# payload = json.dumps(mqttstr)
payload = mqttstr
# 发布消息
result = client.publish(topic, payload)
# 检查消息是否成功发布
status = result[0]
if status == 0:
print(f"VC22Send `{payload}` to topic `{topic}`")
else:
print(f"VC22Failed to send message to topic {topic}")
time.sleep(0.05)#100ms传一次
def monitor_directory(known_files,interval=60):
"""
监控指定目录的新增文件
"""
# known_files=[]#首次全部传输完成后注释掉!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
while True:
ftp = connect_ftp()
ftp.cwd(FTP_DIR)
# 获取当前文件列表
try:
#ftp.set_pasv(True)
current_files = ftp.nlst()#读文件列表
print('获取VC22当前目录------------>:')
# print(current_files)
# 找出新增文件
#new_files = current_files - known_files
new_files = [item for item in current_files if item not in known_files]
print('获取VC22新增文件--------->:')
print(new_files)
#new_files = ['44444444.csv']
if new_files:
print(f"[{datetime.now()}] 发现 {len(new_files)} 个新文件:")
for filename in new_files:
#filepath = os.path.join(directory, filename)
print(f"VC22分析文件: {filename}")
#analyze_file(filepath)
for i in range(10): # 从0到4 防止掉线读不出来
# 使用BytesIO作为文件缓冲区
try:
print(f"VC22第{i}次读取")
ftp = connect_ftp()
ftp.cwd(FTP_DIR)
file_data = io.BytesIO()
ftp.retrbinary(f"RETR {filename}", file_data.write)
file_data.seek(0)
csv_data = file_data.read().decode('utf-8')
csv_reader = csv.reader((io.StringIO(csv_data).getvalue()).splitlines(),delimiter=',')
#csv_reader = csv.reader(csv_data)
list_row = list(csv_reader)
del_file(list_row)#处理数据
# for row in csv_reader:
# del_file(row)#处理数据
break
except Exception as e:
print(f"VC22读取文件{filename}出错: {e}")
# if i == 9:
# i = 0
continue
print("--------------------------------全部文件发送完毕------------------------------------------")#首次全部传输完成后,注释掉
#return#首次全部传输完成后,注释掉
# 打印文件内容
#content = file_data.read().decode('utf-8')
#print(content)
# 更新已知文件列表
known_files = current_files
ftp.quit()
except Exception as e:
print(f"VC22读取当前目录出错: {e}")
# 等待下次检查
time.sleep(interval)
def analyze_file(filepath):
"""
分析文件内容
:param filepath: 文件路径
"""
try:
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()
# 这里可以添加你的分析逻辑
print(f"VC22文件大小: {len(content)} 字节")
#print(f"首100字符: {content[:100]}...")
except Exception as e:
print(f"VC22读取文件 {filepath} 出错: {str(e)}")
# 连接回调函数
def on_connect1(client, userdata, flags, reason_code, properties):
if reason_code == 0:
print("VC22Connected to MQTT Broker!")
else:
print(f"VC22Failed to connect, return code {reason_code}")
if __name__ == "__main__":
# 创建MQTT客户端实例
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id)
#client = mqtt.Client(client_id)
client.on_connect = on_connect1
client.username_pw_set(userName, passWord)
# 连接到MQTT服务器
client.connect(broker, port, 60)
# 开始循环
client.loop_start()
# 初始文件列表
while True:
try:
ftp = connect_ftp()
ftp.cwd(FTP_DIR)
#ftp.set_pasv(True)
known_files = ftp.nlst()
print('获取VC22初始目录:')
#print(known_files)
ftp.quit()
monitor_directory(known_files,10)
except Exception as e:
print(f"VC22获取初始目录出错: {e}")
time.sleep(5)
\ No newline at end of file
import subprocess
import signal
import time
import os
from typing import Dict
class ScriptManager:
def __init__(self):
self.processes: Dict[str, subprocess.Popen] = {}
signal.signal(signal.SIGTERM, self._handle_signal)
signal.signal(signal.SIGINT, self._handle_signal)
def start_script(self, name: str, script_path: str) -> None:
"""启动指定脚本并记录进程"""
if name in self.processes:
print(f"脚本 {name} 已在运行")
return
proc = subprocess.Popen(
["python", script_path],
start_new_session=True # 防止僵尸进程
)
self.processes[name] = proc
print(f"已启动脚本 {name} (PID: {proc.pid})")
def stop_script(self, name: str, timeout=5) -> None:
"""优雅停止指定脚本"""
if name not in self.processes:
print(f"脚本 {name} 未运行")
return
proc = self.processes[name]
try:
proc.terminate() # 先发送SIGTERM
proc.wait(timeout=timeout)
except subprocess.TimeoutExpired:
proc.kill() # 超时后强制终止
print(f"强制终止脚本 {name}")
finally:
self.processes.pop(name)
print(f"已停止脚本 {name}")
def stop_all(self) -> None:
"""停止所有管理的脚本"""
for name in list(self.processes.keys()):
self.stop_script(name)
def _handle_signal(self, signum, frame) -> None:
"""处理终止信号"""
print(f"\n接收到终止信号 {signum}, 正在停止所有脚本...")
self.stop_all()
exit(0)
def list_scripts(self) -> None:
"""列出所有运行中的脚本"""
print("运行中的脚本:")
for name, proc in self.processes.items():
status = "运行中" if proc.poll() is None else "已停止"
print(f"- {name} (PID: {proc.pid}, 状态: {status})")
if __name__ == "__main__":
manager = ScriptManager()
# 示例用法
manager.start_script("worker1", "./filemonitorservice/filemonitorTM9.py")
manager.start_script("worker2", "./filemonitorservice/filemonitorTM10.py")
manager.start_script("worker3", "./filemonitorservice/filemonitorTM10A.py")
manager.start_script("worker4", "./filemonitorservice/filemonitorTM10B.py")
manager.start_script("worker5", "./filemonitorservice/filemonitorVC22.py")
manager.start_script("worker6", "./filemonitorservice/filemonitorVC104.py")
manager.start_script("worker7", "./reportservice/report_tilt.py")
manager.start_script("worker8", "./reportservice/report_vibration.py")
manager.start_script("worker9", "./reportservice/email_task.py")
manager.list_scripts()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
manager.stop_all()
This source diff could not be displayed because it is too large. You can view the blob instead.
2 個 Vibration sensor and 4 個 tilt sensor 會先把 data 以 csv file 推送到指定的 ftp (根很久之前給你試的差不多方式), 之後需要每天只取csv內的某個時間的一個數值, 自動出 daily report 及 send email 給客戶(可能有多個 email 需要接收).
1、物联网平台SaaS版
2、传感器数据对接(2个振动传感器、4个倾角传感器)
3、每日生成报告并发送到多个客户邮箱
configparser
\ No newline at end of file
import requests # type: ignore
import json
from datetime import datetime, timedelta
import pandas as pd
import xlsxwriter # type: ignore
def create_excel_with_chart(result_df, output_file):
result_df['dPitch']=pd.to_numeric(result_df['dPitch'], errors='coerce')
result_df['dRoll']=pd.to_numeric(result_df['dRoll'], errors='coerce')
# 创建Excel写入器
writer = pd.ExcelWriter(output_file, engine='xlsxwriter')
# 将DataFrame写入Excel
result_df.to_excel(writer, sheet_name='Data', startrow=25,index=False)
# 获取工作簿和工作表对象
workbook = writer.book
worksheet = writer.sheets['Data']
# 创建折线图
chart = workbook.add_chart({'type': 'line'})
# 配置图表数据
max_row = len(result_df) +1 # +1因为第一行是标题
chart.add_series({
'name': 'dPitch',
'categories': ['Data', 1+25, 0, max_row-1+25, 0], # Date列作为X轴
'values': ['Data', 1+25, 3, max_row-1+25, 3], # dPitch列作为Y轴
})
# 设置图表标题和轴标签
chart.set_title({'name': 'dPitch over Time'})
chart.set_x_axis({'name': 'Date'})
chart.set_y_axis({'name': 'dPitch'})
chart.set_size({'width': 480, 'height': 320})
# 设置日期格式的X轴
chart.set_x_axis({'date_axis': True})
# 将图表插入工作表
worksheet.insert_chart('B2', chart)
# 保存Excel文件
writer.close()
url = "https://iot.raytue.com/prod-api/login"
payload = {
"username": "admin",
"password": "@raytue123",
"sourceType": 1
}
headers = {
'Content-Type': 'application/json'
}
# 发送POST请求
response = requests.post(url, headers=headers, data=json.dumps(payload))
# 检查请求是否成功
if response.status_code == 200:
# 解析并打印返回的数据
data = response.json()
print(json.dumps(data, indent=4))
else:
# 打印错误信息
print(f"请求失败,状态码:{response.status_code},响应内容:{response.text}")
token= data["token"]
# 定义token和请求接口#
#token = "Bearer eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6IjcwNTdmNzIzLTY5NDUtNDgyZS04ZDViLTgyNjZjNjZhOTg2NCJ9.7Akf3R2AXpYNkGn3LhRkINZjRa7ZWUx1O3zCR6R6rcw5IF0083v5Jypv2OmKfItJxqLTNHLsNJGEVl74qC7FAA"
url = "https://iot.raytue.com/prod-api/data/center/deviceHistory"
# 定义请求的载荷
payload ={
"deviceId": 278,
"serialNumber": "D2367JBEYPY32",
"identifierList": [
{
"identifier": "tiltData_time",
"type": 1
},
{
"identifier": "tiltData_dRoll",
"type": 1
},
{
"identifier": "tiltData_dPitch",
"type": 1
}
],
"beginTime": "2025-05-30 11:45:12",
"endTime": "2025-06-06 11:45:12"
}
# 设置请求头,包括Authorization
headers = {
'Authorization': token,
'Content-Type': 'application/json'
}
# 发送POST请求
response = requests.post(url, headers=headers, data=json.dumps(payload))
# 检查请求是否成功
if response.status_code == 200:
# 解析并打印返回的数据
data1 = response.json()
# print(json.dumps(data1, indent=4))
else:
# 打印错误信息
print(f"请求失败,状态码:{response.status_code},响应内容:{response.text}")
original_json = json.dumps(data1, indent=4)
# 将JSON字符串转换为Python字典
data_dict = json.loads(original_json)
# 初始化tiltData数组
tilt_data_array = []
# 遍历data数组
for item in data_dict['data']:
# 获取时间戳作为键(这里我们不需要它作为最终输出的一部分,但用它来访问内部列表)
timestamp_key = list(item.keys())[0]
# 获取与该时间戳关联的数据列表
data_list = item[timestamp_key]
# 初始化一个空字典来存储组合后的数据
combined_data = {}
# 遍历数据列表,将相关数据合并到字典中
for data in data_list:
for key, value in data.items():
combined_data[key] = value
# 将组合后的数据字典添加到tiltData数组中
tilt_data_array.append(combined_data)
# # 将结果插入回原始字典中的新键'tiltData'
# data_dict['tiltData'] = tilt_data_array
# # 将修改后的字典转换为JSON字符串并打印
# modified_json = json.dumps(data_dict, indent=4)
#print(tilt_data_array)
# print(len(tilt_data_array))
# 打开(或创建)TXT文件并写入字符串
# with open('output.txt', 'w', encoding='utf-8') as file:
# file.write(str(tilt_data_array))
tilt_data = json.dumps(tilt_data_array)
# 转换为DataFrame
df = pd.DataFrame(json.loads(tilt_data))
#print(df['tiltData_time'])
# 将字符串时间转换为datetime对象
df['tiltData_time'] =pd.to_datetime( df['tiltData_time'].str.slice(stop=-6))
# 获取当前日期和时间
current_time = datetime.now()
# print(current_time)
# 计算前30天的日期列表
dates = [current_time - timedelta(days=i) for i in range(1, 31)]
# 初始化一个空的DataFrame来存储结果
result_df = pd.DataFrame(columns=['Date', 'Time', 'dRoll', 'dPitch'])
# 遍历前30天的日期
for date in dates:
# 获取当天上午的数据
# print("--------------------------------------------------------------------")
# print(date.date())
day_data = df[(df['tiltData_time'].dt.date == date.date()) & (df['tiltData_time'].dt.hour < 12)]
# print(day_data)
# print("--------------------------------------------------------------------")
# print(day_data)
# 如果当天有数据,则找到最接近10点30分的数据
if not day_data.empty:
# 计算每个数据与10点30分的时间差
time_diffs = abs(day_data['tiltData_time']- pd.to_datetime(f'{date.date()} 10:30:00'))
print("--------------------------------------------------------------------")
print(time_diffs.idxmin())
# # 找到时间差最小的数据
closest_data = df.iloc[time_diffs.idxmin()]
print(closest_data)
# 将数据添加到结果DataFrame中
result_df = result_df._append({
'Date': closest_data['tiltData_time'].date(),
'Time': closest_data['tiltData_time'].time(),
'dRoll': closest_data['tiltData_dRoll'],
'dPitch': closest_data['tiltData_dPitch']
}, ignore_index=True)
# 按照时间从小到大排序
result_df = result_df.sort_values(by=['Date', 'Time'])
reportname ='report'+ str(datetime.now().date()).replace("-", "") + '.xlsx'
# 将结果保存到Excel表格中
result_df.to_excel(reportname, index=False)
print(f"数据已保存到{reportname}文件中。")
create_excel_with_chart(result_df,'output_with_chart.xlsx')
import os
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
import schedule # type: ignore
import time
from datetime import datetime
import configparser
# 配置信息
SMTP_SERVER = '' # SMTP服务器地址
SMTP_PORT = '' # SMTP端口
SENDER_EMAIL = '' # 发件邮箱
SENDER_PASSWORD = '' # 邮箱密码
RECIPIENTS = '' # 收件人列表
FILE_PREFIX = 'tilt_report_' # 文件前缀
FILE_PREFIX2 = 'vibration_report_' # 文件前缀
FILE_DIR = './report' # 文件目录
def get_today_filename():
"""获取当天日期的文件名"""
# today = datetime.now().strftime('%Y%m%d')
today = str(datetime.now().date()).replace("-", "")
return [f"{FILE_PREFIX}{today}.xlsx",f"{FILE_PREFIX2}{today}.xlsx"]
def send_email(SMTP_SERVER,SMTP_PORT,SENDER_EMAIL,SENDER_PASSWORD,RECIPIENTS):
"""发送邮件函数"""
filename = get_today_filename()
filepath = os.path.join(FILE_DIR, filename[0])
filepath2 = os.path.join(FILE_DIR, filename[1])
if not os.path.exists(filepath):
print(f"文件 {filename[0]} 不存在")
return
if not os.path.exists(filepath2):
print(f"文件 {filename[1]} 不存在")
return
msg = MIMEMultipart()
msg['From'] = SENDER_EMAIL
msg['To'] = ', '.join(RECIPIENTS)
msg['Subject'] = f"每日报告 - {datetime.now().strftime('%Y-%m-%d')}"
# 添加附件
with open(filepath, 'rb') as f:
part = MIMEApplication(f.read(), Name=filename[0])
part['Content-Disposition'] = f'attachment; filename="{filename[0]}"'
msg.attach(part)
with open(filepath2, 'rb') as f:
part = MIMEApplication(f.read(), Name=filename[1])
part['Content-Disposition'] = f'attachment; filename="{filename[1]}"'
msg.attach(part)
try:
server = smtplib.SMTP(SMTP_SERVER, SMTP_PORT)
server.starttls()
server.login(SENDER_EMAIL, SENDER_PASSWORD)
server.sendmail(SENDER_EMAIL, RECIPIENTS, msg.as_string())
server.quit()
print(f"{datetime.now()}: 邮件发送成功")
except Exception as e:
print(f"邮件发送失败: {str(e)}")
def job():
"""定时任务"""
print(f"{datetime.now()}: 开始执行发送任务")
# 创建ConfigParser对象并读取INI文件
config = configparser.ConfigParser()
config.read('./config.ini') # 确保路径正确,替换为你的文件名
SMTP_SERVER = config['EMAIL']['SMTP_SERVER']# SMTP服务器地址
SMTP_PORT = config.get('EMAIL','SMTP_PORT' ) # SMTP端口
SENDER_EMAIL = config['EMAIL']['SENDER_EMAIL'] # 发件邮箱
SENDER_PASSWORD = config['EMAIL']['SENDER_PASSWORD'] # 邮箱密码
RECIPIENTS = config.get('EMAIL', 'RECIPIENTS').split(',') # 收件人列表
send_email(SMTP_SERVER,SMTP_PORT,SENDER_EMAIL,SENDER_PASSWORD,RECIPIENTS)
if __name__ == '__main__':
# 每天8:30执行
print("邮件自动发送程序已启动...")
# 创建ConfigParser对象并读取INI文件
config = configparser.ConfigParser()
config.read('./config.ini') # 确保路径正确,替换为你的文件名
EMAIL_TIME= config['REPORTTIME']['EMAIL_TIME']
schedule.every().day.at(EMAIL_TIME).do(job)
while True:
schedule.run_pending()
time.sleep(60)
import requests # type: ignore
import json
from datetime import datetime, timedelta
import pandas as pd
import xlsxwriter # type: ignore
import openpyxl
from openpyxl import load_workbook
from openpyxl.styles import Border, Side,Alignment
from openpyxl.drawing.image import Image
from openpyxl.chart import LineChart, Reference, Series
from openpyxl.worksheet.dimensions import ColumnDimension
#参考线
Alert=0.0573
Alarm=0.0763
Action=0.1144
Alertneg=-0.0573
Alarmneg=-0.0763
Actionneg=-0.1144
#数据写入表格并生成曲线图*********************************************************************************************************************************************************************************
def create_excel_with_chart(result_df, result_df1, result_df2,result_df3,output_file,startrowNo):
print("开始生成报告......")
result_df['dPitch']=pd.to_numeric(result_df['dPitch'], errors='coerce')
result_df['dRoll']=pd.to_numeric(result_df['dRoll'], errors='coerce')
result_df1['dPitch']=pd.to_numeric(result_df1['dPitch'], errors='coerce')
result_df1['dRoll']=pd.to_numeric(result_df1['dRoll'], errors='coerce')
result_df2['dPitch']=pd.to_numeric(result_df2['dPitch'], errors='coerce')
result_df2['dRoll']=pd.to_numeric(result_df2['dRoll'], errors='coerce')
result_df3['dPitch']=pd.to_numeric(result_df3['dPitch'], errors='coerce')
result_df3['dRoll']=pd.to_numeric(result_df3['dRoll'], errors='coerce')
# 创建Excel写入器
writer = pd.ExcelWriter(output_file, engine='xlsxwriter')
# 将DataFrame写入Excel
result_df.to_excel(writer, sheet_name='Report', startrow = startrowNo,startcol = 1,index=False)
result_df1[['dRoll','dPitch']].to_excel(writer, sheet_name='Report',startrow = startrowNo,startcol = 5,index=False)
result_df2[['dRoll','dPitch']].to_excel(writer, sheet_name='Report',startrow = startrowNo,startcol = 7,index=False)
result_df3[['dRoll','dPitch']].to_excel(writer, sheet_name='Report',startrow = startrowNo,startcol = 9,index=False)
# 获取工作簿和工作表对象
workbook = writer.book
worksheet = writer.sheets['Report']
worksheet2 = workbook.add_worksheet('Data')#6条参考线的数据放到Sheet2里面
worksheet.set_column('D:K', 10)
worksheet.set_column('B:B', 15)
worksheet.set_column('C:C', 5)
# 循环写入数据到指定范围
for row in range(27, 56 + 1):
worksheet2.write(row - 1, 16 - 1, Alert) # 注意:write方法中的行和列是从0开始计数的
# 循环写入数据到指定范围
for row in range(27, 56 + 1):
worksheet2.write(row - 1, 17 - 1, Alarm) # 注意:write方法中的行和列是从0开始计数的
# 循环写入数据到指定范围
for row in range(27, 56 + 1):
worksheet2.write(row - 1, 18 - 1, Action) # 注意:write方法中的行和列是从0开始计数的
# 循环写入数据到指定范围
for row in range(27, 56 + 1):
worksheet2.write(row - 1, 19 - 1, Alertneg) # 注意:write方法中的行和列是从0开始计数的
# 循环写入数据到指定范围
for row in range(27, 56 + 1):
worksheet2.write(row - 1, 20 - 1, Alarmneg) # 注意:write方法中的行和列是从0开始计数的
# 循环写入数据到指定范围
for row in range(27, 56 + 1):
worksheet2.write(row - 1, 21 - 1, Actionneg) # 注意:write方法中的行和列是从0开始计数的
# worksheet.set_column('P:U', 0)
# 创建折线图
chart = workbook.add_chart({'type': 'line'})
# 配置图表数据
max_row = len(result_df) +1 # +1因为第一行是标题
chart.add_series({
'name': 'TM9',
'categories': ['Report', 1+25, 1, max_row-1+25, 1], # Date列作为X轴
'values': ['Report', 1+25, 4, max_row-1+25, 4], # dPitch列作为Y轴
'marker': {'type': 'circle','size': 4}, # 系列标记
'line': {'width': 0.8},
})
chart.add_series({
'name': 'TM10',
'categories': ['Report', 1+25, 1, max_row-1+25, 1], # Date列作为X轴
'values': ['Report', 1+25, 6, max_row-1+25, 6], # dPitch列作为Y轴
'marker': {'type': 'circle','size': 4}, # 系列标记
'line': {'width': 0.8},
})
chart.add_series({
'name': 'TM10A',
'categories': ['Report', 1+25, 1, max_row-1+25, 1], # Date列作为X轴
'values': ['Report', 1+25, 8, max_row-1+25, 8], # dPitch列作为Y轴
'marker': {'type': 'circle','size': 4}, # 系列标记
'line': {'width': 0.8},
})
chart.add_series({
'name': 'TM10B',
'categories': ['Report', 1+25, 1, max_row-1+25, 1], # Date列作为X轴
'values': ['Report', 1+25, 10, max_row-1+25, 10], # dPitch列作为Y轴
'marker': {'type': 'circle','size': 4}, # 系列标记
'line': {'width': 0.8},
})
chart.add_series({
'name': 'Alert',
'categories': ['Report', 1+25, 1, max_row-1+25, 1], # Date列作为X轴
'values': ['Data', 1+25, 15, max_row-1+25, 15], # dPitch列作为Y轴
# 'marker': {'type': 'circle','size': 4}, # 系列标记
'line': {'width': 1.5,'color':'green'},
})
chart.add_series({
'name': 'Alarm',
'categories': ['Report', 1+25, 1, max_row-1+25, 1], # Date列作为X轴
'values': ['Data', 1+25, 16, max_row-1+25, 16], # dPitch列作为Y轴
# 'marker': {'type': 'circle','size': 4}, # 系列标记
'line': {'width': 1.5,'color':'yellow'},
})
chart.add_series({
'name': 'Action',
'categories': ['Report', 1+25, 1, max_row-1+25, 1], # Date列作为X轴
'values': ['Data', 1+25, 17, max_row-1+25, 17], # dPitch列作为Y轴
# 'marker': {'type': 'circle','size': 4}, # 系列标记
'line': {'width': 1.5,'color':'red'},
})
chart.add_series({
'name': 'Alert',
'categories': ['Report', 1+25, 1, max_row-1+25, 1], # Date列作为X轴
'values': ['Data', 1+25, 18, max_row-1+25, 18], # dPitch列作为Y轴
# 'marker': {'type': 'circle','size': 4}, # 系列标记
'line': {'width': 1.5,'color':'green'},
})
chart.add_series({
'name': 'Alarm',
'categories': ['Report', 1+25, 1, max_row-1+25, 1], # Date列作为X轴
'values': ['Data', 1+25, 19, max_row-1+25, 19], # dPitch列作为Y轴
# 'marker': {'type': 'circle','size': 4}, # 系列标记
'line': {'width': 1.5,'color':'yellow'},
})
chart.add_series({
'name': 'Action',
'categories': ['Report', 1+25, 1, max_row-1+25, 1], # Date列作为X轴
'values': ['Data', 1+25, 20, max_row-1+25, 20], # dPitch列作为Y轴
# 'marker': {'type': 'circle','size': 4}, # 系列标记
'line': {'width': 1.5,'color':'red'},
})
# 设置图表标题和轴标签
# chart.set_title({'name': 'dPitch over Time'})
chart.set_y_axis({'crossing': 'min',})
chart.set_size({'width': 880, 'height': 320})
# chart.set_x_axis({'crossing': 'min'})
chart.set_y_axis({
'crossing': 'min',
'major_gridlines': {
'visible': True,
'line': {'color':'#eee2e1'},
# 'line_dash_type': 'dash-dot' # 设置线型为点划线
}})
# chart.set_x_axis({'position_axis': 'on_tick', 'crossing': 'min','date_axis': True})
# 设置日期格式的X轴
# chart.set_x_axis({'date_axis': True})
# 将图表插入工作表
worksheet.insert_chart('B9', chart)
format1 = {
'bold': True, # 字体加粗
# 'align': 'center', # 水平位置设置:居中
'valign': 'vcenter', # 垂直位置设置,居中
'font_size': 8, # '字体大小设置'
}
str_format1 = workbook.add_format(format1) #设置要调整的格式,可参阅链接文章实现更多样式选择
worksheet.write('B4', 'CRBC - Build King Joint Venture',str_format1)
worksheet.write('B5', 'MTR Contract 1500',str_format1)
worksheet.write('B6', 'TME Stations, Viaducts and River Crossing',str_format1)
worksheet.write('B8', 'Tilting Monitoring Record - A16 Rock Filling Works',str_format1)
worksheet.write('G5', 'AAA Value (degree)',str_format1)
worksheet.write('G6', 'Alert',str_format1)
worksheet.write('G7', 'Alarm',str_format1)
worksheet.write('G8', 'Action',str_format1)
format2 = {
# 'bold': True, # 字体加粗
'align': 'center', # 水平位置设置:居中
'valign': 'vcenter', # 垂直位置设置,居中
'font_size': 8, # '字体大小设置'
}
str_format2 = workbook.add_format(format2) #设置要调整的格式,可参阅链接文章实现更多样式选择
worksheet.write('H6', Alert,str_format2)
worksheet.write('H7',Alarm,str_format2)
worksheet.write('H8',Action,str_format2)
format3 = {
'bold': True, # 字体加粗
'align': 'center', # 水平位置设置:居中
'valign': 'vcenter', # 垂直位置设置,居中
'font_size': 11, # '字体大小设置'
}
str_format3 = workbook.add_format(format3) #设置要调整的格式,可参阅链接文章实现更多样式选择
worksheet.merge_range('B25:C25', 'PointID', str_format3)#合并单元格输入
worksheet.merge_range('D25:E25', 'TM9', str_format3)#合并单元格输入
worksheet.merge_range('F25:G25', 'TM10', str_format3)#合并单元格输入
worksheet.merge_range('H25:I25', 'TM10A', str_format3)#合并单元格输入
worksheet.merge_range('J25:K25', 'TM10B', str_format3)#合并单元格输入
worksheet.merge_range('L25:M25', 'Remarks', str_format3)#合并单元格输入
# 保存Excel文件
writer.close()
# 1. 加载现有工作簿
wb = load_workbook(output_file) # 替换为实际文件名
ws = wb.active # 默认操作当前活动工作表
# 2. 定义边框样式(可自定义)
thin_border = Border(
left=Side(style='thin'),
right=Side(style='thin'),
top=Side(style='thin'),
bottom=Side(style='thin')
)
# 3. 设置矩形区域边框(示例:B2:D10)
target_range = 'B26:M56'
for row in ws[target_range]:
for cell in row:
cell.border = thin_border
target_range = 'G5:H8'
for row in ws[target_range]:
for cell in row:
cell.border = thin_border
target_range = 'B25:M25'
for row in ws[target_range]:
for cell in row:
cell.border = thin_border
# # 设置连续单元格的范围(例如 A1:B2)
# cell_range = "B25:M56"
# start_col, start_row = openpyxl.utils.coordinate_to_tuple(cell_range.split(':')[0])
# end_col, end_row = openpyxl.utils.coordinate_to_tuple(cell_range.split(':')[1])
# 创建一个对齐对象,并设置居中对齐
alignment = Alignment(horizontal='center', vertical='center')
# 迭代范围内的每个单元格并应用对齐方式
for col in range(1, 14):
for row in range(27, 57):
cell = ws.cell(row=row, column=col)
cell.alignment = alignment
# 插入logo图片
img = Image('logo.png')
ws.add_image(img, 'J3')
# #这3列放Alert、Alarm、Action数据用于生成折线图的警戒线
# ws.column_dimensions.group("P", hidden=True) # 隐藏列
# ws.column_dimensions.group("Q", hidden=True)
# ws.column_dimensions.group("R", hidden=True)
# 4. 保存修改(可另存为新文件)
wb.save(output_file)
print("生成报告完成!")
#登录获取token***********************************************************************************************************************************************************************************************
def login():
url = "https://iot.raytue.com/prod-api/login"
payload = {
"username": "admin",
"password": "@raytue123",
"sourceType": 1
}
headers = {
'Content-Type': 'application/json'
}
# 发送POST请求
response = requests.post(url, headers=headers, data=json.dumps(payload))
# 检查请求是否成功
if response.status_code == 200:
# 解析并打印返回的数据
data = response.json()
# print(json.dumps(data, indent=4))
print("请求token成功!")
token= data["token"]
return token
else:
# 打印错误信息
print(f"请求失败,状态码:{response.status_code},响应内容:{response.text}")
return None
#************获取历史数据,字典字符数组输出*****************************************************************************************************************************************************************************************
def getResponseTilt(token,url,deviceId,serialNumber,beginTime,endTime):
beginTime = str(beginTime)
endTime = str(endTime)
# 定义请求的载荷
payload ={
"deviceId": deviceId,
"serialNumber": serialNumber,
"identifierList": [
{
"identifier": "tiltData_time",
"type": 1
},
{
"identifier": "tiltData_dRoll",
"type": 1
},
{
"identifier": "tiltData_dPitch",
"type": 1
}
],
"beginTime": beginTime,
"endTime": endTime
}
# 设置请求头,包括Authorization
headers = {
'Authorization': token,
'Content-Type': 'application/json'
}
# 发送POST请求
response = requests.post(url, headers=headers, data=json.dumps(payload))
# 检查请求是否成功
if response.status_code == 200:
# 解析并打印返回的数据
data1 = response.json()
# print(json.dumps(data1, indent=4))
print(f"成功获取设备历史数据,deviceId:{serialNumber}")
else:
# 打印错误信息
print(f"请求失败,状态码:{response.status_code},响应内容:{response.text}")
original_json = json.dumps(data1, indent=4)
# 将JSON字符串转换为Python字典
data_dict = json.loads(original_json)
# 初始化tiltData数组
tilt_data_array = []
# 遍历data数组
for item in data_dict['data']:
# 获取时间戳作为键(这里我们不需要它作为最终输出的一部分,但用它来访问内部列表)
timestamp_key = list(item.keys())[0]
# 获取与该时间戳关联的数据列表
data_list = item[timestamp_key]
# 初始化一个空字典来存储组合后的数据
combined_data = {}
# 遍历数据列表,将相关数据合并到字典中
for data in data_list:
for key, value in data.items():
combined_data[key] = value
# 将组合后的数据字典添加到tiltData数组中
tilt_data_array.append(combined_data)
return tilt_data_array
#********************筛选30天内10:30的数据,dataframe格式输出******************************************************************************************************************************************************************************
def getdfData(tilt_data_array):
tilt_data = json.dumps(tilt_data_array)
# 转换为DataFrame
df = pd.DataFrame(json.loads(tilt_data))
#print(df['tiltData_time'])
# 将字符串时间转换为datetime对象
df['tiltData_time'] =pd.to_datetime( df['tiltData_time'].str.slice(stop=-6))
# 获取当前日期和时间
current_time = datetime.now()
# print(current_time)
# 计算前30天的日期列表
dates = [current_time - timedelta(days=i) for i in range(1, 31)]
# 初始化一个空的DataFrame来存储结果
result_df = pd.DataFrame(columns=['Date', 'Time', 'dRoll', 'dPitch'])
# 遍历前30天的日期
for date in dates:
# 获取当天上午的数据
# print("--------------------------------------------------------------------")
# print(date.date())
day_data = df[(df['tiltData_time'].dt.date == date.date()) & (df['tiltData_time'].dt.hour < 12)]
# print(day_data)
# print("--------------------------------------------------------------------")
# print(day_data)
# 如果当天有数据,则找到最接近10点30分的数据
if not day_data.empty:
# 计算每个数据与10点30分的时间差
time_diffs = abs(day_data['tiltData_time']- pd.to_datetime(f'{date.date()} 10:30:00'))
# print("--------------------------------------------------------------------")
# print(time_diffs.idxmin())
# # 找到时间差最小的数据
closest_data = df.iloc[time_diffs.idxmin()]
# print(closest_data)
# 将数据添加到结果DataFrame中
result_df = result_df._append({
'Date': closest_data['tiltData_time'].date(),
# 'Time': closest_data['tiltData_time'].time(),
'Time': 'AM',
'dRoll': closest_data['tiltData_dRoll'],
'dPitch': closest_data['tiltData_dPitch']
}, ignore_index=True)
else:
result_df = result_df._append({#当天没有数据的,取值为空
'Date':date.date(),
# 'Time': '10:30:00',
'Time': 'AM',
'dRoll': None,
'dPitch': None
}, ignore_index=True)
# 按照时间从小到大排序
result_df = result_df.sort_values(by=['Date', 'Time'])
return result_df
#**********main()*******************************************************************************************************************************************************************************************
#登录获取token
token = login()
#历史数据接口地址
url = "https://iot.raytue.com/prod-api/data/center/deviceHistory"
#获取传感器数据字典格式数组
tilt_data_array_TM9 = getResponseTilt(token,url,277,"D23ANR8041JQI",(datetime.now()-timedelta(31)).strftime("%Y-%m-%d %H:%M:%S"),datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
#转换成dataframe数据
result_df_TM9 =getdfData(tilt_data_array_TM9)
tilt_data_array_TM10 = getResponseTilt(token,url,278,"D2367JBEYPY32",(datetime.now()-timedelta(31)).strftime("%Y-%m-%d %H:%M:%S"),datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
result_df_TM10 =getdfData(tilt_data_array_TM10)
tilt_data_array_TM10A = getResponseTilt(token,url,279,"D23AFZM72Q620",(datetime.now()-timedelta(31)).strftime("%Y-%m-%d %H:%M:%S"),datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
result_df_TM10A =getdfData(tilt_data_array_TM10A)
tilt_data_array_TM10B = getResponseTilt(token,url,280,"D2368757I1Y4G",(datetime.now()-timedelta(31)).strftime("%Y-%m-%d %H:%M:%S"),datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
result_df_TM10B =getdfData(tilt_data_array_TM10B)
# print(result_df_TM10B)
#生成当天日期命名的文件名
reportname ='report'+ str(datetime.now().date()).replace("-", "") + '.xlsx'
# # 将结果保存到Excel表格中
# result_df.to_excel(reportname, index=False)
# print(f"数据已保存到{reportname}文件中。")
#生成报告
create_excel_with_chart(result_df_TM9,result_df_TM10,result_df_TM10A,result_df_TM10B,reportname,25)
import requests # type: ignore
import json
from datetime import datetime, timedelta
import pandas as pd
import xlsxwriter # type: ignore
import openpyxl
from openpyxl import load_workbook
from openpyxl.styles import Border, Side,Alignment,NamedStyle
from openpyxl.drawing.image import Image
from openpyxl.chart import LineChart, Reference, Series
from openpyxl.worksheet.dimensions import ColumnDimension
import schedule # type: ignore
import time
import configparser
import math
from pandas import ExcelWriter
from pandas import ExcelFile
#参考线
Alert=0.0573
Alarm=0.0763
Action=0.1144
Alertneg=-0.0573
Alarmneg=-0.0763
Actionneg=-0.1144
Initial_Date='2025-5-7'
Initial_Reading=0
#数据写入表格并生成曲线图*********************************************************************************************************************************************************************************
def create_excel_with_chart(result_df, result_df1, result_df2,result_df3,output_file,startrowNo):
print("开始生成报告......")
result_df['dPitch']=pd.to_numeric(result_df['dPitch'], errors='coerce')
result_df['dRoll']=pd.to_numeric(result_df['dRoll'], errors='coerce')
result_df1['dPitch']=pd.to_numeric(result_df1['dPitch'], errors='coerce')
result_df1['dRoll']=pd.to_numeric(result_df1['dRoll'], errors='coerce')
result_df2['dPitch']=pd.to_numeric(result_df2['dPitch'], errors='coerce')
result_df2['dRoll']=pd.to_numeric(result_df2['dRoll'], errors='coerce')
result_df3['dPitch']=pd.to_numeric(result_df3['dPitch'], errors='coerce')
result_df3['dRoll']=pd.to_numeric(result_df3['dRoll'], errors='coerce')
# 创建Excel写入器
writer = pd.ExcelWriter(output_file, engine='xlsxwriter')
# 将DataFrame写入Excel
result_df[['Date','Time']].to_excel(writer, sheet_name='Report', startrow = startrowNo,startcol = 1,index=False)
# result_df['dPitch']=0
result_df[['dPitch']].to_excel(writer, sheet_name='Report', startrow = startrowNo,startcol = 3,index=False)
result_df[['dRoll']].to_excel(writer, sheet_name='Report', startrow = startrowNo,startcol = 4,index=False)
result_df1[['dPitch']].to_excel(writer, sheet_name='Report', startrow = startrowNo,startcol = 5,index=False)
result_df1[['dRoll']].to_excel(writer, sheet_name='Report',startrow = startrowNo,startcol = 6,index=False)
result_df2[['dPitch']].to_excel(writer, sheet_name='Report', startrow = startrowNo,startcol = 7,index=False)
result_df2[['dRoll']].to_excel(writer, sheet_name='Report',startrow = startrowNo,startcol = 8,index=False)
result_df3[['dPitch']].to_excel(writer, sheet_name='Report', startrow = startrowNo,startcol = 9,index=False)
result_df3[['dRoll']].to_excel(writer, sheet_name='Report',startrow = startrowNo,startcol = 10,index=False)
# 获取工作簿和工作表对象
workbook = writer.book
worksheet = writer.sheets['Report']
worksheet2 = workbook.add_worksheet('Data')#6条参考线的数据放到Sheet2里面
worksheet.set_column('D:K', 10)
worksheet.set_column('B:B', 15)
worksheet.set_column('C:C', 5)
data_format = workbook.add_format({
'align': 'center',
'valign': 'vcenter'
})
# 其实表中数据已写入,但是to_excel不能居中写入,为了让表格的数据居中,重新写入,带居中格式
# 应用数据格式
for row_num in range(len(result_df)):
cell_value = result_df.iat[row_num, 0]
worksheet.write(row_num + 26, 0 + 1, str(cell_value), data_format)
for row_num in range(len(result_df)):
cell_value = result_df.iat[row_num,1]
worksheet.write(row_num + 26, 0 + 2, cell_value, data_format)
for row_num in range(len(result_df)):
cell_value = result_df.iat[row_num,2]
if str(cell_value) in ["NaN","nan","NAN"]:#如果有"NaN","nan","NAN",会报错,替换为none
cell_value=None
worksheet.write(row_num + 26, 0 + 4, cell_value, data_format)
for row_num in range(len(result_df)):
cell_value = result_df.iat[row_num,3]
if str(cell_value) in ["NaN","nan","NAN"]:
cell_value=None
worksheet.write(row_num + 26, 0 + 3, cell_value, data_format)
for row_num in range(len(result_df1)):
cell_value = result_df1.iat[row_num,3]
if str(cell_value) in ["NaN","nan","NAN"]:
cell_value=None
worksheet.write(row_num + 26, 0 + 5, cell_value, data_format)
for row_num in range(len(result_df1)):
cell_value = result_df1.iat[row_num,2]
if str(cell_value) in ["NaN","nan","NAN"]:
cell_value=None
worksheet.write(row_num + 26, 0 + 6, cell_value, data_format)
for row_num in range(len(result_df2)):
cell_value = result_df2.iat[row_num,3]
if str(cell_value) in ["NaN","nan","NAN"]:
cell_value=None
worksheet.write(row_num + 26, 0 + 7, cell_value, data_format)
for row_num in range(len(result_df2)):
cell_value = result_df2.iat[row_num,2]
if str(cell_value) in ["NaN","nan","NAN"]:
cell_value=None
worksheet.write(row_num + 26, 0 + 8, cell_value, data_format)
for row_num in range(len(result_df3)):
cell_value = result_df3.iat[row_num,3]
if str(cell_value) in ["NaN","nan","NAN"]:
cell_value=None
worksheet.write(row_num + 26, 0 + 9, cell_value, data_format)
for row_num in range(len(result_df3)):
cell_value = result_df3.iat[row_num,2]
if str(cell_value) in ["NaN","nan","NAN"]:
cell_value=None
worksheet.write(row_num + 26, 0 + 10, cell_value, data_format)
# 将参考线的数据写入到第二张表中,方便引用
# 循环写入数据到指定范围
for row in range(27, 56 + 1):
worksheet2.write(row - 1, 16 - 1, Alert) # 注意:write方法中的行和列是从0开始计数的
# 循环写入数据到指定范围
for row in range(27, 56 + 1):
worksheet2.write(row - 1, 17 - 1, Alarm) # 注意:write方法中的行和列是从0开始计数的
# 循环写入数据到指定范围
for row in range(27, 56 + 1):
worksheet2.write(row - 1, 18 - 1, Action) # 注意:write方法中的行和列是从0开始计数的
# 循环写入数据到指定范围
for row in range(27, 56 + 1):
worksheet2.write(row - 1, 19 - 1, Alertneg) # 注意:write方法中的行和列是从0开始计数的
# 循环写入数据到指定范围
for row in range(27, 56 + 1):
worksheet2.write(row - 1, 20 - 1, Alarmneg) # 注意:write方法中的行和列是从0开始计数的
# 循环写入数据到指定范围
for row in range(27, 56 + 1):
worksheet2.write(row - 1, 21 - 1, Actionneg) # 注意:write方法中的行和列是从0开始计数的
# worksheet.set_column('P:U', 0)
# 创建折线图
chart = workbook.add_chart({'type': 'line'})
# 配置图表数据
max_row = len(result_df) +1 # +1因为第一行是标题
chart.add_series({
'name': 'TM9',
'categories': ['Report', 1+25, 1, max_row-1+25, 1], # Date列作为X轴
'values': ['Report', 1+25, 4, max_row-1+25, 4], # dPitch列作为Y轴
'marker': {'type': 'circle','size': 4}, # 系列标记
'line': {'width': 0.8},
})
chart.add_series({
'name': 'TM10',
'categories': ['Report', 1+25, 1, max_row-1+25, 1], # Date列作为X轴
'values': ['Report', 1+25, 6, max_row-1+25, 6], # dPitch列作为Y轴
'marker': {'type': 'circle','size': 4}, # 系列标记
'line': {'width': 0.8},
})
chart.add_series({
'name': 'TM10A',
'categories': ['Report', 1+25, 1, max_row-1+25, 1], # Date列作为X轴
'values': ['Report', 1+25, 8, max_row-1+25, 8], # dPitch列作为Y轴
'marker': {'type': 'circle','size': 4}, # 系列标记
'line': {'width': 0.8},
})
chart.add_series({
'name': 'TM10B',
'categories': ['Report', 1+25, 1, max_row-1+25, 1], # Date列作为X轴
'values': ['Report', 1+25, 10, max_row-1+25, 10], # dPitch列作为Y轴
'marker': {'type': 'circle','size': 4}, # 系列标记
'line': {'width': 0.8},
})
chart.add_series({
'name': '',
'categories': ['Report', 1+25, 1, max_row-1+25, 1], # Date列作为X轴
'values': ['Data', 1+25, 15, max_row-1+25, 15], # dPitch列作为Y轴
# 'marker': {'type': 'circle','size': 4}, # 系列标记
'line': {'width': 1.5,'color':'green'},
})
chart.add_series({
'name': '',
'categories': ['Report', 1+25, 1, max_row-1+25, 1], # Date列作为X轴
'values': ['Data', 1+25, 16, max_row-1+25, 16], # dPitch列作为Y轴
# 'marker': {'type': 'circle','size': 4}, # 系列标记
'line': {'width': 1.5,'color':'yellow'},
})
chart.add_series({
'name': '',
'categories': ['Report', 1+25, 1, max_row-1+25, 1], # Date列作为X轴
'values': ['Data', 1+25, 17, max_row-1+25, 17], # dPitch列作为Y轴
# 'marker': {'type': 'circle','size': 4}, # 系列标记
'line': {'width': 1.5,'color':'red'},
})
chart.add_series({
'name': 'Alert',
'categories': ['Report', 1+25, 1, max_row-1+25, 1], # Date列作为X轴
'values': ['Data', 1+25, 18, max_row-1+25, 18], # dPitch列作为Y轴
# 'marker': {'type': 'circle','size': 4}, # 系列标记
'line': {'width': 1.5,'color':'green'},
})
chart.add_series({
'name': 'Alarm',
'categories': ['Report', 1+25, 1, max_row-1+25, 1], # Date列作为X轴
'values': ['Data', 1+25, 19, max_row-1+25, 19], # dPitch列作为Y轴
# 'marker': {'type': 'circle','size': 4}, # 系列标记
'line': {'width': 1.5,'color':'yellow'},
})
chart.add_series({
'name': 'Action',
'categories': ['Report', 1+25, 1, max_row-1+25, 1], # Date列作为X轴
'values': ['Data', 1+25, 20, max_row-1+25, 20], # dPitch列作为Y轴
# 'marker': {'type': 'circle','size': 4}, # 系列标记
'line': {'width': 1.5,'color':'red'},
})
# 设置图表标题和轴标签
# chart.set_title({'name': 'dPitch over Time'})
chart.set_size({'width': 670, 'height': 315})
chart.set_x_axis({'num_font': {'rotation': -60},'name_font': {'size': 5,},})
# chart.set_x_axis({'crossing': 'min'})
chart.set_y_axis({
'min':-0.15,
'max': 0.15,
'crossing': 'min',
'major_gridlines': {
'visible': True,
'line': {'color':'#eee2e1'},
# 'line_dash_type': 'dash-dot' # 设置线型为点划线
},
})
# chart.set_y_axis({'crossing': -0.15})
# chart.set_y_axis({'min':-0.15, 'max': 0.15}) # 设置Y轴范围
# chart.set_x_axis({'position_axis': 'on_tick', 'crossing': 'min','date_axis': True})
# 设置日期格式的X轴
# chart.set_x_axis({'date_axis': True})
# chart.set_legend_options({'delete_series': [4,5,6,7,8,9]})
chart.set_legend({'delete_series': [4,5,6,7,8,9]})
# 将图表插入工作表
worksheet.insert_chart('B7', chart)
format1 = {
'bold': True, # 字体加粗
# 'align': 'center', # 水平位置设置:居中
'valign': 'vcenter', # 垂直位置设置,居中
'font_size': 8, # '字体大小设置'
}
str_format1 = workbook.add_format(format1) #设置要调整的格式,可参阅链接文章实现更多样式选择
worksheet.write('B2', 'CRBC - Build King Joint Venture',str_format1)
worksheet.write('B3', 'MTR Contract 1500',str_format1)
worksheet.write('B4', 'TME Stations, Viaducts and River Crossing',str_format1)
worksheet.write('B6', 'Wong Chu Road Bridge Tilting Monitoring Record',str_format1)
worksheet.write('G3', 'AAA Value (degree)',str_format1)
worksheet.write('G4', 'Alert',str_format1)
worksheet.write('G5', 'Alarm',str_format1)
worksheet.write('G6', 'Action',str_format1)
format2 = {
# 'bold': True, # 字体加粗
'align': 'center', # 水平位置设置:居中
'valign': 'vcenter', # 垂直位置设置,居中
'font_size': 8, # '字体大小设置'
}
str_format2 = workbook.add_format(format2) #设置要调整的格式,可参阅链接文章实现更多样式选择
worksheet.write('H4', Alert,str_format2)
worksheet.write('H5',Alarm,str_format2)
worksheet.write('H6',Action,str_format2)
format3 = {
'bold': True, # 字体加粗
'align': 'center', # 水平位置设置:居中
'valign': 'vcenter', # 垂直位置设置,居中
'font_size': 11, # '字体大小设置'
}
str_format3 = workbook.add_format(format3) #设置要调整的格式,可参阅链接文章实现更多样式选择
worksheet.merge_range('B25:C25', 'PointID', str_format3)#合并单元格输入
worksheet.merge_range('D25:E25', 'TM9', str_format3)#合并单元格输入
worksheet.merge_range('F25:G25', 'TM10', str_format3)#合并单元格输入
worksheet.merge_range('H25:I25', 'TM10A', str_format3)#合并单元格输入
worksheet.merge_range('J25:K25', 'TM10B', str_format3)#合并单元格输入
worksheet.merge_range('L25:M25', 'Remarks', str_format3)#合并单元格输入
worksheet.merge_range('B24:C24', 'Initial Date', str_format3)#合并单元格输入
worksheet.merge_range('D24:E24', Initial_Date, str_format3)#合并单元格输入
worksheet.merge_range('F24:G24', Initial_Date, str_format3)#合并单元格输入
worksheet.merge_range('H24:I24', Initial_Date, str_format3)#合并单元格输入
worksheet.merge_range('J24:K24', Initial_Date, str_format3)#合并单元格输入
worksheet.merge_range('B23:C23', 'Initial Reading', str_format3)#合并单元格输入
worksheet.merge_range('D23:E23', Initial_Reading, str_format3)#合并单元格输入
worksheet.merge_range('F23:G23', Initial_Reading, str_format3)#合并单元格输入
worksheet.merge_range('H23:I23', Initial_Reading, str_format3)#合并单元格输入
worksheet.merge_range('J23:K23', Initial_Reading, str_format3)#合并单元格输
worksheet.write('D26','Degree',str_format3)
worksheet.write('F26','Degree',str_format3)
worksheet.write('H26','Degree',str_format3)
worksheet.write('J26','Degree',str_format3)
worksheet.write('E26','ΔDegree',str_format3)
worksheet.write('G26','ΔDegree',str_format3)
worksheet.write('I26','ΔDegree',str_format3)
worksheet.write('K26','ΔDegree',str_format3)
worksheet.merge_range('K7:M7',"Site Location", str_format3)#合并单元格
format4 = {
'border': 1, # 字体加粗
}
cell_format = workbook.add_format(format4) # 细边框
worksheet.conditional_format('B23:M56', {'type': 'no_errors', 'format': cell_format})
worksheet.conditional_format('K7:M20', {'type': 'no_errors', 'format': cell_format})
worksheet.conditional_format('G3:H6', {'type': 'no_errors', 'format': cell_format})
worksheet.insert_image('K8', './reportservice/location.jpg', {
'x_scale': 1.02, # 水平缩放50%
'y_scale': 1.2 # 垂直缩放30%
}) # 在B2单元格插入图片
worksheet.insert_image('J2', './reportservice/logo.png', {
'x_scale':1, # 水平缩放50%
'y_scale': 1.08 # 垂直缩放30%
}) # 在B2单元格插入图片
# 用openpyxl读取数据
# wb = load_workbook(output_file)
# ws = wb.active
# 获取矩形区域数据
# data = []
# for row in ws['B27':'M56']:
# row_data = [cell.value for cell in row]
# data.append(row_data)
# # 设置居中格式
# center_format = workbook.add_format({'align': 'center'})
# # 写入数据并应用格式
# for row_num, row_data in enumerate(data):
# for col_num, cell_data in enumerate(row_data):
# worksheet.write(row_num, col_num, cell_data, center_format)
# wb.close()
# workbook.close()
# 保存Excel文件
writer.close()
# # 1. 加载现有工作簿
# wb = load_workbook(output_file) # 替换为实际文件名
# # wb.read_excel('your_file.xls', engine='xlrd')
# ws = wb.active # 默认操作当前活动工作表
# # wb = xlrd.open_workbook(output_file)
# # ws = wb.sheet_by_index(0)
# # 2. 定义边框样式(可自定义)
# thin_border = Border(
# left=Side(style='thin'),
# right=Side(style='thin'),
# top=Side(style='thin'),
# bottom=Side(style='thin')
# )
# # 3. 设置矩形区域边框(示例:B2:D10)
# target_range = 'B26:M56'
# for row in ws[target_range]:
# for cell in row:
# cell.border = thin_border
# target_range = 'G3:H6'
# for row in ws[target_range]:
# for cell in row:
# cell.border = thin_border
# target_range = 'B23:M25'
# for row in ws[target_range]:
# for cell in row:
# cell.border = thin_border
# target_range = 'K7:M20'
# for row in ws[target_range]:
# for cell in row:
# cell.border = thin_border
# # # 设置连续单元格的范围(例如 A1:B2)
# # cell_range = "B25:M56"
# # start_col, start_row = openpyxl.utils.coordinate_to_tuple(cell_range.split(':')[0])
# # end_col, end_row = openpyxl.utils.coordinate_to_tuple(cell_range.split(':')[1])
# # 创建一个对齐对象,并设置居中对齐
# alignment = Alignment(horizontal='center', vertical='center')
# # 迭代范围内的每个单元格并应用对齐方式
# for col in range(1, 14):
# for row in range(27, 57):
# cell = ws.cell(row=row, column=col)
# cell.alignment = alignment
# # 插入logo图片
# img = Image('../reportservice/logo.png')
# ws.add_image(img, 'J2')
# img = Image('../reportservice/location.jpg')
# img.width, img.height = 1.15*img.width, 1.2*img.height # 将图片大小放大
# ws.add_image(img, 'K8')
# # #这3列放Alert、Alarm、Action数据用于生成折线图的警戒线
# # ws.column_dimensions.group("P", hidden=True) # 隐藏列
# # ws.column_dimensions.group("Q", hidden=True)
# # ws.column_dimensions.group("R", hidden=True)
# # 4. 保存修改(可另存为新文件)
# wb.save(output_file)
# # data = pd.read_excel(output_file, engine='openpyxl')
# # data.to_excel(output_file, index=False, engine='xlwt')
# # 读取xlsx文件
# df = pd.read_excel(output_file, engine='openpyxl')
# # # 将DataFrame写入xls文件
# with ExcelWriter('output.xls', engine='xlwt') as writer:
# df.to_excel(writer, index=False)
print("生成报告完成!")
#登录获取token***********************************************************************************************************************************************************************************************
def login():
url = "https://iot.raytue.com/prod-api/login"
payload = {
"username": "admin",
"password": "@raytue123",
"sourceType": 1
}
headers = {
'Content-Type': 'application/json'
}
# 发送POST请求
response = requests.post(url, headers=headers, data=json.dumps(payload))
# 检查请求是否成功
if response.status_code == 200:
# 解析并打印返回的数据
data = response.json()
# print(json.dumps(data, indent=4))
print("请求token成功!")
token= data["token"]
return token
else:
# 打印错误信息
print(f"请求失败,状态码:{response.status_code},响应内容:{response.text}")
return None
#************获取历史数据,字典字符数组输出*****************************************************************************************************************************************************************************************
def getResponseTilt(token,url,deviceId,serialNumber,beginTime,endTime):
beginTime = str(beginTime)
endTime = str(endTime)
# 定义请求的载荷
payload ={
"deviceId": deviceId,
"serialNumber": serialNumber,
"identifierList": [
{
"identifier": "tiltData_time",
"type": 1
},
{
"identifier": "tiltData_dRoll",
"type": 1
},
{
"identifier": "tiltData_dPitch",
"type": 1
}
],
"beginTime": beginTime,
"endTime": endTime
}
# 设置请求头,包括Authorization
headers = {
'Authorization': token,
'Content-Type': 'application/json'
}
# 发送POST请求
response = requests.post(url, headers=headers, data=json.dumps(payload))
# 检查请求是否成功
if response.status_code == 200:
# 解析并打印返回的数据
data1 = response.json()
# print(json.dumps(data1, indent=4))
print(f"成功获取设备历史数据,deviceId:{serialNumber}")
else:
# 打印错误信息
print(f"请求失败,状态码:{response.status_code},响应内容:{response.text}")
original_json = json.dumps(data1, indent=4)
# 将JSON字符串转换为Python字典
data_dict = json.loads(original_json)
# 初始化tiltData数组
tilt_data_array = []
# 遍历data数组
for item in data_dict['data']:
# 获取时间戳作为键(这里我们不需要它作为最终输出的一部分,但用它来访问内部列表)
timestamp_key = list(item.keys())[0]
# 获取与该时间戳关联的数据列表
data_list = item[timestamp_key]
# 初始化一个空字典来存储组合后的数据
combined_data = {}
# 遍历数据列表,将相关数据合并到字典中
for data in data_list:
for key, value in data.items():
combined_data[key] = value
# 将组合后的数据字典添加到tiltData数组中
tilt_data_array.append(combined_data)
return tilt_data_array
#********************筛选30天内10:30的数据,dataframe格式输出******************************************************************************************************************************************************************************
def getdfData(tilt_data_array):
tilt_data = json.dumps(tilt_data_array)
# 转换为DataFrame
df = pd.DataFrame(json.loads(tilt_data))
#print(df['tiltData_time'])
# 将字符串时间转换为datetime对象
df['tiltData_time'] =pd.to_datetime( df['tiltData_time'].str.slice(stop=-6))
# 获取当前日期和时间
current_time = datetime.now()
# print(current_time)
# 计算前30天的日期列表
dates = [current_time - timedelta(days=i) for i in range(1, 31)]
# 初始化一个空的DataFrame来存储结果
result_df = pd.DataFrame(columns=['Date', 'Time', 'dRoll', 'dPitch'])
# 遍历前30天的日期
for date in dates:
# 获取当天上午的数据
# print("--------------------------------------------------------------------")
# print(date.date())
day_data = df[(df['tiltData_time'].dt.date == date.date()) & (df['tiltData_time'].dt.hour < 12)]
# print(day_data)
# print("--------------------------------------------------------------------")
# print(day_data)
# 如果当天有数据,则找到最接近10点30分的数据
if not day_data.empty:
# 计算每个数据与10点30分的时间差
time_diffs = abs(day_data['tiltData_time']- pd.to_datetime(f'{date.date()} 10:30:00'))
# print("--------------------------------------------------------------------")
# print(time_diffs.idxmin())
# # 找到时间差最小的数据
closest_data = df.iloc[time_diffs.idxmin()]
# print(closest_data)
# 将数据添加到结果DataFrame中
result_df = result_df._append({
'Date':(closest_data['tiltData_time'].date()),
# 'Time': closest_data['tiltData_time'].time(),
'Time': 'AM',
'dRoll': closest_data['tiltData_dRoll'],
# 'dPitch': closest_data['tiltData_dPitch']#表格这一列固定为0,所以下一句代替
'dPitch': 0
}, ignore_index=True)
else:
result_df = result_df._append({#当天没有数据的,取值为空
'Date':date.date(),
# 'Time': '10:30:00',
'Time': 'AM',
'dRoll': '',
'dPitch':''
}, ignore_index=True)
# 按照时间从小到大排序
result_df = result_df.sort_values(by=['Date', 'Time'])
return result_df
#**********main()*******************************************************************************************************************************************************************************************
def job():
#登录获取token
token = login()
#历史数据接口地址
url = "https://iot.raytue.com/prod-api/data/center/deviceHistory"
#获取传感器数据字典格式数组
tilt_data_array_TM9 = getResponseTilt(token,url,277,"D23ANR8041JQI",(datetime.now()-timedelta(31)).strftime("%Y-%m-%d %H:%M:%S"),datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
#转换成dataframe数据
result_df_TM9 =getdfData(tilt_data_array_TM9)
tilt_data_array_TM10 = getResponseTilt(token,url,278,"D2367JBEYPY32",(datetime.now()-timedelta(31)).strftime("%Y-%m-%d %H:%M:%S"),datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
result_df_TM10 =getdfData(tilt_data_array_TM10)
tilt_data_array_TM10A = getResponseTilt(token,url,279,"D23AFZM72Q620",(datetime.now()-timedelta(31)).strftime("%Y-%m-%d %H:%M:%S"),datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
result_df_TM10A =getdfData(tilt_data_array_TM10A)
tilt_data_array_TM10B = getResponseTilt(token,url,280,"D2368757I1Y4G",(datetime.now()-timedelta(31)).strftime("%Y-%m-%d %H:%M:%S"),datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
result_df_TM10B =getdfData(tilt_data_array_TM10B)
# print(result_df_TM10B)
#生成当天日期命名的文件名
reportname ='./report/tilt_report_'+ str(datetime.now().date()).replace("-", "") + '.xlsx'
# # 将结果保存到Excel表格中
# result_df.to_excel(reportname, index=False)
# print(f"数据已保存到{reportname}文件中。")
#生成报告
create_excel_with_chart(result_df_TM9,result_df_TM10,result_df_TM10A,result_df_TM10B,reportname,25)
# job()
# 每天上午8点执行job函数
# 创建ConfigParser对象并读取INI文件
config = configparser.ConfigParser()
config.read('./config.ini') # 确保路径正确,替换为你的文件名
TILT_REPORT_TIME= config['REPORTTIME']['TILT_REPORT_TIME']
# print(TILT_REPORT_TIME)
print("开启tilt报告服务!")
schedule.every().day.at(TILT_REPORT_TIME).do(job)
while True:
schedule.run_pending()
time.sleep(60)
import requests # type: ignore
import json
from datetime import datetime, timedelta
import pandas as pd
import xlsxwriter # type: ignore
import openpyxl
from openpyxl import load_workbook
from openpyxl.styles import Border, Side,Alignment
from openpyxl.drawing.image import Image
from openpyxl.chart import LineChart, Reference, Series
from openpyxl.worksheet.dimensions import ColumnDimension
import schedule # type: ignore
import time
import configparser
#参考线
Alert=15
Alarm=20
Action=25
Alertneg=-15
Alarmneg=-20
Actionneg=-25
Initial_Date='2025-5-7'
Initial_Reading=0
#数据写入表格并生成曲线图*********************************************************************************************************************************************************************************
def create_excel_with_chart(result_df, result_df1,output_file,startrowNo):
print("开始生成报告......")
result_df['PVS']=pd.to_numeric(result_df['PVS'], errors='coerce')
result_df1['PVS']=pd.to_numeric(result_df1['PVS'], errors='coerce')
# 创建Excel写入器
writer = pd.ExcelWriter(output_file, engine='xlsxwriter')
# 将DataFrame写入Excel
result_df[['Date','Time']].to_excel(writer, sheet_name='Report', startrow = startrowNo,startcol = 1,index=False)
# result_df['dPitch']=0
result_df[['PVS']].to_excel(writer, sheet_name='Report', startrow = startrowNo,startcol = 3,index=False)
result_df1[['PVS']].to_excel(writer, sheet_name='Report', startrow = startrowNo,startcol =4,index=False)
# 获取工作簿和工作表对象
workbook = writer.book
worksheet = writer.sheets['Report']
worksheet2 = workbook.add_worksheet('Data')#6条参考线的数据放到Sheet2里面
worksheet.set_column('D:K', 10)
worksheet.set_column('B:B', 15)
worksheet.set_column('C:C', 5)
data_format = workbook.add_format({
'align': 'center',
'valign': 'vcenter'
})
for row_num in range(len(result_df)):
cell_value = result_df.iat[row_num, 0]
worksheet.write(row_num + 26, 0 + 1, str(cell_value), data_format)
for row_num in range(len(result_df)):
cell_value = result_df.iat[row_num,1]
worksheet.write(row_num + 26, 0 + 2, cell_value, data_format)
for row_num in range(len(result_df)):
cell_value = result_df.iat[row_num,2]
if str(cell_value) in ["NaN","nan","NAN"]:#如果有"NaN","nan","NAN",会报错,替换为none
cell_value=None
worksheet.write(row_num + 26, 0 + 3, cell_value, data_format)
for row_num in range(len(result_df1)):
cell_value = result_df1.iat[row_num,2]
if str(cell_value) in ["NaN","nan","NAN"]:#如果有"NaN","nan","NAN",会报错,替换为none
cell_value=None
worksheet.write(row_num + 26, 0 + 4, cell_value, data_format)
# 循环写入数据到指定范围
for row in range(27, 56 + 1):
worksheet2.write(row - 1, 16 - 1, Alert) # 注意:write方法中的行和列是从0开始计数的
# 循环写入数据到指定范围
for row in range(27, 56 + 1):
worksheet2.write(row - 1, 17 - 1, Alarm) # 注意:write方法中的行和列是从0开始计数的
# 循环写入数据到指定范围
for row in range(27, 56 + 1):
worksheet2.write(row - 1, 18 - 1, Action) # 注意:write方法中的行和列是从0开始计数的
# 循环写入数据到指定范围
for row in range(27, 56 + 1):
worksheet2.write(row - 1, 19 - 1, Alertneg) # 注意:write方法中的行和列是从0开始计数的
# 循环写入数据到指定范围
for row in range(27, 56 + 1):
worksheet2.write(row - 1, 20 - 1, Alarmneg) # 注意:write方法中的行和列是从0开始计数的
# 循环写入数据到指定范围
for row in range(27, 56 + 1):
worksheet2.write(row - 1, 21 - 1, Actionneg) # 注意:write方法中的行和列是从0开始计数的
# worksheet.set_column('P:U', 0)
# 创建折线图
chart = workbook.add_chart({'type': 'line'})
# 配置图表数据
max_row = len(result_df) +1 # +1因为第一行是标题
chart.add_series({
'name': 'VC22',
'categories': ['Report', 1+25, 1, max_row-1+25, 1], # Date列作为X轴
'values': ['Report', 1+25, 3, max_row-1+25, 3], # dPitch列作为Y轴
'marker': {'type': 'circle','size': 4}, # 系列标记
'line': {'width': 0.8},
})
chart.add_series({
'name': 'VC104',
'categories': ['Report', 1+25, 1, max_row-1+25, 1], # Date列作为X轴
'values': ['Report', 1+25, 4, max_row-1+25, 4], # dPitch列作为Y轴
'marker': {'type': 'circle','size': 4}, # 系列标记
'line': {'width': 0.8},
})
chart.add_series({
'name': 'Alert',
'categories': ['Report', 1+25, 1, max_row-1+25, 1], # Date列作为X轴
'values': ['Data', 1+25, 15, max_row-1+25, 15], # dPitch列作为Y轴
# 'marker': {'type': 'circle','size': 4}, # 系列标记
'line': {'width': 1.5,'color':'green'},
})
chart.add_series({
'name': 'Alarm',
'categories': ['Report', 1+25, 1, max_row-1+25, 1], # Date列作为X轴
'values': ['Data', 1+25, 16, max_row-1+25, 16], # dPitch列作为Y轴
# 'marker': {'type': 'circle','size': 4}, # 系列标记
'line': {'width': 1.5,'color':'yellow'},
})
chart.add_series({
'name': 'Action',
'categories': ['Report', 1+25, 1, max_row-1+25, 1], # Date列作为X轴
'values': ['Data', 1+25, 17, max_row-1+25, 17], # dPitch列作为Y轴
# 'marker': {'type': 'circle','size': 4}, # 系列标记
'line': {'width': 1.5,'color':'red'},
})
chart.add_series({
'name': 'Alert',
'categories': ['Report', 1+25, 1, max_row-1+25, 1], # Date列作为X轴
'values': ['Data', 1+25, 18, max_row-1+25, 18], # dPitch列作为Y轴
# 'marker': {'type': 'circle','size': 4}, # 系列标记
'line': {'width': 1.5,'color':'green'},
})
chart.add_series({
'name': 'Alarm',
'categories': ['Report', 1+25, 1, max_row-1+25, 1], # Date列作为X轴
'values': ['Data', 1+25, 19, max_row-1+25, 19], # dPitch列作为Y轴
# 'marker': {'type': 'circle','size': 4}, # 系列标记
'line': {'width': 1.5,'color':'yellow'},
})
chart.add_series({
'name': 'Action',
'categories': ['Report', 1+25, 1, max_row-1+25, 1], # Date列作为X轴
'values': ['Data', 1+25, 20, max_row-1+25, 20], # dPitch列作为Y轴
# 'marker': {'type': 'circle','size': 4}, # 系列标记
'line': {'width': 1.5,'color':'red'},
})
# 设置图表标题和轴标签
# chart.set_title({'name': 'dPitch over Time'})
chart.set_size({'width': 670, 'height': 315})
chart.set_x_axis({'num_font': {'rotation': -60},'name_font': {'size': 5,},})
# chart.set_x_axis({'crossing': 'min'})
chart.set_y_axis({
'crossing': 'min',
'major_gridlines': {
'visible': True,
'line': {'color':'#eee2e1'},
# 'line_dash_type': 'dash-dot' # 设置线型为点划线
}})
# chart.set_x_axis({'position_axis': 'on_tick', 'crossing': 'min','date_axis': True})
# 设置日期格式的X轴
# chart.set_x_axis({'date_axis': True})
chart.set_legend({'delete_series': [2,3,4,5,6,7]})
# 将图表插入工作表
worksheet.insert_chart('B7', chart)
format1 = {
'bold': True, # 字体加粗
# 'align': 'center', # 水平位置设置:居中
'valign': 'vcenter', # 垂直位置设置,居中
'font_size': 8, # '字体大小设置'
}
str_format1 = workbook.add_format(format1) #设置要调整的格式,可参阅链接文章实现更多样式选择
worksheet.write('B2', 'CRBC - Build King Joint Venture',str_format1)
worksheet.write('B3', 'MTR Contract 1500',str_format1)
worksheet.write('B4', 'TME Stations, Viaducts and River Crossing',str_format1)
worksheet.write('B6', 'Wong Chu Road Bridge Vibration Monitoring Record',str_format1)
worksheet.write('G3', 'AAA Value (degree)',str_format1)
worksheet.write('G4', 'Alert',str_format1)
worksheet.write('G5', 'Alarm',str_format1)
worksheet.write('G6', 'Action',str_format1)
format2 = {
# 'bold': True, # 字体加粗
'align': 'center', # 水平位置设置:居中
'valign': 'vcenter', # 垂直位置设置,居中
'font_size': 8, # '字体大小设置'
}
str_format2 = workbook.add_format(format2) #设置要调整的格式,可参阅链接文章实现更多样式选择
worksheet.write('H4', Alert,str_format2)
worksheet.write('H5',Alarm,str_format2)
worksheet.write('H6',Action,str_format2)
format3 = {
'bold': True, # 字体加粗
'align': 'center', # 水平位置设置:居中
'valign': 'vcenter', # 垂直位置设置,居中
'font_size': 11, # '字体大小设置'
}
str_format3 = workbook.add_format(format3) #设置要调整的格式,可参阅链接文章实现更多样式选择
worksheet.merge_range('B25:C25', 'PointID', str_format3)#合并单元格输入
worksheet.write('D25', 'VC22', str_format3)#合并单元格输入
worksheet.write('E25', 'VC104', str_format3)#合并单元格输入
worksheet.merge_range('L25:M26', 'Remarks', str_format3)#合并单元格输入
worksheet.write('D26','mm/s',str_format3)
worksheet.write('E26','mm/s',str_format3)
worksheet.merge_range('K7:M7',"Site Location", str_format3)#合并单元格
format4 = {
'border': 1, # 字体加粗
}
cell_format = workbook.add_format(format4) # 细边框
worksheet.conditional_format('B25:M56', {'type': 'no_errors', 'format': cell_format})
worksheet.conditional_format('K7:M20', {'type': 'no_errors', 'format': cell_format})
worksheet.conditional_format('G3:H6', {'type': 'no_errors', 'format': cell_format})
worksheet.insert_image('K8', './reportservice/location.jpg', {
'x_scale': 1.02, # 水平缩放50%
'y_scale': 1.2 # 垂直缩放30%
}) # 在B2单元格插入图片
worksheet.insert_image('J2', './reportservice/logo.png', {
'x_scale':1, # 水平缩放50%
'y_scale': 1.08 # 垂直缩放30%
}) # 在B2单元格插入图片
# # 保存Excel文件
writer.close()
# # 1. 加载现有工作簿
# wb = load_workbook(output_file) # 替换为实际文件名
# ws = wb.active # 默认操作当前活动工作表
# # 2. 定义边框样式(可自定义)
# thin_border = Border(
# left=Side(style='thin'),
# right=Side(style='thin'),
# top=Side(style='thin'),
# bottom=Side(style='thin')
# )
# # 3. 设置矩形区域边框(示例:B2:D10)
# target_range = 'B26:M56'
# for row in ws[target_range]:
# for cell in row:
# cell.border = thin_border
# target_range = 'G3:H6'
# for row in ws[target_range]:
# for cell in row:
# cell.border = thin_border
# target_range = 'B25:M25'
# for row in ws[target_range]:
# for cell in row:
# cell.border = thin_border
# target_range = 'K7:M20'
# for row in ws[target_range]:
# for cell in row:
# cell.border = thin_border
# # # 设置连续单元格的范围(例如 A1:B2)
# # cell_range = "B25:M56"
# # start_col, start_row = openpyxl.utils.coordinate_to_tuple(cell_range.split(':')[0])
# # end_col, end_row = openpyxl.utils.coordinate_to_tuple(cell_range.split(':')[1])
# # 创建一个对齐对象,并设置居中对齐
# alignment = Alignment(horizontal='center', vertical='center')
# # 迭代范围内的每个单元格并应用对齐方式
# for col in range(1, 14):
# for row in range(27, 57):
# cell = ws.cell(row=row, column=col)
# cell.alignment = alignment
# # 插入logo图片
# img = Image('./reportservice/logo.png')
# ws.add_image(img, 'J2')
# img = Image('./reportservice/location.jpg')
# img.width, img.height = 1.15*img.width, 1.2*img.height # 将图片大小放大
# ws.add_image(img, 'K8')
# # #这3列放Alert、Alarm、Action数据用于生成折线图的警戒线
# # ws.column_dimensions.group("P", hidden=True) # 隐藏列
# # ws.column_dimensions.group("Q", hidden=True)
# # ws.column_dimensions.group("R", hidden=True)
# # 4. 保存修改(可另存为新文件)
# wb.save(output_file)
print("生成报告完成!")
#登录获取token***********************************************************************************************************************************************************************************************
def login():
url = "https://iot.raytue.com/prod-api/login"
payload = {
"username": "admin",
"password": "@raytue123",
"sourceType": 1
}
headers = {
'Content-Type': 'application/json'
}
# 发送POST请求
response = requests.post(url, headers=headers, data=json.dumps(payload))
# 检查请求是否成功
if response.status_code == 200:
# 解析并打印返回的数据
data = response.json()
# print(json.dumps(data, indent=4))
print("请求token成功!")
token= data["token"]
return token
else:
# 打印错误信息
print(f"请求失败,状态码:{response.status_code},响应内容:{response.text}")
return None
#************获取历史数据,字典字符数组输出*****************************************************************************************************************************************************************************************
def getResponseTilt(token,url,deviceId,serialNumber,beginTime,endTime):
beginTime = str(beginTime)
endTime = str(endTime)
# 定义请求的载荷
payload ={
"deviceId": deviceId,
"serialNumber": serialNumber,
"identifierList": [
{
"identifier": "vibrationData_time",
"type": 1
},
{
"identifier": "vibrationData_PVS",
"type": 1
}
],
"beginTime": beginTime,
"endTime": endTime
}
# 设置请求头,包括Authorization
headers = {
'Authorization': token,
'Content-Type': 'application/json'
}
# 发送POST请求
response = requests.post(url, headers=headers, data=json.dumps(payload))
# 检查请求是否成功
if response.status_code == 200:
# 解析并打印返回的数据
data1 = response.json()
# print(json.dumps(data1, indent=4))
print(f"成功获取设备历史数据,deviceId:{serialNumber}")
else:
# 打印错误信息
print(f"请求失败,状态码:{response.status_code},响应内容:{response.text}")
original_json = json.dumps(data1, indent=4)
# 将JSON字符串转换为Python字典
data_dict = json.loads(original_json)
# 初始化tiltData数组
tilt_data_array = []
# 遍历data数组
for item in data_dict['data']:
# 获取时间戳作为键(这里我们不需要它作为最终输出的一部分,但用它来访问内部列表)
timestamp_key = list(item.keys())[0]
# 获取与该时间戳关联的数据列表
data_list = item[timestamp_key]
# 初始化一个空字典来存储组合后的数据
combined_data = {}
# 遍历数据列表,将相关数据合并到字典中
for data in data_list:
for key, value in data.items():
combined_data[key] = value
# 将组合后的数据字典添加到tiltData数组中
tilt_data_array.append(combined_data)
return tilt_data_array
#********************筛选30天内10:30的数据,dataframe格式输出******************************************************************************************************************************************************************************
def getdfData(tilt_data_array):
tilt_data = json.dumps(tilt_data_array)
# 转换为DataFrame
df = pd.DataFrame(json.loads(tilt_data))
#print(df['tiltData_time'])
# 将字符串时间转换为datetime对象
df['vibrationData_time'] =pd.to_datetime( df['vibrationData_time'].str.slice(stop=-6))
# 获取当前日期和时间
current_time = datetime.now()
# print(current_time)
# 计算前30天的日期列表
dates = [current_time - timedelta(days=i) for i in range(1, 31)]
# 初始化一个空的DataFrame来存储结果
result_df = pd.DataFrame(columns=['Date', 'Time', 'PVS'])
# 遍历前30天的日期
for date in dates:
# 获取当天上午的数据
# print("--------------------------------------------------------------------")
# print(date.date())
day_data = df[(df['vibrationData_time'].dt.date == date.date()) & (df['vibrationData_time'].dt.hour < 12)]
# print(day_data)
# print("--------------------------------------------------------------------")
# print(day_data)
# 如果当天有数据,则找到最接近10点30分的数据
if not day_data.empty:
# 计算每个数据与10点30分的时间差
time_diffs = abs(day_data['vibrationData_time']- pd.to_datetime(f'{date.date()} 10:30:00'))
# print("--------------------------------------------------------------------")
# print(time_diffs.idxmin())
# # 找到时间差最小的数据
closest_data = df.iloc[time_diffs.idxmin()]
# print(closest_data)
# 将数据添加到结果DataFrame中
result_df = result_df._append({
'Date': closest_data['vibrationData_time'].date(),
# 'Time': closest_data['tiltData_time'].time(),
'Time': 'AM',
'PVS': closest_data['vibrationData_PVS'],
}, ignore_index=True)
else:
result_df = result_df._append({#当天没有数据的,取值为空
'Date':date.date(),
# 'Time': '10:30:00',
'Time': 'AM',
'PVS': None,
}, ignore_index=True)
# 按照时间从小到大排序
result_df = result_df.sort_values(by=['Date', 'Time'])
return result_df
#**********main()*******************************************************************************************************************************************************************************************
def job():
#登录获取token
token = login()
#历史数据接口地址
url = "https://iot.raytue.com/prod-api/data/center/deviceHistory"
#获取传感器数据字典格式数组
vibration_data_array_VC22 = getResponseTilt(token,url,285,"D239F9D04LVM9",(datetime.now()-timedelta(31)).strftime("%Y-%m-%d %H:%M:%S"),datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
#转换成dataframe数据
result_df__VC22 =getdfData(vibration_data_array_VC22)
vibration_data_array_VC104 = getResponseTilt(token,url,284,"D23538EQB38P9",(datetime.now()-timedelta(31)).strftime("%Y-%m-%d %H:%M:%S"),datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
result_df__VC104 =getdfData(vibration_data_array_VC104)
# print(result_df_TM10B)
#生成当天日期命名的文件名
reportname ='./report/vibration_report_'+ str(datetime.now().date()).replace("-", "") + '.xlsx'
# # 将结果保存到Excel表格中
# result_df.to_excel(reportname, index=False)
# print(f"数据已保存到{reportname}文件中。")
#生成报告
create_excel_with_chart(result_df__VC22,result_df__VC104,reportname,25)
# job()
# 每天上午8点执行job函数
print("开启vibration报告服务!")
# 创建ConfigParser对象并读取INI文件
config = configparser.ConfigParser()
config.read('./config.ini') # 确保路径正确,替换为你的文件名
VIBRATION_REPORT_TIME= config['REPORTTIME']['VIBRATION_REPORT_TIME']
print("开启tilt报告服务!")
schedule.every().day.at(VIBRATION_REPORT_TIME).do(job)
while True:
schedule.run_pending()
time.sleep(60)
TM10B 113.981321 22.389807
TM10A 113.9812 22.389619
TM10 113.981541 22.389464
TM9 113.981685 22.389636
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment