Refactor dataset variable schemas and UI handling in Dashboard component for improved clarity and external schema compatibility; streamline variable configuration process.

This commit is contained in:
Miguel 2025-08-25 18:37:43 +02:00
parent 551ec8b4a5
commit e77a5c3932
6 changed files with 697 additions and 987 deletions

View File

@ -1,465 +1,5 @@
{
"events": [
{
"timestamp": "2025-08-25T14:02:29.981110",
"level": "info",
"event_type": "performance_report",
"message": "Performance report: 40 points saved, 0 lost, 0.0% CPU",
"details": {
"duration": 10.027307510375977,
"points_saved": 40,
"points_rate": 3.989106742623493,
"variables_saved": 120,
"udp_points_sent": 0,
"points_lost": 0,
"cpu_average": 0.0,
"cpu_max": 0.0,
"delay_average": 0.0,
"delay_max": 0.0,
"read_errors": 0,
"csv_errors": 0,
"udp_errors": 0,
"read_time_avg": 0.027162200212478636,
"csv_write_time_avg": 0.0
}
},
{
"timestamp": "2025-08-25T14:02:40.008028",
"level": "info",
"event_type": "performance_report",
"message": "Performance report: 40 points saved, 0 lost, 0.2% CPU",
"details": {
"duration": 10.026918172836304,
"points_saved": 40,
"points_rate": 3.9892616365777362,
"variables_saved": 120,
"udp_points_sent": 0,
"points_lost": 0,
"cpu_average": 0.2,
"cpu_max": 0.2,
"delay_average": 0.0,
"delay_max": 0.0,
"read_errors": 0,
"csv_errors": 0,
"udp_errors": 0,
"read_time_avg": 0.02955700159072876,
"csv_write_time_avg": 3.319978713989258e-06
}
},
{
"timestamp": "2025-08-25T14:02:50.034470",
"level": "info",
"event_type": "performance_report",
"message": "Performance report: 40 points saved, 0 lost, 0.2% CPU",
"details": {
"duration": 10.02644157409668,
"points_saved": 40,
"points_rate": 3.9894512628827394,
"variables_saved": 120,
"udp_points_sent": 0,
"points_lost": 0,
"cpu_average": 0.2,
"cpu_max": 0.2,
"delay_average": 0.0,
"delay_max": 0.0,
"read_errors": 0,
"csv_errors": 0,
"udp_errors": 0,
"read_time_avg": 0.028314751386642457,
"csv_write_time_avg": 0.0
}
},
{
"timestamp": "2025-08-25T14:03:00.060741",
"level": "info",
"event_type": "performance_report",
"message": "Performance report: 40 points saved, 0 lost, 0.2% CPU",
"details": {
"duration": 10.026271104812622,
"points_saved": 40,
"points_rate": 3.989519092576696,
"variables_saved": 120,
"udp_points_sent": 0,
"points_lost": 0,
"cpu_average": 0.2,
"cpu_max": 0.2,
"delay_average": 0.0,
"delay_max": 0.0,
"read_errors": 0,
"csv_errors": 0,
"udp_errors": 0,
"read_time_avg": 0.029216140508651733,
"csv_write_time_avg": 0.0
}
},
{
"timestamp": "2025-08-25T14:03:10.091122",
"level": "info",
"event_type": "performance_report",
"message": "Performance report: 40 points saved, 0 lost, 0.0% CPU",
"details": {
"duration": 10.030381202697754,
"points_saved": 40,
"points_rate": 3.987884327790221,
"variables_saved": 120,
"udp_points_sent": 0,
"points_lost": 0,
"cpu_average": 0.0,
"cpu_max": 0.0,
"delay_average": 0.0,
"delay_max": 0.0,
"read_errors": 0,
"csv_errors": 0,
"udp_errors": 0,
"read_time_avg": 0.03202961683273316,
"csv_write_time_avg": 0.0
}
},
{
"timestamp": "2025-08-25T14:03:20.121878",
"level": "info",
"event_type": "performance_report",
"message": "Performance report: 40 points saved, 0 lost, 0.2% CPU",
"details": {
"duration": 10.030755996704102,
"points_saved": 40,
"points_rate": 3.987735322556263,
"variables_saved": 120,
"udp_points_sent": 0,
"points_lost": 0,
"cpu_average": 0.2,
"cpu_max": 0.2,
"delay_average": 0.0,
"delay_max": 0.0,
"read_errors": 0,
"csv_errors": 0,
"udp_errors": 0,
"read_time_avg": 0.028543853759765626,
"csv_write_time_avg": 2.3484230041503905e-06
}
},
{
"timestamp": "2025-08-25T14:03:30.148923",
"level": "info",
"event_type": "performance_report",
"message": "Performance report: 40 points saved, 0 lost, 0.2% CPU",
"details": {
"duration": 10.027044773101807,
"points_saved": 40,
"points_rate": 3.98921126863845,
"variables_saved": 120,
"udp_points_sent": 0,
"points_lost": 0,
"cpu_average": 0.2,
"cpu_max": 0.2,
"delay_average": 0.0,
"delay_max": 0.0,
"read_errors": 0,
"csv_errors": 0,
"udp_errors": 0,
"read_time_avg": 0.03223702907562256,
"csv_write_time_avg": 0.0
}
},
{
"timestamp": "2025-08-25T14:03:40.177615",
"level": "info",
"event_type": "performance_report",
"message": "Performance report: 40 points saved, 0 lost, 0.2% CPU",
"details": {
"duration": 10.02869176864624,
"points_saved": 40,
"points_rate": 3.988556127037051,
"variables_saved": 120,
"udp_points_sent": 0,
"points_lost": 0,
"cpu_average": 0.2,
"cpu_max": 0.2,
"delay_average": 0.0,
"delay_max": 0.0,
"read_errors": 0,
"csv_errors": 0,
"udp_errors": 0,
"read_time_avg": 0.029716211557388305,
"csv_write_time_avg": 0.0
}
},
{
"timestamp": "2025-08-25T14:03:50.205219",
"level": "info",
"event_type": "performance_report",
"message": "Performance report: 40 points saved, 0 lost, 0.2% CPU",
"details": {
"duration": 10.026633262634277,
"points_saved": 40,
"points_rate": 3.9893749928069955,
"variables_saved": 120,
"udp_points_sent": 0,
"points_lost": 0,
"cpu_average": 0.2,
"cpu_max": 0.2,
"delay_average": 0.0,
"delay_max": 0.0,
"read_errors": 0,
"csv_errors": 0,
"udp_errors": 0,
"read_time_avg": 0.034369897842407224,
"csv_write_time_avg": 0.0
}
},
{
"timestamp": "2025-08-25T14:04:00.234789",
"level": "info",
"event_type": "performance_report",
"message": "Performance report: 40 points saved, 0 lost, 0.2% CPU",
"details": {
"duration": 10.030540943145752,
"points_saved": 40,
"points_rate": 3.987820819108815,
"variables_saved": 120,
"udp_points_sent": 0,
"points_lost": 0,
"cpu_average": 0.2,
"cpu_max": 0.2,
"delay_average": 0.0,
"delay_max": 0.0,
"read_errors": 0,
"csv_errors": 0,
"udp_errors": 0,
"read_time_avg": 0.030520808696746827,
"csv_write_time_avg": 0.0
}
},
{
"timestamp": "2025-08-25T14:04:10.261749",
"level": "info",
"event_type": "performance_report",
"message": "Performance report: 40 points saved, 0 lost, 0.2% CPU",
"details": {
"duration": 10.026959896087646,
"points_saved": 40,
"points_rate": 3.98924503683388,
"variables_saved": 120,
"udp_points_sent": 0,
"points_lost": 0,
"cpu_average": 0.2,
"cpu_max": 0.2,
"delay_average": 0.0,
"delay_max": 0.0,
"read_errors": 0,
"csv_errors": 0,
"udp_errors": 0,
"read_time_avg": 0.03205314874649048,
"csv_write_time_avg": 0.0
}
},
{
"timestamp": "2025-08-25T14:04:20.290427",
"level": "info",
"event_type": "performance_report",
"message": "Performance report: 40 points saved, 0 lost, 0.2% CPU",
"details": {
"duration": 10.028677940368652,
"points_saved": 40,
"points_rate": 3.9885616267511335,
"variables_saved": 120,
"udp_points_sent": 0,
"points_lost": 0,
"cpu_average": 0.2,
"cpu_max": 0.2,
"delay_average": 0.0,
"delay_max": 0.0,
"read_errors": 0,
"csv_errors": 0,
"udp_errors": 0,
"read_time_avg": 0.031254750490188596,
"csv_write_time_avg": 0.0
}
},
{
"timestamp": "2025-08-25T14:04:30.317707",
"level": "info",
"event_type": "performance_report",
"message": "Performance report: 40 points saved, 0 lost, 0.2% CPU",
"details": {
"duration": 10.0272798538208,
"points_saved": 40,
"points_rate": 3.98911774510396,
"variables_saved": 120,
"udp_points_sent": 0,
"points_lost": 0,
"cpu_average": 0.2,
"cpu_max": 0.2,
"delay_average": 0.0,
"delay_max": 0.0,
"read_errors": 0,
"csv_errors": 0,
"udp_errors": 0,
"read_time_avg": 0.03653101325035095,
"csv_write_time_avg": 0.0
}
},
{
"timestamp": "2025-08-25T14:04:40.347341",
"level": "info",
"event_type": "performance_report",
"message": "Performance report: 40 points saved, 0 lost, 0.3% CPU",
"details": {
"duration": 10.029634714126587,
"points_saved": 40,
"points_rate": 3.98818113920546,
"variables_saved": 120,
"udp_points_sent": 0,
"points_lost": 0,
"cpu_average": 0.3,
"cpu_max": 0.3,
"delay_average": 0.0,
"delay_max": 0.0,
"read_errors": 0,
"csv_errors": 0,
"udp_errors": 0,
"read_time_avg": 0.03144925832748413,
"csv_write_time_avg": 0.0
}
},
{
"timestamp": "2025-08-25T14:04:50.373515",
"level": "info",
"event_type": "performance_report",
"message": "Performance report: 40 points saved, 0 lost, 0.2% CPU",
"details": {
"duration": 10.026173830032349,
"points_saved": 40,
"points_rate": 3.9895577992258833,
"variables_saved": 120,
"udp_points_sent": 0,
"points_lost": 0,
"cpu_average": 0.2,
"cpu_max": 0.2,
"delay_average": 0.0,
"delay_max": 0.0,
"read_errors": 0,
"csv_errors": 0,
"udp_errors": 0,
"read_time_avg": 0.03237649202346802,
"csv_write_time_avg": 0.0
}
},
{
"timestamp": "2025-08-25T14:05:00.400342",
"level": "info",
"event_type": "performance_report",
"message": "Performance report: 40 points saved, 0 lost, 0.2% CPU",
"details": {
"duration": 10.026827096939087,
"points_saved": 40,
"points_rate": 3.989297871927092,
"variables_saved": 120,
"udp_points_sent": 0,
"points_lost": 0,
"cpu_average": 0.2,
"cpu_max": 0.2,
"delay_average": 0.0,
"delay_max": 0.0,
"read_errors": 0,
"csv_errors": 0,
"udp_errors": 0,
"read_time_avg": 0.031496965885162355,
"csv_write_time_avg": 0.0
}
},
{
"timestamp": "2025-08-25T14:05:10.427694",
"level": "info",
"event_type": "performance_report",
"message": "Performance report: 40 points saved, 0 lost, 0.2% CPU",
"details": {
"duration": 10.026376724243164,
"points_saved": 40,
"points_rate": 3.9894770663546337,
"variables_saved": 120,
"udp_points_sent": 0,
"points_lost": 0,
"cpu_average": 0.2,
"cpu_max": 0.2,
"delay_average": 0.0,
"delay_max": 0.0,
"read_errors": 0,
"csv_errors": 0,
"udp_errors": 0,
"read_time_avg": 0.03402681946754456,
"csv_write_time_avg": 0.0
}
},
{
"timestamp": "2025-08-25T14:05:20.461769",
"level": "info",
"event_type": "performance_report",
"message": "Performance report: 40 points saved, 0 lost, 0.3% CPU",
"details": {
"duration": 10.035049676895142,
"points_saved": 40,
"points_rate": 3.986029096806231,
"variables_saved": 120,
"udp_points_sent": 0,
"points_lost": 0,
"cpu_average": 0.3,
"cpu_max": 0.3,
"delay_average": 0.0,
"delay_max": 0.0,
"read_errors": 0,
"csv_errors": 0,
"udp_errors": 0,
"read_time_avg": 0.032566672563552855,
"csv_write_time_avg": 0.0
}
},
{
"timestamp": "2025-08-25T14:05:30.491522",
"level": "info",
"event_type": "performance_report",
"message": "Performance report: 40 points saved, 0 lost, 0.2% CPU",
"details": {
"duration": 10.02975344657898,
"points_saved": 40,
"points_rate": 3.988133927025244,
"variables_saved": 120,
"udp_points_sent": 0,
"points_lost": 0,
"cpu_average": 0.2,
"cpu_max": 0.2,
"delay_average": 0.0,
"delay_max": 0.0,
"read_errors": 0,
"csv_errors": 0,
"udp_errors": 0,
"read_time_avg": 0.03259522318840027,
"csv_write_time_avg": 0.0
}
},
{
"timestamp": "2025-08-25T14:05:40.519035",
"level": "info",
"event_type": "performance_report",
"message": "Performance report: 40 points saved, 0 lost, 0.2% CPU",
"details": {
"duration": 10.027512550354004,
"points_saved": 40,
"points_rate": 3.989025174402586,
"variables_saved": 120,
"udp_points_sent": 0,
"points_lost": 0,
"cpu_average": 0.2,
"cpu_max": 0.2,
"delay_average": 0.0,
"delay_max": 0.0,
"read_errors": 0,
"csv_errors": 0,
"udp_errors": 0,
"read_time_avg": 0.034430992603302,
"csv_write_time_avg": 0.0
}
},
{
"timestamp": "2025-08-25T14:05:50.550723",
"level": "info",
@ -21248,8 +20788,311 @@
"event_type": "application_started",
"message": "Application initialization completed successfully",
"details": {}
},
{
"timestamp": "2025-08-25T18:06:38.975607",
"level": "info",
"event_type": "application_started",
"message": "Application initialization completed successfully",
"details": {}
},
{
"timestamp": "2025-08-25T18:06:40.012005",
"level": "info",
"event_type": "application_started",
"message": "Application initialization completed successfully",
"details": {}
},
{
"timestamp": "2025-08-25T18:14:29.288722",
"level": "info",
"event_type": "application_started",
"message": "Application initialization completed successfully",
"details": {}
},
{
"timestamp": "2025-08-25T18:14:30.332808",
"level": "info",
"event_type": "application_started",
"message": "Application initialization completed successfully",
"details": {}
},
{
"timestamp": "2025-08-25T18:37:19.932684",
"level": "info",
"event_type": "config_reload",
"message": "Dataset configuration reloaded from files with CSV header validation",
"details": {
"datasets_count": 1,
"active_datasets_count": 1,
"csv_recording_active": false
}
},
{
"timestamp": "2025-08-25T18:39:46.281395",
"level": "info",
"event_type": "application_started",
"message": "Application initialization completed successfully",
"details": {}
},
{
"timestamp": "2025-08-25T18:39:47.318112",
"level": "info",
"event_type": "application_started",
"message": "Application initialization completed successfully",
"details": {}
},
{
"timestamp": "2025-08-25T18:39:53.767096",
"level": "info",
"event_type": "dataset_activated",
"message": "Dataset activated: DAR",
"details": {
"dataset_id": "DAR",
"variables_count": 4,
"streaming_count": 3,
"prefix": "dar"
}
},
{
"timestamp": "2025-08-25T18:39:53.793213",
"level": "info",
"event_type": "csv_recording_started",
"message": "🔥 CRITICAL PRIORITY: CSV recording started with MAXIMUM PRIORITY, async buffering, and performance monitoring: 1 datasets activated",
"details": {
"activated_datasets": 1,
"total_datasets": 1,
"priority": "CRITICAL",
"recording_protection": true,
"performance_monitoring": true,
"async_csv_buffering": true,
"csv_flush_interval": 5.0
}
},
{
"timestamp": "2025-08-25T18:39:53.825723",
"level": "info",
"event_type": "plc_connection",
"message": "Successfully connected to PLC 10.1.33.11 and auto-started CSV recording for 1 datasets",
"details": {
"ip": "10.1.33.11",
"rack": 0,
"slot": 2,
"symbols_path": "C:/Users/migue/Downloads/symSAE452.asc",
"auto_started_recording": true,
"recording_datasets": 1,
"dataset_names": [
"DAR"
]
}
},
{
"timestamp": "2025-08-25T18:40:03.766490",
"level": "info",
"event_type": "performance_report",
"message": "Performance report: 20 points saved, 0 lost, 0.0% CPU",
"details": {
"duration": 17.452539920806885,
"points_saved": 20,
"points_rate": 1.1459650051369337,
"variables_saved": 80,
"udp_points_sent": 0,
"points_lost": 0,
"cpu_average": 0.0,
"cpu_max": 0.0,
"delay_average": 0.0,
"delay_max": 0.0,
"read_errors": 0,
"csv_errors": 0,
"udp_errors": 0,
"read_time_avg": 0.033115696907043454,
"csv_write_time_avg": 0.0
}
},
{
"timestamp": "2025-08-25T18:40:10.740922",
"level": "info",
"event_type": "udp_streaming_started",
"message": "UDP streaming to PlotJuggler started",
"details": {
"udp_host": "127.0.0.1",
"udp_port": 9870,
"datasets_available": 1
}
},
{
"timestamp": "2025-08-25T18:40:13.805084",
"level": "info",
"event_type": "performance_report",
"message": "Performance report: 20 points saved, 0 lost, 1.2% CPU",
"details": {
"duration": 10.038594007492065,
"points_saved": 20,
"points_rate": 1.9923108739205386,
"variables_saved": 80,
"udp_points_sent": 18,
"points_lost": 0,
"cpu_average": 1.2,
"cpu_max": 1.2,
"delay_average": 0.0,
"delay_max": 0.0,
"read_errors": 0,
"csv_errors": 0,
"udp_errors": 0,
"read_time_avg": 0.03423429727554321,
"csv_write_time_avg": 0.0
}
},
{
"timestamp": "2025-08-25T18:40:21.249789",
"level": "info",
"event_type": "config_reload",
"message": "Dataset configuration reloaded from files with CSV header validation",
"details": {
"datasets_count": 1,
"active_datasets_count": 1,
"csv_recording_active": true
}
},
{
"timestamp": "2025-08-25T18:40:23.859171",
"level": "info",
"event_type": "performance_report",
"message": "Performance report: 21 points saved, 0 lost, 1.6% CPU",
"details": {
"duration": 10.054086923599243,
"points_saved": 21,
"points_rate": 2.088702848859223,
"variables_saved": 84,
"udp_points_sent": 63,
"points_lost": 0,
"cpu_average": 1.6,
"cpu_max": 1.6,
"delay_average": 0.0,
"delay_max": 0.0,
"read_errors": 0,
"csv_errors": 0,
"udp_errors": 0,
"read_time_avg": 0.035013005847022646,
"csv_write_time_avg": 0.0
}
},
{
"timestamp": "2025-08-25T18:40:33.917226",
"level": "info",
"event_type": "performance_report",
"message": "Performance report: 20 points saved, 0 lost, 1.7% CPU",
"details": {
"duration": 10.058055639266968,
"points_saved": 20,
"points_rate": 1.988455892202402,
"variables_saved": 80,
"udp_points_sent": 60,
"points_lost": 0,
"cpu_average": 1.7,
"cpu_max": 1.7,
"delay_average": 0.0,
"delay_max": 0.0,
"read_errors": 0,
"csv_errors": 0,
"udp_errors": 0,
"read_time_avg": 0.031715011596679686,
"csv_write_time_avg": 0.0
}
},
{
"timestamp": "2025-08-25T18:40:43.953703",
"level": "info",
"event_type": "performance_report",
"message": "Performance report: 20 points saved, 0 lost, 0.8% CPU",
"details": {
"duration": 10.036476373672485,
"points_saved": 20,
"points_rate": 1.9927312390694867,
"variables_saved": 80,
"udp_points_sent": 60,
"points_lost": 0,
"cpu_average": 0.8,
"cpu_max": 0.8,
"delay_average": 0.0,
"delay_max": 0.0,
"read_errors": 0,
"csv_errors": 0,
"udp_errors": 0,
"read_time_avg": 0.03160557746887207,
"csv_write_time_avg": 0.0
}
},
{
"timestamp": "2025-08-25T18:40:53.987085",
"level": "info",
"event_type": "performance_report",
"message": "Performance report: 20 points saved, 0 lost, 0.9% CPU",
"details": {
"duration": 10.033382177352905,
"points_saved": 20,
"points_rate": 1.9933457777720747,
"variables_saved": 80,
"udp_points_sent": 60,
"points_lost": 0,
"cpu_average": 0.9,
"cpu_max": 0.9,
"delay_average": 0.0,
"delay_max": 0.0,
"read_errors": 0,
"csv_errors": 0,
"udp_errors": 0,
"read_time_avg": 0.034756577014923094,
"csv_write_time_avg": 0.0
}
},
{
"timestamp": "2025-08-25T18:41:04.037132",
"level": "info",
"event_type": "performance_report",
"message": "Performance report: 20 points saved, 0 lost, 1.1% CPU",
"details": {
"duration": 10.050047159194946,
"points_saved": 20,
"points_rate": 1.9900404130642995,
"variables_saved": 80,
"udp_points_sent": 60,
"points_lost": 0,
"cpu_average": 1.1,
"cpu_max": 1.1,
"delay_average": 0.0,
"delay_max": 0.0,
"read_errors": 0,
"csv_errors": 0,
"udp_errors": 0,
"read_time_avg": 0.03677387237548828,
"csv_write_time_avg": 0.0
}
},
{
"timestamp": "2025-08-25T18:41:14.094379",
"level": "info",
"event_type": "performance_report",
"message": "Performance report: 20 points saved, 0 lost, 0.8% CPU",
"details": {
"duration": 10.056742906570435,
"points_saved": 20,
"points_rate": 1.9887154504997115,
"variables_saved": 80,
"udp_points_sent": 60,
"points_lost": 0,
"cpu_average": 0.8,
"cpu_max": 0.8,
"delay_average": 0.0,
"delay_max": 0.0,
"read_errors": 0,
"csv_errors": 0,
"udp_errors": 0,
"read_time_avg": 0.03401594161987305,
"csv_write_time_avg": 0.0
}
}
],
"last_updated": "2025-08-25T17:54:00.414879",
"last_updated": "2025-08-25T18:41:14.094379",
"total_entries": 1000
}

