diff --git a/application_events.json b/application_events.json
index d4f4aea..09a4783 100644
--- a/application_events.json
+++ b/application_events.json
@@ -1,257 +1,5 @@
{
"events": [
- {
- "timestamp": "2025-08-14T16:52:25.768669",
- "level": "warning",
- "event_type": "symbol_parse_warning",
- "message": "Could not parse PLC address: DB 2121",
- "details": {}
- },
- {
- "timestamp": "2025-08-14T16:52:25.776678",
- "level": "warning",
- "event_type": "symbol_parse_warning",
- "message": "Unrecognized address format: UDT 82",
- "details": {}
- },
- {
- "timestamp": "2025-08-14T16:52:25.785672",
- "level": "warning",
- "event_type": "symbol_parse_warning",
- "message": "Could not parse PLC address: UDT 82",
- "details": {}
- },
- {
- "timestamp": "2025-08-14T16:52:25.794673",
- "level": "warning",
- "event_type": "symbol_parse_warning",
- "message": "Unrecognized address format: UDT 1",
- "details": {}
- },
- {
- "timestamp": "2025-08-14T16:52:25.803233",
- "level": "warning",
- "event_type": "symbol_parse_warning",
- "message": "Could not parse PLC address: UDT 1",
- "details": {}
- },
- {
- "timestamp": "2025-08-14T16:52:25.811243",
- "level": "warning",
- "event_type": "symbol_parse_warning",
- "message": "Unrecognized address format: VAT 22",
- "details": {}
- },
- {
- "timestamp": "2025-08-14T16:52:25.819268",
- "level": "warning",
- "event_type": "symbol_parse_warning",
- "message": "Could not parse PLC address: VAT 22",
- "details": {}
- },
- {
- "timestamp": "2025-08-14T16:52:25.826782",
- "level": "warning",
- "event_type": "symbol_parse_warning",
- "message": "Unrecognized address format: DB 959",
- "details": {}
- },
- {
- "timestamp": "2025-08-14T16:52:25.834787",
- "level": "warning",
- "event_type": "symbol_parse_warning",
- "message": "Could not parse PLC address: DB 959",
- "details": {}
- },
- {
- "timestamp": "2025-08-14T16:52:25.841796",
- "level": "warning",
- "event_type": "symbol_parse_warning",
- "message": "Unrecognized address format: FC 1804",
- "details": {}
- },
- {
- "timestamp": "2025-08-14T16:52:25.848796",
- "level": "warning",
- "event_type": "symbol_parse_warning",
- "message": "Could not parse PLC address: FC 1804",
- "details": {}
- },
- {
- "timestamp": "2025-08-14T16:52:25.857991",
- "level": "warning",
- "event_type": "symbol_parse_warning",
- "message": "Unrecognized address format: DB 972",
- "details": {}
- },
- {
- "timestamp": "2025-08-14T16:52:25.864990",
- "level": "warning",
- "event_type": "symbol_parse_warning",
- "message": "Could not parse PLC address: DB 972",
- "details": {}
- },
- {
- "timestamp": "2025-08-14T16:52:25.872997",
- "level": "warning",
- "event_type": "symbol_parse_warning",
- "message": "Unrecognized address format: DB 930",
- "details": {}
- },
- {
- "timestamp": "2025-08-14T16:52:25.881999",
- "level": "warning",
- "event_type": "symbol_parse_warning",
- "message": "Could not parse PLC address: DB 930",
- "details": {}
- },
- {
- "timestamp": "2025-08-14T16:52:25.890523",
- "level": "warning",
- "event_type": "symbol_parse_warning",
- "message": "Unrecognized address format: FB 1800",
- "details": {}
- },
- {
- "timestamp": "2025-08-14T16:52:25.898534",
- "level": "warning",
- "event_type": "symbol_parse_warning",
- "message": "Could not parse PLC address: FB 1800",
- "details": {}
- },
- {
- "timestamp": "2025-08-14T16:52:25.907703",
- "level": "warning",
- "event_type": "symbol_parse_warning",
- "message": "Unrecognized address format: DB 971",
- "details": {}
- },
- {
- "timestamp": "2025-08-14T16:52:25.914685",
- "level": "warning",
- "event_type": "symbol_parse_warning",
- "message": "Could not parse PLC address: DB 971",
- "details": {}
- },
- {
- "timestamp": "2025-08-14T16:52:25.922698",
- "level": "warning",
- "event_type": "symbol_parse_warning",
- "message": "Unrecognized address format: DB 970",
- "details": {}
- },
- {
- "timestamp": "2025-08-14T16:52:25.929693",
- "level": "warning",
- "event_type": "symbol_parse_warning",
- "message": "Could not parse PLC address: DB 970",
- "details": {}
- },
- {
- "timestamp": "2025-08-14T16:52:25.937844",
- "level": "warning",
- "event_type": "symbol_parse_warning",
- "message": "Unrecognized address format: FC 2000",
- "details": {}
- },
- {
- "timestamp": "2025-08-14T16:52:25.944860",
- "level": "warning",
- "event_type": "symbol_parse_warning",
- "message": "Could not parse PLC address: FC 2000",
- "details": {}
- },
- {
- "timestamp": "2025-08-14T16:52:25.954008",
- "level": "warning",
- "event_type": "symbol_parse_warning",
- "message": "Unrecognized address format: FC 2036",
- "details": {}
- },
- {
- "timestamp": "2025-08-14T16:52:25.962012",
- "level": "warning",
- "event_type": "symbol_parse_warning",
- "message": "Could not parse PLC address: FC 2036",
- "details": {}
- },
- {
- "timestamp": "2025-08-14T16:52:25.971003",
- "level": "warning",
- "event_type": "symbol_parse_warning",
- "message": "Unrecognized address format: FC 2013",
- "details": {}
- },
- {
- "timestamp": "2025-08-14T16:52:25.978013",
- "level": "warning",
- "event_type": "symbol_parse_warning",
- "message": "Could not parse PLC address: FC 2013",
- "details": {}
- },
- {
- "timestamp": "2025-08-14T16:52:25.987006",
- "level": "warning",
- "event_type": "symbol_parse_warning",
- "message": "Unrecognized address format: FC 2001",
- "details": {}
- },
- {
- "timestamp": "2025-08-14T16:52:25.994321",
- "level": "warning",
- "event_type": "symbol_parse_warning",
- "message": "Could not parse PLC address: FC 2001",
- "details": {}
- },
- {
- "timestamp": "2025-08-14T16:52:26.002877",
- "level": "warning",
- "event_type": "symbol_parse_warning",
- "message": "Unrecognized address format: FC 2003",
- "details": {}
- },
- {
- "timestamp": "2025-08-14T16:52:26.009876",
- "level": "warning",
- "event_type": "symbol_parse_warning",
- "message": "Could not parse PLC address: FC 2003",
- "details": {}
- },
- {
- "timestamp": "2025-08-14T16:52:26.017866",
- "level": "warning",
- "event_type": "symbol_parse_warning",
- "message": "Unrecognized address format: FC 2037",
- "details": {}
- },
- {
- "timestamp": "2025-08-14T16:52:26.025863",
- "level": "warning",
- "event_type": "symbol_parse_warning",
- "message": "Could not parse PLC address: FC 2037",
- "details": {}
- },
- {
- "timestamp": "2025-08-14T16:52:26.033864",
- "level": "warning",
- "event_type": "symbol_parse_warning",
- "message": "Unrecognized address format: FC 2033",
- "details": {}
- },
- {
- "timestamp": "2025-08-14T16:52:26.041875",
- "level": "warning",
- "event_type": "symbol_parse_warning",
- "message": "Could not parse PLC address: FC 2033",
- "details": {}
- },
- {
- "timestamp": "2025-08-14T16:52:26.049093",
- "level": "warning",
- "event_type": "symbol_parse_warning",
- "message": "Unrecognized address format: FC 2012",
- "details": {}
- },
{
"timestamp": "2025-08-14T16:52:26.063705",
"level": "warning",
@@ -6999,8 +6747,354 @@
"event_type": "symbols_loaded",
"message": "Loaded 2077 symbols from C:/Users/migue/Downloads/symSAE452.asc",
"details": {}
+ },
+ {
+ "timestamp": "2025-08-14T17:00:00.267126",
+ "level": "error",
+ "event_type": "csv_cleanup_failed",
+ "message": "CSV cleanup failed: 'max_hours'",
+ "details": {}
+ },
+ {
+ "timestamp": "2025-08-14T17:06:22.110502",
+ "level": "info",
+ "event_type": "application_started",
+ "message": "Application initialization completed successfully",
+ "details": {}
+ },
+ {
+ "timestamp": "2025-08-14T17:06:22.161221",
+ "level": "info",
+ "event_type": "dataset_activated",
+ "message": "Dataset activated: DAR",
+ "details": {
+ "dataset_id": "DAR",
+ "variables_count": 2,
+ "streaming_count": 2,
+ "prefix": "gateway_phoenix"
+ }
+ },
+ {
+ "timestamp": "2025-08-14T17:06:22.174891",
+ "level": "info",
+ "event_type": "csv_recording_started",
+ "message": "CSV recording started: 1 datasets activated",
+ "details": {
+ "activated_datasets": 1,
+ "total_datasets": 3
+ }
+ },
+ {
+ "timestamp": "2025-08-14T17:06:22.183906",
+ "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": 3
+ }
+ },
+ {
+ "timestamp": "2025-08-14T17:06:22.192523",
+ "level": "error",
+ "event_type": "csv_cleanup_failed",
+ "message": "CSV cleanup failed: 'max_hours'",
+ "details": {}
+ },
+ {
+ "timestamp": "2025-08-14T17:10:14.827169",
+ "level": "info",
+ "event_type": "application_started",
+ "message": "Application initialization completed successfully",
+ "details": {}
+ },
+ {
+ "timestamp": "2025-08-14T17:10:14.876601",
+ "level": "info",
+ "event_type": "dataset_activated",
+ "message": "Dataset activated: DAR",
+ "details": {
+ "dataset_id": "DAR",
+ "variables_count": 2,
+ "streaming_count": 2,
+ "prefix": "gateway_phoenix"
+ }
+ },
+ {
+ "timestamp": "2025-08-14T17:10:14.884605",
+ "level": "info",
+ "event_type": "csv_recording_started",
+ "message": "CSV recording started: 1 datasets activated",
+ "details": {
+ "activated_datasets": 1,
+ "total_datasets": 3
+ }
+ },
+ {
+ "timestamp": "2025-08-14T17:10:14.892976",
+ "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": 3
+ }
+ },
+ {
+ "timestamp": "2025-08-14T17:10:14.908569",
+ "level": "error",
+ "event_type": "csv_cleanup_failed",
+ "message": "CSV cleanup failed: 'max_hours'",
+ "details": {}
+ },
+ {
+ "timestamp": "2025-08-14T17:10:32.756676",
+ "level": "info",
+ "event_type": "application_started",
+ "message": "Application initialization completed successfully",
+ "details": {}
+ },
+ {
+ "timestamp": "2025-08-14T17:10:32.805384",
+ "level": "info",
+ "event_type": "dataset_activated",
+ "message": "Dataset activated: DAR",
+ "details": {
+ "dataset_id": "DAR",
+ "variables_count": 2,
+ "streaming_count": 2,
+ "prefix": "gateway_phoenix"
+ }
+ },
+ {
+ "timestamp": "2025-08-14T17:10:32.814382",
+ "level": "info",
+ "event_type": "csv_recording_started",
+ "message": "CSV recording started: 1 datasets activated",
+ "details": {
+ "activated_datasets": 1,
+ "total_datasets": 3
+ }
+ },
+ {
+ "timestamp": "2025-08-14T17:10:32.823381",
+ "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": 3
+ }
+ },
+ {
+ "timestamp": "2025-08-14T17:10:32.837621",
+ "level": "error",
+ "event_type": "csv_cleanup_failed",
+ "message": "CSV cleanup failed: 'max_hours'",
+ "details": {}
+ },
+ {
+ "timestamp": "2025-08-14T17:14:00.334194",
+ "level": "info",
+ "event_type": "application_started",
+ "message": "Application initialization completed successfully",
+ "details": {}
+ },
+ {
+ "timestamp": "2025-08-14T17:14:00.401621",
+ "level": "info",
+ "event_type": "dataset_activated",
+ "message": "Dataset activated: DAR",
+ "details": {
+ "dataset_id": "DAR",
+ "variables_count": 2,
+ "streaming_count": 2,
+ "prefix": "gateway_phoenix"
+ }
+ },
+ {
+ "timestamp": "2025-08-14T17:14:00.410620",
+ "level": "info",
+ "event_type": "csv_recording_started",
+ "message": "CSV recording started: 1 datasets activated",
+ "details": {
+ "activated_datasets": 1,
+ "total_datasets": 3
+ }
+ },
+ {
+ "timestamp": "2025-08-14T17:14:00.421480",
+ "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": 3
+ }
+ },
+ {
+ "timestamp": "2025-08-14T17:14:00.435620",
+ "level": "error",
+ "event_type": "csv_cleanup_failed",
+ "message": "CSV cleanup failed: 'max_hours'",
+ "details": {}
+ },
+ {
+ "timestamp": "2025-08-14T17:25:34.393400",
+ "level": "info",
+ "event_type": "application_started",
+ "message": "Application initialization completed successfully",
+ "details": {}
+ },
+ {
+ "timestamp": "2025-08-14T17:25:34.443828",
+ "level": "info",
+ "event_type": "dataset_activated",
+ "message": "Dataset activated: DAR",
+ "details": {
+ "dataset_id": "DAR",
+ "variables_count": 2,
+ "streaming_count": 2,
+ "prefix": "gateway_phoenix"
+ }
+ },
+ {
+ "timestamp": "2025-08-14T17:25:34.451828",
+ "level": "info",
+ "event_type": "csv_recording_started",
+ "message": "CSV recording started: 1 datasets activated",
+ "details": {
+ "activated_datasets": 1,
+ "total_datasets": 3
+ }
+ },
+ {
+ "timestamp": "2025-08-14T17:25:34.464832",
+ "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": 3
+ }
+ },
+ {
+ "timestamp": "2025-08-14T17:25:34.477358",
+ "level": "error",
+ "event_type": "csv_cleanup_failed",
+ "message": "CSV cleanup failed: 'max_hours'",
+ "details": {}
+ },
+ {
+ "timestamp": "2025-08-14T17:31:05.141755",
+ "level": "info",
+ "event_type": "application_started",
+ "message": "Application initialization completed successfully",
+ "details": {}
+ },
+ {
+ "timestamp": "2025-08-14T17:31:05.207794",
+ "level": "info",
+ "event_type": "dataset_activated",
+ "message": "Dataset activated: DAR",
+ "details": {
+ "dataset_id": "DAR",
+ "variables_count": 2,
+ "streaming_count": 2,
+ "prefix": "gateway_phoenix"
+ }
+ },
+ {
+ "timestamp": "2025-08-14T17:31:05.219935",
+ "level": "info",
+ "event_type": "csv_recording_started",
+ "message": "CSV recording started: 1 datasets activated",
+ "details": {
+ "activated_datasets": 1,
+ "total_datasets": 3
+ }
+ },
+ {
+ "timestamp": "2025-08-14T17:31:05.234342",
+ "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": 3
+ }
+ },
+ {
+ "timestamp": "2025-08-14T17:31:05.240939",
+ "level": "error",
+ "event_type": "csv_cleanup_failed",
+ "message": "CSV cleanup failed: 'max_hours'",
+ "details": {}
+ },
+ {
+ "timestamp": "2025-08-14T17:32:09.019907",
+ "level": "info",
+ "event_type": "application_started",
+ "message": "Application initialization completed successfully",
+ "details": {}
+ },
+ {
+ "timestamp": "2025-08-14T17:32:09.087100",
+ "level": "info",
+ "event_type": "dataset_activated",
+ "message": "Dataset activated: DAR",
+ "details": {
+ "dataset_id": "DAR",
+ "variables_count": 2,
+ "streaming_count": 2,
+ "prefix": "gateway_phoenix"
+ }
+ },
+ {
+ "timestamp": "2025-08-14T17:32:09.107982",
+ "level": "info",
+ "event_type": "csv_recording_started",
+ "message": "CSV recording started: 1 datasets activated",
+ "details": {
+ "activated_datasets": 1,
+ "total_datasets": 3
+ }
+ },
+ {
+ "timestamp": "2025-08-14T17:32:09.122999",
+ "level": "error",
+ "event_type": "csv_cleanup_failed",
+ "message": "CSV cleanup failed: 'max_hours'",
+ "details": {}
+ },
+ {
+ "timestamp": "2025-08-14T17:32:09.144483",
+ "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": 3
+ }
}
],
- "last_updated": "2025-08-14T16:52:36.475776",
+ "last_updated": "2025-08-14T17:32:09.144483",
+ "total_entries": 1000
+}ted",
+ "details": {
+ "udp_host": "127.0.0.1",
+ "udp_port": 9870,
+ "datasets_available": 3
+ }
+ }
+ ],
+ "last_updated": "2025-08-14T17:32:09.123999",
"total_entries": 1000
}
\ No newline at end of file
diff --git a/config/data/dataset_variables.json b/config/data/dataset_variables.json
index c87504d..1c711e9 100644
--- a/config/data/dataset_variables.json
+++ b/config/data/dataset_variables.json
@@ -4,6 +4,7 @@
"dataset_id": "DAR",
"variables": [
{
+ "configType": "manual",
"area": "db",
"db": 1011,
"name": "UR29_Brix",
@@ -12,6 +13,7 @@
"type": "real"
},
{
+ "configType": "manual",
"area": "db",
"db": 1011,
"name": "UR29_ma",
@@ -23,7 +25,15 @@
},
{
"dataset_id": "Fast",
- "variables": []
+ "variables": [
+ {
+ "configType": "symbol",
+ "area": "db",
+ "type": "real",
+ "streaming": false,
+ "symbol": "FTP302_Brix"
+ }
+ ]
}
]
}
\ No newline at end of file
diff --git a/config/schema/ui/dataset-variables.uischema.json b/config/schema/ui/dataset-variables.uischema.json
index 5fad8d7..24832ee 100644
--- a/config/schema/ui/dataset-variables.uischema.json
+++ b/config/schema/ui/dataset-variables.uischema.json
@@ -25,167 +25,215 @@
"removable": true
},
"items": {
- "ui:order": [
- "name",
- "area",
- "db",
- "offset",
- "bit",
- "type",
- "streaming"
- ],
- "ui:layout": [
- [
- {
- "name": "name",
- "width": 4
+ "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"
},
- {
- "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)"
+ "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 (required for DB area)",
- "ui:placeholder": "1011"
- },
- "offset": {
- "ui:widget": "updown",
- "ui:help": "Byte offset within the memory area"
- },
- "bit": {
- "ui:widget": "updown",
- "ui:help": "Bit position (0-7) for bit-addressable areas"
- },
- "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)"
+ },
+ "db": {
+ "ui:widget": "updown",
+ "ui:help": "Data Block number (required for DB area)",
+ "ui:placeholder": "1011"
+ },
+ "offset": {
+ "ui:widget": "updown",
+ "ui:help": "Byte offset within the memory area"
+ },
+ "bit": {
+ "ui:widget": "updown",
+ "ui:help": "Bit position (0-7) for bit-addressable areas"
+ },
+ "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)"
+ }
+ ]
}
- ]
+ },
+ "streaming": {
+ "ui:widget": "checkbox",
+ "ui:help": "📡 Enable real-time streaming to PlotJuggler for visualization"
+ }
+ },
+ {
+ "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
+ },
+ "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": "checkbox",
+ "ui:help": "📡 Enable real-time streaming to PlotJuggler for visualization"
+ }
}
- },
- "streaming": {
- "ui:widget": "checkbox",
- "ui:help": "📡 Enable real-time streaming to PlotJuggler for visualization"
- }
+ ]
}
}
}
diff --git a/frontend/src/components/DatasetVariablesRJSF.jsx b/frontend/src/components/DatasetVariablesRJSF.jsx
new file mode 100644
index 0000000..9ceac98
--- /dev/null
+++ b/frontend/src/components/DatasetVariablesRJSF.jsx
@@ -0,0 +1,195 @@
+import React, { useState, useEffect } from 'react'
+import {
+ Box,
+ VStack,
+ HStack,
+ Card,
+ CardBody,
+ CardHeader,
+ Heading,
+ Text,
+ Select,
+ Alert,
+ AlertIcon,
+ useColorModeValue,
+ Spinner
+} from '@chakra-ui/react'
+import Form from '@rjsf/chakra-ui'
+import validator from '@rjsf/validator-ajv8'
+import LayoutObjectFieldTemplate from './rjsf/LayoutObjectFieldTemplate.jsx'
+import { allWidgets } from './widgets/AllWidgets.jsx'
+
+/**
+ * DatasetVariablesRJSF - Maneja variables de dataset usando RJSF Type 3 pattern
+ */
+export default function DatasetVariablesRJSF({
+ datasets = {},
+ selectedDatasetId,
+ onSelectDataset,
+ onVariablesUpdate
+}) {
+ const [schema, setSchema] = useState(null)
+ const [uiSchema, setUiSchema] = useState(null)
+ const [variables, setVariables] = useState({ variables: [] })
+ const [loading, setLoading] = useState(true)
+ const [saving, setSaving] = useState(false)
+ const [message, setMessage] = useState('')
+
+ const muted = useColorModeValue('gray.600', 'gray.300')
+
+ // Load schema and data
+ useEffect(() => {
+ loadSchemaAndData()
+ }, [])
+
+ const loadSchemaAndData = async () => {
+ setLoading(true)
+ try {
+ // Load schema
+ const schemaResp = await fetch('/api/config/schema/dataset-variables')
+ const schemaData = await schemaResp.json()
+
+ if (schemaData.success) {
+ setSchema(schemaData.schema)
+ setUiSchema(schemaData.ui_schema || {})
+ }
+
+ // Load data
+ const dataResp = await fetch('/api/config/dataset-variables')
+ const data = await dataResp.json()
+
+ if (data.success) {
+ setVariables(data.data || { variables: [] })
+ }
+
+ } catch (error) {
+ console.error('Error loading schema/data:', error)
+ setMessage(`Error loading: ${error.message}`)
+ } finally {
+ setLoading(false)
+ }
+ }
+
+ const saveVariables = async (formData) => {
+ setSaving(true)
+ try {
+ const response = await fetch('/api/config/dataset-variables', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(formData)
+ })
+
+ const result = await response.json()
+
+ if (result.success) {
+ setVariables(formData)
+ setMessage('Variables saved successfully')
+ setTimeout(() => setMessage(''), 3000)
+
+ if (onVariablesUpdate) {
+ onVariablesUpdate(formData)
+ }
+ } else {
+ throw new Error(result.error || 'Failed to save variables')
+ }
+ } catch (error) {
+ console.error('Error saving variables:', error)
+ setMessage(`Error saving: ${error.message}`)
+ } finally {
+ setSaving(false)
+ }
+ }
+
+ // Get available datasets for selector
+ const datasetOptions = Object.entries(datasets).map(([id, dataset]) => ({
+ value: id,
+ label: `${dataset.name || id} (${id})`
+ }))
+
+ if (loading) {
+ return (
+
+
+
+
+ Loading dataset variables configuration...
+
+
+
+ )
+ }
+
+ if (!schema) {
+ return (
+
+
+
+
+ Failed to load schema for dataset variables
+
+
+
+ )
+ }
+
+ return (
+
+
+
+ 🔧 Dataset Variables
+
+ Configure PLC variables for each dataset - use symbols or manual configuration
+
+
+ {datasetOptions.length > 0 && (
+
+ Reference Dataset:
+
+
+ )}
+
+
+
+ {message && (
+
+
+ {message}
+
+ )}
+
+
+
+
+ )
+}
diff --git a/frontend/src/components/FormTable.jsx b/frontend/src/components/FormTable.jsx
index baa32c2..5acc097 100644
--- a/frontend/src/components/FormTable.jsx
+++ b/frontend/src/components/FormTable.jsx
@@ -21,7 +21,7 @@ import { AddIcon, DeleteIcon, EditIcon } from '@chakra-ui/icons'
import Form from '@rjsf/chakra-ui'
import validator from '@rjsf/validator-ajv8'
import LayoutObjectFieldTemplate from './rjsf/LayoutObjectFieldTemplate.jsx'
-import { widgets } from './rjsf/widgets.jsx'
+import { allWidgets } from './widgets/AllWidgets.jsx'
/**
* FormTable - Muestra objetos como filas de formularios usando schemas RJSF
@@ -152,7 +152,7 @@ export default function FormTable({
validator={validator}
onSubmit={({ formData }) => handleAdd(formData)}
templates={{ ObjectFieldTemplate: LayoutObjectFieldTemplate }}
- widgets={widgets}
+ widgets={allWidgets}
showErrorList={false}
>
@@ -231,7 +231,7 @@ export default function FormTable({
onChange={editingKey === key ? ({ formData }) => setEditingFormData(formData) : () => { }}
onSubmit={editingKey === key ? ({ formData }) => handleEdit(key, formData) : undefined}
templates={{ ObjectFieldTemplate: LayoutObjectFieldTemplate }}
- widgets={widgets}
+ widgets={allWidgets}
readonly={editingKey !== key}
showErrorList={false}
>
diff --git a/frontend/src/components/widgets/AllWidgets.jsx b/frontend/src/components/widgets/AllWidgets.jsx
index fa1254e..27ea409 100644
--- a/frontend/src/components/widgets/AllWidgets.jsx
+++ b/frontend/src/components/widgets/AllWidgets.jsx
@@ -3,6 +3,7 @@ import { widgets } from '../rjsf/widgets'
import VariableSelectorWidget from '../rjsf/VariableSelectorWidget'
import FilePathWidget from './FilePathWidget'
import SymbolSelectorWidget from './SymbolSelectorWidget'
+import DatasetVariableSymbolWidget from './DatasetVariableSymbolWidget'
// Comprehensive widget collection that merges all available widgets
// for full UI schema support with layouts
@@ -35,6 +36,11 @@ export const allWidgets = {
'symbol-selector': SymbolSelectorWidget,
SymbolSelectorWidget: SymbolSelectorWidget,
+ // Dataset variable symbol widget with auto-fill
+ datasetVariableSymbol: DatasetVariableSymbolWidget,
+ 'dataset-variable-symbol': DatasetVariableSymbolWidget,
+ DatasetVariableSymbolWidget: DatasetVariableSymbolWidget,
+
// PLC-specific widget aliases (if available)
plcArea: widgets.PlcAreaWidget,
plcDataType: widgets.PlcDataTypeWidget,
diff --git a/frontend/src/components/widgets/DatasetVariableSymbolWidget.jsx b/frontend/src/components/widgets/DatasetVariableSymbolWidget.jsx
new file mode 100644
index 0000000..cf36748
--- /dev/null
+++ b/frontend/src/components/widgets/DatasetVariableSymbolWidget.jsx
@@ -0,0 +1,100 @@
+import React, { useState, useEffect } from 'react'
+import {
+ Box,
+ VStack,
+ Text,
+ Badge,
+ useToast
+} from '@chakra-ui/react'
+import SymbolSelectorWidget from './SymbolSelectorWidget'
+
+const DatasetVariableSymbolWidget = ({ value, onChange, label, disabled, readonly, required, placeholder, formContext }) => {
+ const [selectedSymbol, setSelectedSymbol] = useState(null)
+ const toast = useToast()
+
+ // Load symbol details when value changes
+ useEffect(() => {
+ if (value && !selectedSymbol) {
+ loadSymbolDetails(value)
+ }
+ }, [value])
+
+ const loadSymbolDetails = async (symbolName) => {
+ try {
+ const response = await fetch('/api/symbols')
+ const data = await response.json()
+
+ if (data.success && data.symbols) {
+ const symbol = data.symbols.find(s => s.name === symbolName)
+ if (symbol) {
+ setSelectedSymbol(symbol)
+ }
+ }
+ } catch (error) {
+ console.error('Error loading symbol details:', error)
+ }
+ }
+
+ const handleSymbolSelect = (symbolName) => {
+ // Update the symbol field
+ onChange(symbolName)
+
+ // Show success message
+ toast({
+ title: 'Symbol Selected',
+ description: `Selected: ${symbolName}`,
+ status: 'success',
+ duration: 2000,
+ isClosable: true,
+ })
+ }
+
+ const symbolOptions = {
+ onSymbolSelect: (symbol) => {
+ setSelectedSymbol(symbol)
+ handleSymbolSelect(symbol.name)
+ }
+ }
+
+ return (
+
+
+
+ {selectedSymbol && (
+
+
+ Symbol Information:
+
+
+
+ 📝 Name: {selectedSymbol.description || selectedSymbol.name}
+
+
+ 📍 Address: {selectedSymbol.plc_address}
+
+
+ 🔧 Area: {selectedSymbol.area?.toUpperCase()}, Offset: {selectedSymbol.offset}
+ {selectedSymbol.db && `, DB: ${selectedSymbol.db}`}
+ {selectedSymbol.bit !== null && selectedSymbol.bit !== undefined && `, Bit: ${selectedSymbol.bit}`}
+
+
+ {selectedSymbol.data_type}
+
+
+
+ )}
+
+ )
+}
+
+export default DatasetVariableSymbolWidget
diff --git a/frontend/src/components/widgets/SymbolSelectorWidget.jsx b/frontend/src/components/widgets/SymbolSelectorWidget.jsx
index 71b83ce..831f634 100644
--- a/frontend/src/components/widgets/SymbolSelectorWidget.jsx
+++ b/frontend/src/components/widgets/SymbolSelectorWidget.jsx
@@ -26,7 +26,7 @@ import {
} from '@chakra-ui/react'
import { FiSearch, FiX, FiList, FiInfo } from 'react-icons/fi'
-const SymbolSelectorWidget = ({ value, onChange, label, disabled, readonly, required, placeholder }) => {
+const SymbolSelectorWidget = ({ value, onChange, label, disabled, readonly, required, placeholder, formContext, options }) => {
const [symbols, setSymbols] = useState([])
const [searchQuery, setSearchQuery] = useState('')
const [isLoading, setIsLoading] = useState(false)
@@ -92,6 +92,12 @@ const SymbolSelectorWidget = ({ value, onChange, label, disabled, readonly, requ
const handleSymbolSelect = (symbol) => {
setSelectedSymbol(symbol)
onChange(symbol.name)
+
+ // If we have formContext and the widget options include callbacks for auto-fill
+ if (formContext && options && options.onSymbolSelect) {
+ options.onSymbolSelect(symbol)
+ }
+
onClose()
toast({
diff --git a/frontend/src/pages/Dashboard.jsx b/frontend/src/pages/Dashboard.jsx
index 5ee7c2f..29b6680 100644
--- a/frontend/src/pages/Dashboard.jsx
+++ b/frontend/src/pages/Dashboard.jsx
@@ -783,25 +783,60 @@ function DatasetManager() {
items: {
type: "object",
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 }
+ configType: {
+ type: "string",
+ title: "Configuration Type",
+ enum: ["manual", "symbol"],
+ default: "manual"
+ }
},
- required: ["name", "area", "offset", "type"]
+ 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"]
+ }
+ }
+ ]
}
}
}
@@ -810,14 +845,49 @@ function DatasetManager() {
const singleDatasetUiSchema = {
variables: {
items: {
- "ui:layout": [[
- { "name": "name", "width": 3 },
- { "name": "area", "width": 2 },
- { "name": "db", "width": 1 },
- { "name": "offset", "width": 2 },
- { "name": "type", "width": 2 },
- { "name": "streaming", "width": 2 }
- ]]
+ "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": "checkbox",
+ "ui:help": "Enable UDP streaming to PlotJuggler"
+ }
}
}
}
diff --git a/system_state.json b/system_state.json
index 5e5fdcc..b901054 100644
--- a/system_state.json
+++ b/system_state.json
@@ -3,11 +3,11 @@
"should_connect": true,
"should_stream": true,
"active_datasets": [
+ "Fast",
"Test",
- "DAR",
- "Fast"
+ "DAR"
]
},
"auto_recovery_enabled": true,
- "last_update": "2025-08-14T16:52:19.757206"
+ "last_update": "2025-08-14T17:32:09.169720"
}
\ No newline at end of file