View File

@ -33,10 +33,10 @@
{
"configType": "manual",
"area": "PEW",
"type": "word",
"streaming": false,
"name": "CTS306_PEW",
"offset": 256
"offset": 256,
"streaming": true,
"type": "word"
}
]
},
@ -44,16 +44,13 @@
"dataset_id": "Fast",
"variables": [
{
"area": "DB",
"configType": "symbol",
"name": "AUX Blink_2.0S",
"streaming": true,
"symbol": "AUX Blink_2.0S",
"type": "real"
"symbol": "AUX Blink_2.0S"
},
{
"area": "M",
"bit": 1,
"configType": "manual",
"name": "M50.1",
"offset": 50,
"streaming": false,
@ -62,7 +59,6 @@
{
"area": "M",
"bit": 2,
"configType": "manual",
"name": "M50.2",
"offset": 50,
"streaming": false,

View File

@ -24,140 +24,161 @@
"description": "Array of PLC variables for this dataset",
"items": {
"type": "object",
"oneOf": [
"properties": {
"configType": {
"type": "string",
"title": "Configuration Type",
"enum": ["manual", "symbol"],
"default": "manual"
}
},
"allOf": [
{
"title": "Manual Configuration",
"description": "Manually configure PLC variable parameters",
"properties": {
"name": {
"type": "string",
"title": "Variable Name",
"description": "Human-readable name for the variable"
},
"area": {
"type": "string",
"title": "Memory Area",
"enum": [
"DB",
"MW",
"M",
"PEW",
"PE",
"PAW",
"PA",
"E",
"A",
"MB"
]
},
"db": {
"type": [
"integer",
"null"
],
"title": "DB Number",
"minimum": 1,
"maximum": 9999
},
"offset": {
"type": "integer",
"title": "Offset",
"minimum": 0,
"maximum": 8191
},
"bit": {
"type": [
"integer",
"null"
],
"title": "Bit Position",
"minimum": 0,
"maximum": 7
},
"type": {
"type": "string",
"title": "Data Type",
"enum": [
"real",
"int",
"bool",
"dint",
"word",
"byte",
"uint",
"udint",
"sint",
"usint",
"dword"
]
},
"streaming": {
"type": "boolean",
"title": "Stream to PlotJuggler",
"description": "Include this variable in UDP streaming",
"default": false
"if": {
"properties": {
"configType": {
"const": "manual"
}
}
},
"required": [
"name",
"area",
"offset",
"type"
],
"allOf": [
{
"if": {
"properties": {
"area": {
"const": "DB"
}
}
"then": {
"properties": {
"name": {
"type": "string",
"title": "Variable Name",
"description": "Human-readable name for the variable"
},
"then": {
"required": ["db"]
"area": {
"type": "string",
"title": "Memory Area",
"enum": [
"DB",
"MW",
"M",
"PEW",
"PE",
"PAW",
"PA",
"E",
"A",
"MB"
]
},
"db": {
"type": [
"integer",
"null"
],
"title": "DB Number",
"minimum": 1,
"maximum": 9999
},
"offset": {
"type": "integer",
"title": "Offset",
"minimum": 0,
"maximum": 8191
},
"bit": {
"type": [
"integer",
"null"
],
"title": "Bit Position",
"minimum": 0,
"maximum": 7
},
"type": {
"type": "string",
"title": "Data Type",
"enum": [
"real",
"int",
"bool",
"dint",
"word",
"byte",
"uint",
"udint",
"sint",
"usint",
"dword"
]
},
"streaming": {
"type": "boolean",
"title": "Stream to PlotJuggler",
"description": "Include this variable in UDP streaming",
"default": false
}
},
{
"if": {
"properties": {
"type": {
"const": "bool"
"required": [
"configType",
"name",
"area",
"offset",
"type"
],
"allOf": [
{
"if": {
"properties": {
"area": {
"const": "DB"
}
}
},
"then": {
"required": ["db"]
}
},
"then": {
"required": ["bit"]
{
"if": {
"properties": {
"type": {
"const": "bool"
}
}
},
"then": {
"required": ["bit"]
}
}
}
]
]
}
},
{
"title": "Symbol-based Configuration",
"description": "Use a symbol from the loaded ASC file",
"properties": {
"name": {
"type": "string",
"title": "Variable Name",
"description": "Human-readable name for the variable (auto-filled from symbol)"
},
"symbol": {
"type": "string",
"title": "PLC Symbol",
"description": "Select a symbol from the loaded ASC file",
"options": {
"widget": "symbol-selector"
"if": {
"properties": {
"configType": {
"const": "symbol"
}
},
"streaming": {
"type": "boolean",
"title": "Stream to PlotJuggler",
"description": "Include this variable in UDP streaming",
"default": false
}
},
"required": [
"symbol"
]
"then": {
"properties": {
"name": {
"type": "string",
"title": "Variable Name",
"description": "Human-readable name for the variable (auto-filled from symbol)"
},
"symbol": {
"type": "string",
"title": "PLC Symbol",
"description": "Select a symbol from the loaded ASC file"
},
"streaming": {
"type": "boolean",
"title": "Stream to PlotJuggler",
"description": "Include this variable in UDP streaming",
"default": false
}
},
"required": [
"configType",
"symbol"
]
}
}
]
}

View File

@ -25,221 +25,206 @@
"removable": true
},
"items": {
"oneOf": [
{
"ui:title": "Manual Configuration",
"ui:description": "Configure PLC variable parameters manually",
"ui:order": [
"name",
"area",
"db",
"offset",
"bit",
"type",
"streaming"
],
"ui:layout": [
[
{
"name": "name",
"width": 4
},
{
"name": "area",
"width": 2
},
{
"name": "db",
"width": 2
},
{
"name": "offset",
"width": 2
},
{
"name": "type",
"width": 2
}
],
[
{
"name": "bit",
"width": 3
},
{
"name": "streaming",
"width": 9
}
]
],
"name": {
"ui:widget": "text",
"ui:placeholder": "Variable name",
"ui:help": "📝 Human-readable name for this variable"
},
"area": {
"ui:widget": "select",
"ui:help": "PLC memory area (DB=DataBlock, MW=MemoryWord, etc.)",
"ui:options": {
"enumOptions": [
{
"value": "DB",
"label": "🗃️ DB (Data Block)"
},
{
"value": "MW",
"label": "📊 MW (Memory Word)"
},
{
"value": "M",
"label": "💾 M (Memory)"
},
{
"value": "PEW",
"label": "📥 PEW (Process Input Word)"
},
{
"value": "PE",
"label": "📥 PE (Process Input)"
},
{
"value": "PAW",
"label": "📤 PAW (Process Output Word)"
},
{
"value": "PA",
"label": "📤 PA (Process Output)"
},
{
"value": "E",
"label": "🔌 E (Input)"
},
{
"value": "A",
"label": "🔌 A (Output)"
},
{
"value": "MB",
"label": "💾 MB (Memory Byte)"
}
]
}
},
"db": {
"ui:widget": "updown",
"ui:help": "⚠️ Data Block number (only required for DB area - will be ignored for other areas like PE, PA, MW, etc.)",
"ui:placeholder": "1011",
"ui:description": "🗃️ This field is only used when Area = 'DB (Data Block)'"
},
"offset": {
"ui:widget": "updown",
"ui:help": "Byte offset within the memory area"
},
"bit": {
"ui:widget": "updown",
"ui:help": "⚠️ Bit position (0-7) - only required for BOOL data type, will be ignored for other types",
"ui:description": "✅ This field is only used when Type = 'BOOL (1-bit boolean)'"
},
"type": {
"ui:widget": "select",
"ui:help": "PLC data type",
"ui:options": {
"enumOptions": [
{
"value": "real",
"label": "🔢 REAL (32-bit float)"
},
{
"value": "int",
"label": "🔢 INT (16-bit signed)"
},
{
"value": "bool",
"label": "✅ BOOL (1-bit boolean)"
},
{
"value": "dint",
"label": "🔢 DINT (32-bit signed)"
},
{
"value": "word",
"label": "🔢 WORD (16-bit unsigned)"
},
{
"value": "byte",
"label": "🔢 BYTE (8-bit unsigned)"
},
{
"value": "uint",
"label": "🔢 UINT (16-bit unsigned)"
},
{
"value": "udint",
"label": "🔢 UDINT (32-bit unsigned)"
},
{
"value": "sint",
"label": "🔢 SINT (8-bit signed)"
},
{
"value": "usint",
"label": "🔢 USINT (8-bit unsigned)"
},
{
"value": "dword",
"label": "🔢 DWORD (32-bit unsigned)"
}
]
}
},
"streaming": {
"ui:widget": "switch",
"ui:help": "📡 Enable real-time streaming to PlotJuggler for visualization"
"ui:order": [
"configType",
"name",
"symbol",
"area",
"db",
"offset",
"bit",
"type",
"streaming"
],
"ui:layout": [
[
{
"name": "configType",
"width": 3
}
},
{
"ui:title": "Symbol-based Configuration",
"ui:description": "Use a symbol from the loaded ASC file",
"ui:order": [
"name",
"symbol",
"streaming"
],
"ui:layout": [
[
{
"name": "name",
"width": 6
},
{
"name": "symbol",
"width": 6
}
],
[
{
"name": "streaming",
"width": 12
}
]
],
"name": {
"ui:widget": "text",
"ui:placeholder": "Variable name (auto-filled from symbol)",
"ui:help": "📝 Human-readable name for this variable",
"ui:readonly": true
],
[
{
"name": "name",
"width": 6
},
"symbol": {
"ui:widget": "dataset-variable-symbol",
"ui:placeholder": "Select a PLC symbol...",
"ui:help": "🔍 Search and select a symbol from the loaded ASC file"
},
"streaming": {
"ui:widget": "switch",
"ui:help": "📡 Enable real-time streaming to PlotJuggler for visualization"
{
"name": "symbol",
"width": 6
}
],
[
{
"name": "area",
"width": 2
},
{
"name": "db",
"width": 2
},
{
"name": "offset",
"width": 2
},
{
"name": "bit",
"width": 2
},
{
"name": "type",
"width": 2
},
{
"name": "streaming",
"width": 2
}
]
],
"configType": {
"ui:widget": "select",
"ui:help": "Choose between manual configuration or symbol-based setup",
"ui:options": {
"enumOptions": [
{
"value": "manual",
"label": "🔧 Manual Configuration"
},
{
"value": "symbol",
"label": "🔍 Symbol-based Configuration"
}
]
}
]
},
"name": {
"ui:widget": "text",
"ui:placeholder": "Variable name",
"ui:help": "📝 Human-readable name for this variable"
},
"symbol": {
"ui:widget": "dataset-variable-symbol",
"ui:placeholder": "Select a PLC symbol...",
"ui:help": "🔍 Search and select a symbol from the loaded ASC file"
},
"area": {
"ui:widget": "select",
"ui:help": "PLC memory area (DB=DataBlock, MW=MemoryWord, etc.)",
"ui:options": {
"enumOptions": [
{
"value": "DB",
"label": "🗃️ DB (Data Block)"
},
{
"value": "MW",
"label": "📊 MW (Memory Word)"
},
{
"value": "M",
"label": "💾 M (Memory)"
},
{
"value": "PEW",
"label": "📥 PEW (Process Input Word)"
},
{
"value": "PE",
"label": "📥 PE (Process Input)"
},
{
"value": "PAW",
"label": "📤 PAW (Process Output Word)"
},
{
"value": "PA",
"label": "📤 PA (Process Output)"
},
{
"value": "E",
"label": "🔌 E (Input)"
},
{
"value": "A",
"label": "🔌 A (Output)"
},
{
"value": "MB",
"label": "💾 MB (Memory Byte)"
}
]
}
},
"db": {
"ui:widget": "updown",
"ui:help": "⚠️ Data Block number (only required for DB area - will be ignored for other areas like PE, PA, MW, etc.)",
"ui:placeholder": "1011",
"ui:description": "🗃️ This field is only used when Area = 'DB (Data Block)'"
},
"offset": {
"ui:widget": "updown",
"ui:help": "Byte offset within the memory area"
},
"bit": {
"ui:widget": "updown",
"ui:help": "⚠️ Bit position (0-7) - only required for BOOL data type, will be ignored for other types",
"ui:description": "✅ This field is only used when Type = 'BOOL (1-bit boolean)'"
},
"type": {
"ui:widget": "select",
"ui:help": "PLC data type",
"ui:options": {
"enumOptions": [
{
"value": "real",
"label": "🔢 REAL (32-bit float)"
},
{
"value": "int",
"label": "🔢 INT (16-bit signed)"
},
{
"value": "bool",
"label": "✅ BOOL (1-bit boolean)"
},
{
"value": "dint",
"label": "🔢 DINT (32-bit signed)"
},
{
"value": "word",
"label": "🔢 WORD (16-bit unsigned)"
},
{
"value": "byte",
"label": "🔢 BYTE (8-bit unsigned)"
},
{
"value": "uint",
"label": "🔢 UINT (16-bit unsigned)"
},
{
"value": "udint",
"label": "🔢 UDINT (32-bit unsigned)"
},
{
"value": "sint",
"label": "🔢 SINT (8-bit signed)"
},
{
"value": "usint",
"label": "🔢 USINT (8-bit unsigned)"
},
{
"value": "dword",
"label": "🔢 DWORD (32-bit unsigned)"
}
]
}
},
"streaming": {
"ui:widget": "switch",
"ui:help": "📡 Enable real-time streaming to PlotJuggler for visualization"
}
}
}
}

View File

@ -1374,129 +1374,56 @@ function DatasetManager() {
/>
</Flex>
{/* Simplified schema for selected dataset variables */}
{/* Schema for selected dataset variables - derived from external schema */}
{(() => {
const selectedDatasetVars = getSelectedDatasetVariables()
// Schema for this dataset's variables
const singleDatasetSchema = {
type: "object",
properties: {
variables: {
type: "array",
title: `Variables for Dataset: ${availableDatasets.find(d => d.id === selectedDatasetId)?.name || selectedDatasetId}`,
description: `PLC variables to record in dataset ${selectedDatasetId}`,
items: {
type: "object",
properties: {
configType: {
type: "string",
title: "Configuration Type",
enum: ["manual", "symbol"],
default: "manual"
}
},
allOf: [
{
if: { properties: { configType: { const: "manual" } } },
then: {
properties: {
name: { type: "string", title: "Variable Name" },
area: {
type: "string",
title: "Memory Area",
enum: ["DB", "MW", "M", "PEW", "PE", "PAW", "PA", "E", "A", "MB"],
default: "DB"
},
db: { type: "integer", title: "DB Number", minimum: 1, maximum: 9999 },
offset: { type: "integer", title: "Offset", minimum: 0, maximum: 8191 },
bit: { type: "integer", title: "Bit Position", minimum: 0, maximum: 7 },
type: {
type: "string",
title: "Data Type",
enum: ["real", "int", "dint", "bool", "word", "byte"],
default: "real"
},
streaming: { type: "boolean", title: "Stream to UDP", default: false }
},
required: ["name", "area", "offset", "type"]
}
},
{
if: { properties: { configType: { const: "symbol" } } },
then: {
properties: {
name: {
type: "string",
title: "Variable Name",
description: "Auto-filled from symbol",
readOnly: true
},
symbol: {
type: "string",
title: "PLC Symbol",
description: "Select a symbol from loaded ASC file"
},
streaming: { type: "boolean", title: "Stream to UDP", default: false }
},
required: ["symbol"]
}
}
]
// Create simplified schema from external schema for single dataset variables
let singleDatasetSchema = null
let singleDatasetUiSchema = null
if (variablesSchemaData?.schema) {
// Extract the variables array schema from the external schema
// Path: schema.properties.variables.items.properties.variables
const datasetItemSchema = variablesSchemaData.schema.properties?.variables?.items
const variablesArraySchema = datasetItemSchema?.properties?.variables
if (variablesArraySchema) {
singleDatasetSchema = {
type: "object",
properties: {
variables: {
...variablesArraySchema,
title: `Variables for Dataset: ${availableDatasets.find(d => d.id === selectedDatasetId)?.name || selectedDatasetId}`,
description: `PLC variables to record in dataset ${selectedDatasetId}`
}
}
}
}
}
const singleDatasetUiSchema = {
variables: {
items: {
"ui:order": ["configType", "name", "symbol", "area", "db", "offset", "bit", "type", "streaming"],
"ui:layout": [
[
{ "name": "configType", "width": 3 }
],
[
{ "name": "name", "width": 4 },
{ "name": "symbol", "width": 8 }
],
[
{ "name": "area", "width": 2 },
{ "name": "db", "width": 2 },
{ "name": "offset", "width": 2 },
{ "name": "bit", "width": 2 },
{ "name": "type", "width": 2 },
{ "name": "streaming", "width": 2 }
]
],
"configType": {
"ui:widget": "select",
"ui:help": "Choose between manual configuration or symbol-based setup",
"ui:enumNames": ["Manual Configuration", "Symbol-based Configuration"]
},
"symbol": {
"ui:widget": "symbol-selector",
"ui:placeholder": "Select a PLC symbol...",
"ui:help": "🔍 Search and select a symbol from the loaded ASC file"
},
"name": {
"ui:help": "Human-readable name for this variable"
},
"area": {
"ui:widget": "select",
"ui:help": "PLC memory area"
},
"type": {
"ui:widget": "select",
"ui:help": "PLC data type"
},
"streaming": {
"ui:widget": "switch",
"ui:help": "Enable UDP streaming to PlotJuggler"
}
if (variablesSchemaData?.uiSchema) {
// Extract the variables UI schema from the external UI schema
// Path: uiSchema.variables.items.variables
const datasetItemUiSchema = variablesSchemaData.uiSchema.variables?.items
const variablesUiSchema = datasetItemUiSchema?.variables
if (variablesUiSchema) {
singleDatasetUiSchema = {
variables: variablesUiSchema
}
}
}
// Fallback if external schemas are not available
if (!singleDatasetSchema || !singleDatasetUiSchema) {
return (
<Alert status="warning">
<AlertIcon />
<Text>External schemas not loaded. Please refresh the page.</Text>
</Alert>
)
}
// Function to expand symbol data using backend API
const expandSymbolToManualConfig = async (symbolName, currentVariable = {}) => {
@ -1504,8 +1431,7 @@ function DatasetManager() {
// Create a temporary variable array with just this symbol
const tempVariables = [{
symbol: symbolName,
streaming: currentVariable.streaming || false,
configType: "symbol"
streaming: currentVariable.streaming || false
}]
// Call backend API to process the symbol
@ -1589,68 +1515,10 @@ function DatasetManager() {
}
}
// Custom onChange handler that detects configType changes and auto-fills data
const handleFormChange = async ({ formData }) => {
// Check if there are variables and if any configType changed from symbol to manual
if (formData?.variables && selectedDatasetVars?.variables) {
const updatedVariables = []
let hasSymbolToManualChange = false
for (let index = 0; index < formData.variables.length; index++) {
const newVar = formData.variables[index]
const oldVar = selectedDatasetVars.variables[index]
// Detect if configType changed from "symbol" to "manual"
if (oldVar?.configType === "symbol" &&
newVar?.configType === "manual" &&
oldVar?.symbol) {
hasSymbolToManualChange = true
try {
// Auto-fill manual fields from symbol data using backend API
const symbolData = await expandSymbolToManualConfig(oldVar.symbol, oldVar)
// Add the variable with auto-filled data
updatedVariables.push({
...newVar,
...symbolData,
configType: "manual", // Ensure configType is set correctly
symbol: undefined // Clear symbol field to avoid confusion
})
} catch (error) {
console.error('Error expanding symbol:', error)
// Fallback: add variable as-is on error
updatedVariables.push(newVar)
}
} else {
// For other cases, return the variable as-is
updatedVariables.push(newVar)
}
}
if (hasSymbolToManualChange) {
// Show toast notification about the auto-fill
toast({
title: '🔄 Auto-filled from symbol',
description: 'Symbol data has been copied to manual configuration fields',
status: 'success',
duration: 3000
})
}
// Update with the modified variables
const updatedFormData = {
...formData,
variables: updatedVariables
}
updateSelectedDatasetVariables(updatedFormData)
} else {
// Normal update without special processing
updateSelectedDatasetVariables(formData)
}
// Standard form change handler for external schema compatibility
const handleFormChange = ({ formData }) => {
// Direct update without special processing for external schema compatibility
updateSelectedDatasetVariables(formData)
}
return (
@ -1669,12 +1537,7 @@ function DatasetManager() {
})
}}
onChange={({ formData }) => {
// Call the async handler
handleFormChange({ formData }).catch(error => {
console.error('Error in form change handler:', error)
// Fallback to normal update on error
updateSelectedDatasetVariables(formData)
})
handleFormChange({ formData })
}}
>
<VStack spacing={3} mt={4} align="stretch">

View File

@ -1,10 +1,12 @@
{
"last_state": {
"should_connect": false,
"should_stream": false,
"active_datasets": []
"should_connect": true,
"should_stream": true,
"active_datasets": [
"DAR"
]
},
"auto_recovery_enabled": true,
"last_update": "2025-08-25T17:50:18.320817",
"last_update": "2025-08-25T18:40:24.478882",
"plotjuggler_path": "C:\\Program Files\\PlotJuggler\\plotjuggler.exe"
}