Implementación de nuevas funcionalidades en la API y mejoras en la interfaz de usuario
- Se añadió una nueva ruta API para abrir la carpeta de un grupo en el explorador de archivos, mejorando la accesibilidad. - Se implementaron botones en la interfaz para abrir la carpeta del grupo y copiar la ruta del grupo al portapapeles. - Se mejoró la lógica de visualización de botones en la interfaz, permitiendo un mejor manejo de la visibilidad de los mismos. - Se realizaron ajustes en los logs de ejecución para reflejar las nuevas funcionalidades y cambios en los directorios de trabajo.
This commit is contained in:
parent
9ac769e2fc
commit
be3b333491
101
app.py
101
app.py
|
@ -913,6 +913,107 @@ def open_group_in_editor(editor, group_system, group_id):
|
||||||
"message": f"Error al abrir {editor}: {str(e)}"
|
"message": f"Error al abrir {editor}: {str(e)}"
|
||||||
}), 500
|
}), 500
|
||||||
|
|
||||||
|
@app.route("/api/open-group-folder/<group_system>/<group_id>", methods=["POST"])
|
||||||
|
def open_group_folder(group_system, group_id):
|
||||||
|
"""Abrir carpeta de un grupo en el explorador de archivos"""
|
||||||
|
try:
|
||||||
|
# Determinar directorio según el sistema
|
||||||
|
if group_system == 'config':
|
||||||
|
script_group_path = os.path.join(config_manager.script_groups_path, group_id)
|
||||||
|
if not os.path.isdir(script_group_path):
|
||||||
|
return jsonify({
|
||||||
|
"status": "error",
|
||||||
|
"message": f"Directorio del grupo config '{group_id}' no encontrado"
|
||||||
|
}), 404
|
||||||
|
elif group_system == 'launcher':
|
||||||
|
group = launcher_manager.get_launcher_group(group_id)
|
||||||
|
if not group:
|
||||||
|
return jsonify({
|
||||||
|
"status": "error",
|
||||||
|
"message": f"Grupo launcher '{group_id}' no encontrado"
|
||||||
|
}), 404
|
||||||
|
script_group_path = group["directory"]
|
||||||
|
if not os.path.isdir(script_group_path):
|
||||||
|
return jsonify({
|
||||||
|
"status": "error",
|
||||||
|
"message": f"Directorio del grupo launcher '{group['name']}' no encontrado"
|
||||||
|
}), 404
|
||||||
|
else:
|
||||||
|
return jsonify({
|
||||||
|
"status": "error",
|
||||||
|
"message": f"Sistema de grupo '{group_system}' no válido. Usar 'config' o 'launcher'"
|
||||||
|
}), 400
|
||||||
|
|
||||||
|
# Abrir en el explorador según el sistema operativo
|
||||||
|
try:
|
||||||
|
if sys.platform == "win32":
|
||||||
|
os.startfile(script_group_path)
|
||||||
|
elif sys.platform == "darwin": # macOS
|
||||||
|
subprocess.Popen(["open", script_group_path])
|
||||||
|
else: # linux variants
|
||||||
|
subprocess.Popen(["xdg-open", script_group_path])
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
"status": "success",
|
||||||
|
"message": f"Abriendo '{script_group_path}' en el explorador",
|
||||||
|
"path": script_group_path
|
||||||
|
})
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({
|
||||||
|
"status": "error",
|
||||||
|
"message": f"Error al abrir el explorador en '{script_group_path}': {str(e)}"
|
||||||
|
}), 500
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error opening folder for {group_system} group '{group_id}': {str(e)}")
|
||||||
|
return jsonify({
|
||||||
|
"status": "error",
|
||||||
|
"message": f"Error al abrir carpeta: {str(e)}"
|
||||||
|
}), 500
|
||||||
|
|
||||||
|
@app.route("/api/get-group-path/<group_system>/<group_id>", methods=["GET"])
|
||||||
|
def get_group_path(group_system, group_id):
|
||||||
|
"""Obtener el path completo de un grupo de scripts"""
|
||||||
|
try:
|
||||||
|
# Determinar directorio según el sistema
|
||||||
|
if group_system == 'config':
|
||||||
|
script_group_path = os.path.join(config_manager.script_groups_path, group_id)
|
||||||
|
if not os.path.isdir(script_group_path):
|
||||||
|
return jsonify({
|
||||||
|
"status": "error",
|
||||||
|
"message": f"Directorio del grupo config '{group_id}' no encontrado"
|
||||||
|
}), 404
|
||||||
|
elif group_system == 'launcher':
|
||||||
|
group = launcher_manager.get_launcher_group(group_id)
|
||||||
|
if not group:
|
||||||
|
return jsonify({
|
||||||
|
"status": "error",
|
||||||
|
"message": f"Grupo launcher '{group_id}' no encontrado"
|
||||||
|
}), 404
|
||||||
|
script_group_path = group["directory"]
|
||||||
|
if not os.path.isdir(script_group_path):
|
||||||
|
return jsonify({
|
||||||
|
"status": "error",
|
||||||
|
"message": f"Directorio del grupo launcher '{group['name']}' no encontrado"
|
||||||
|
}), 404
|
||||||
|
else:
|
||||||
|
return jsonify({
|
||||||
|
"status": "error",
|
||||||
|
"message": f"Sistema de grupo '{group_system}' no válido. Usar 'config' o 'launcher'"
|
||||||
|
}), 400
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
"status": "success",
|
||||||
|
"path": script_group_path
|
||||||
|
})
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error getting path for {group_system} group '{group_id}': {str(e)}")
|
||||||
|
return jsonify({
|
||||||
|
"status": "error",
|
||||||
|
"message": f"Error al obtener path: {str(e)}"
|
||||||
|
}), 500
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# --- Start Flask in a background thread ---
|
# --- Start Flask in a background thread ---
|
||||||
flask_thread = threading.Thread(target=run_flask, daemon=True)
|
flask_thread = threading.Thread(target=run_flask, daemon=True)
|
||||||
|
|
|
@ -1,39 +1,35 @@
|
||||||
--- Log de Ejecución: x1.py ---
|
--- Log de Ejecución: x1.py ---
|
||||||
Grupo: EmailCrono
|
Grupo: EmailCrono
|
||||||
Directorio de Trabajo: C:\Trabajo\SIDEL\12 - SAE052 - Syrup Update & GSD Update\Reporte\Emails
|
Directorio de Trabajo: C:\Trabajo\SIDEL\14 - E5.007172 - Modifica O&U - SAE340\Reporte\Email
|
||||||
Inicio: 2025-05-18 16:00:44
|
Inicio: 2025-06-09 17:06:35
|
||||||
Fin: 2025-05-18 16:00:44
|
Fin: 2025-06-09 17:06:36
|
||||||
Duración: 0:00:00.445734
|
Duración: 0:00:00.370858
|
||||||
Estado: SUCCESS (Código de Salida: 0)
|
Estado: SUCCESS (Código de Salida: 0)
|
||||||
|
|
||||||
--- SALIDA ESTÁNDAR (STDOUT) ---
|
--- SALIDA ESTÁNDAR (STDOUT) ---
|
||||||
Working directory: C:\Trabajo\SIDEL\12 - SAE052 - Syrup Update & GSD Update\Reporte\Emails
|
Working directory: C:\Trabajo\SIDEL\14 - E5.007172 - Modifica O&U - SAE340\Reporte\Email
|
||||||
Input directory: C:\Trabajo\SIDEL\12 - SAE052 - Syrup Update & GSD Update\Reporte\Emails
|
Input directory: C:\Trabajo\SIDEL\14 - E5.007172 - Modifica O&U - SAE340\Reporte\Email
|
||||||
Output directory: C:/Users/migue/OneDrive/Miguel/Obsidean/Trabajo/VM/04-SIDEL/12 - SAE052 - Syrup Update & GSD Update
|
Output directory: C:/Users/migue/OneDrive/Miguel/Obsidean/Trabajo/VM/04-SIDEL/14 - E5.007172 - Modifica O&U - SAE340
|
||||||
Cronologia file: C:/Users/migue/OneDrive/Miguel/Obsidean/Trabajo/VM/04-SIDEL/12 - SAE052 - Syrup Update & GSD Update\cronologia.md
|
Cronologia file: C:/Users/migue/OneDrive/Miguel/Obsidean/Trabajo/VM/04-SIDEL/14 - E5.007172 - Modifica O&U - SAE340\cronologia.md
|
||||||
Attachments directory: C:\Trabajo\SIDEL\12 - SAE052 - Syrup Update & GSD Update\Reporte\Emails\adjuntos
|
Attachments directory: C:\Trabajo\SIDEL\14 - E5.007172 - Modifica O&U - SAE340\Reporte\Email\adjuntos
|
||||||
Beautify rules file: D:\Proyectos\Scripts\ParamManagerScripts\backend\script_groups\EmailCrono\config\beautify_rules.json
|
Beautify rules file: D:\Proyectos\Scripts\ParamManagerScripts\backend\script_groups\EmailCrono\config\beautify_rules.json
|
||||||
Found 2 .eml files
|
Found 2 .eml files
|
||||||
Loaded 0 existing messages
|
Loaded 0 existing messages
|
||||||
|
|
||||||
Processing C:\Trabajo\SIDEL\12 - SAE052 - Syrup Update & GSD Update\Reporte\Emails\I_ Backup SAE052.eml
|
Processing C:\Trabajo\SIDEL\14 - E5.007172 - Modifica O&U - SAE340\Reporte\Email\E5.007172.eml
|
||||||
Aplicando reglas de prioridad 1
|
Aplicando reglas de prioridad 1
|
||||||
Aplicando reglas de prioridad 2
|
Aplicando reglas de prioridad 2
|
||||||
Aplicando reglas de prioridad 3
|
Aplicando reglas de prioridad 3
|
||||||
Aplicando reglas de prioridad 4
|
Aplicando reglas de prioridad 4
|
||||||
|
|
||||||
Processing C:\Trabajo\SIDEL\12 - SAE052 - Syrup Update & GSD Update\Reporte\Emails\Parametri Modificati SAE052.eml
|
Processing C:\Trabajo\SIDEL\14 - E5.007172 - Modifica O&U - SAE340\Reporte\Email\R_ NOTICE OF GOODS READY ASSIGN ORDER 169423 - Won Opportunity - Services- 169423.A.2.2 - AJETHAI CO., LTD. - Thailand - Filling - Service CRM_0037299==CHECK PAYMENT TERM==E5.007172.eml
|
||||||
Aplicando reglas de prioridad 1
|
|
||||||
Aplicando reglas de prioridad 2
|
|
||||||
Aplicando reglas de prioridad 3
|
|
||||||
Aplicando reglas de prioridad 4
|
|
||||||
|
|
||||||
Estadísticas de procesamiento:
|
Estadísticas de procesamiento:
|
||||||
- Total mensajes encontrados: 2
|
- Total mensajes encontrados: 1
|
||||||
- Mensajes únicos añadidos: 2
|
- Mensajes únicos añadidos: 1
|
||||||
- Mensajes duplicados ignorados: 0
|
- Mensajes duplicados ignorados: 0
|
||||||
|
|
||||||
Writing 2 messages to C:/Users/migue/OneDrive/Miguel/Obsidean/Trabajo/VM/04-SIDEL/12 - SAE052 - Syrup Update & GSD Update\cronologia.md
|
Writing 1 messages to C:/Users/migue/OneDrive/Miguel/Obsidean/Trabajo/VM/04-SIDEL/14 - E5.007172 - Modifica O&U - SAE340\cronologia.md
|
||||||
|
|
||||||
--- ERRORES (STDERR) ---
|
--- ERRORES (STDERR) ---
|
||||||
Ninguno
|
Ninguno
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
"cronologia_file": "cronologia.md"
|
"cronologia_file": "cronologia.md"
|
||||||
},
|
},
|
||||||
"level3": {
|
"level3": {
|
||||||
"output_directory": "C:/Users/migue/OneDrive/Miguel/Obsidean/Trabajo/VM/04-SIDEL/12 - SAE052 - Syrup Update & GSD Update"
|
"output_directory": "C:/Users/migue/OneDrive/Miguel/Obsidean/Trabajo/VM/04-SIDEL/14 - E5.007172 - Modifica O&U - SAE340"
|
||||||
},
|
},
|
||||||
"working_directory": "C:\\Trabajo\\SIDEL\\12 - SAE052 - Syrup Update & GSD Update\\Reporte\\Emails"
|
"working_directory": "C:\\Trabajo\\SIDEL\\14 - E5.007172 - Modifica O&U - SAE340\\Reporte\\Email"
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
"path": "C:\\Trabajo\\SIDEL\\12 - SAE052 - Syrup Update & GSD Update\\Reporte\\Emails",
|
"path": "C:\\Trabajo\\SIDEL\\14 - E5.007172 - Modifica O&U - SAE340\\Reporte\\Email",
|
||||||
"history": [
|
"history": [
|
||||||
|
"C:\\Trabajo\\SIDEL\\14 - E5.007172 - Modifica O&U - SAE340\\Reporte\\Email",
|
||||||
"C:\\Trabajo\\SIDEL\\12 - SAE052 - Syrup Update & GSD Update\\Reporte\\Emails",
|
"C:\\Trabajo\\SIDEL\\12 - SAE052 - Syrup Update & GSD Update\\Reporte\\Emails",
|
||||||
"C:\\Trabajo\\SIDEL\\10 - E5.007095 - Modifica O&U - SAE463\\Reporte\\Email",
|
"C:\\Trabajo\\SIDEL\\10 - E5.007095 - Modifica O&U - SAE463\\Reporte\\Email",
|
||||||
"C:\\Trabajo\\SIDEL\\08 - Masselli TEST\\Reporte\\EMAILs",
|
"C:\\Trabajo\\SIDEL\\08 - Masselli TEST\\Reporte\\EMAILs",
|
||||||
|
@ -9,7 +10,6 @@
|
||||||
"C:\\Trabajo\\VM\\40 - 93040 - HENKEL - NEXT2 Problem\\Reporte\\EmailTody",
|
"C:\\Trabajo\\VM\\40 - 93040 - HENKEL - NEXT2 Problem\\Reporte\\EmailTody",
|
||||||
"C:\\Trabajo\\VM\\30 - 9.3941- Kosme - Portogallo (Modifica + Linea)\\Reporte\\Emails",
|
"C:\\Trabajo\\VM\\30 - 9.3941- Kosme - Portogallo (Modifica + Linea)\\Reporte\\Emails",
|
||||||
"C:\\Users\\migue\\OneDrive\\Miguel\\Obsidean\\Trabajo\\VM\\30 - 9.3941- Kosme - Portogallo (Modifica + Linea)\\Emails",
|
"C:\\Users\\migue\\OneDrive\\Miguel\\Obsidean\\Trabajo\\VM\\30 - 9.3941- Kosme - Portogallo (Modifica + Linea)\\Emails",
|
||||||
"C:\\Trabajo\\VM\\40 - 93040 - HENKEL - NEXT2 Problem\\Reporte\\Emails\\Trial",
|
"C:\\Trabajo\\VM\\40 - 93040 - HENKEL - NEXT2 Problem\\Reporte\\Emails\\Trial"
|
||||||
"C:\\Trabajo\\VM\\40 - 93040 - HENKEL - NEXT2 Problem\\Reporte\\Emails"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
@ -2,49 +2,10 @@
|
||||||
|
|
||||||
| Network | Type | Address | Device Name | Sub-Device | OrderNo | Type | IO Type | IO Address | Number of Bits |
|
| Network | Type | Address | Device Name | Sub-Device | OrderNo | Type | IO Type | IO Address | Number of Bits |
|
||||||
|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|
|
|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.31 | U30110-AxisX | DO SERVO_1 | N/A | DO SERVO | Input | `EW 100..119` | 160 |
|
| PLC Local Modules | Local I/O | Local | PLC A40510 | A41110 | 6ES7 131-6BF01-0BA0 | DI 8x24VDC ST | Input | `EW 0..0` | 8 |
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.31 | U30110-AxisX | DO SERVO_1 | N/A | DO SERVO | Output | `AW 100..119` | 160 |
|
| PLC Local Modules | Local I/O | Local | PLC A40510 | A41111 | 6ES7 131-6BF01-0BA0 | DI 8x24VDC ST | Input | `EW 1..1` | 8 |
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.32 | U30210-AxisY | DO SERVO_1 | N/A | DO SERVO | Input | `EW 120..139` | 160 |
|
| PLC Local Modules | Local I/O | Local | PLC A40510 | A41120 | 6ES7 131-6BF01-0BA0 | DI 8x24VDC ST | Input | `EW 2..2` | 8 |
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.32 | U30210-AxisY | DO SERVO_1 | N/A | DO SERVO | Output | `AW 120..139` | 160 |
|
| PLC Local Modules | Local I/O | Local | PLC A40510 | A41121 | 6ES7 131-6BF01-0BA0 | DI 8x24VDC ST | Input | `EW 3..3` | 8 |
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.33 | U30310 | DO with manufacturer telegr. 102_1 | N/A | DO with manufacturer telegr. 102 | Input | `EW 4..51` | 384 |
|
| PLC Local Modules | Local I/O | Local | PLC A40510 | A41130 | 6ES7 132-6BF01-0BA0 | DQ 8x24VDC/0.5A ST | Output | `AW 0..0` | 8 |
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.33 | U30310 | DO with manufacturer telegr. 102_1 | N/A | DO with manufacturer telegr. 102 | Output | `AW 3..50` | 384 |
|
| PLC Local Modules | Local I/O | Local | PLC A40510 | A41131 | 6ES7 132-6BF01-0BA0 | DQ 8x24VDC/0.5A ST | Output | `AW 1..1` | 8 |
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.34 | U30410 | DO with manufacturer telegr. 102_1 | N/A | DO with manufacturer telegr. 102 | Input | `EW 52..99` | 384 |
|
| PLC Local Modules | Local I/O | Local | PLC A40510 | A41140 | 6ES7 132-6BF01-0BA0 | DQ 8x24VDC/0.5A ST | Output | `AW 2..2` | 8 |
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.34 | U30410 | DO with manufacturer telegr. 102_1 | N/A | DO with manufacturer telegr. 102 | Output | `AW 51..98` | 384 |
|
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.35 | U30510 | DO with manufacturer telegr. 102_1 | N/A | DO with manufacturer telegr. 102 | Input | `EW 156..203` | 384 |
|
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.35 | U30510 | DO with manufacturer telegr. 102_1 | N/A | DO with manufacturer telegr. 102 | Output | `AW 144..191` | 384 |
|
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.36 | U30610 | DO with manufacturer telegr. 102_1 | N/A | DO with manufacturer telegr. 102 | Input | `EW 204..251` | 384 |
|
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.36 | U30610 | DO with manufacturer telegr. 102_1 | N/A | DO with manufacturer telegr. 102 | Output | `AW 192..239` | 384 |
|
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.37 | M30710 | DS402_Extend-A | N/A | N/A | Input | `EW 4066..4087` | 176 |
|
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.37 | M30710 | DS402_Extend-A | N/A | N/A | Output | `AW 4132..4175` | 352 |
|
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.40 | M31010 | Module I/O (08 words) | N/A | Module I/O (08 words) | Input | `EW 272..287` | 128 |
|
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.40 | M31010 | Module I/O (08 words) | N/A | Module I/O (08 words) | Output | `AW 272..287` | 128 |
|
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.41 | M31110 | DS402_Extend-A | N/A | N/A | Input | `EW 4000..4021` | 176 |
|
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.41 | M31110 | DS402_Extend-A | N/A | N/A | Output | `AW 4000..4043` | 352 |
|
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.42 | M31210 | DS402_Extend-A | N/A | N/A | Input | `EW 4022..4043` | 176 |
|
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.42 | M31210 | DS402_Extend-A | N/A | N/A | Output | `AW 4044..4087` | 352 |
|
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.43 | M31310 | DS402_Extend-A | N/A | N/A | Input | `EW 4044..4065` | 176 |
|
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.43 | M31310 | DS402_Extend-A | N/A | N/A | Output | `AW 4088..4131` | 352 |
|
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.44 | M31410 | Module I/O (08 words) | N/A | Module I/O (08 words) | Input | `EW 288..303` | 128 |
|
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.44 | M31410 | Module I/O (08 words) | N/A | Module I/O (08 words) | Output | `AW 288..303` | 128 |
|
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.45 | M31510 | Module I/O (08 words) | N/A | Module I/O (08 words) | Input | `EW 304..319` | 128 |
|
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.45 | M31510 | Module I/O (08 words) | N/A | Module I/O (08 words) | Output | `AW 304..319` | 128 |
|
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.46 | M31610 | DS402_Extend-A | N/A | N/A | Input | `EW 4088..4109` | 176 |
|
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.46 | M31610 | DS402_Extend-A | N/A | N/A | Output | `AW 4176..4219` | 352 |
|
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.47 | M31710 | DS402_Extend-A | N/A | N/A | Input | `EW 4110..4131` | 176 |
|
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.47 | M31710 | DS402_Extend-A | N/A | N/A | Output | `AW 4220..4263` | 352 |
|
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.48 | M31810 | DS402_Extend-A | N/A | N/A | Input | `EW 4132..4153` | 176 |
|
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.48 | M31810 | DS402_Extend-A | N/A | N/A | Output | `AW 4264..4307` | 352 |
|
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.49 | M31910 | DS402_Extend-A | N/A | N/A | Input | `EW 4154..4175` | 176 |
|
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.49 | M31910 | DS402_Extend-A | N/A | N/A | Output | `AW 4308..4351` | 352 |
|
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.70 | M34010 | DS402_Extend-A | N/A | N/A | Input | `EW 4176..4197` | 176 |
|
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.70 | M34010 | DS402_Extend-A | N/A | N/A | Output | `AW 4352..4395` | 352 |
|
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.71 | M34110 | DS402_Extend-A | N/A | N/A | Input | `EW 4198..4219` | 176 |
|
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.71 | M34110 | DS402_Extend-A | N/A | N/A | Output | `AW 4396..4439` | 352 |
|
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.72 | M34210 | DS402_Extend-A | N/A | N/A | Input | `EW 4220..4241` | 176 |
|
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.72 | M34210 | DS402_Extend-A | N/A | N/A | Output | `AW 4440..4483` | 352 |
|
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.73 | M34310 | DS402_Extend-A | N/A | N/A | Input | `EW 4242..4263` | 176 |
|
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.73 | M34310 | DS402_Extend-A | N/A | N/A | Output | `AW 4484..4527` | 352 |
|
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.74 | M34410 | Module I/O (08 words) | N/A | Module I/O (08 words) | Input | `EW 362..377` | 128 |
|
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.74 | M34410 | Module I/O (08 words) | N/A | Module I/O (08 words) | Output | `AW 340..355` | 128 |
|
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.170 | E44010-Encoder | EO Encoder Multiturn V2.x_1 | N/A | N/A | Input | `EW 140..155` | 128 |
|
|
||||||
| PN/IE_1 | Ethernet/Profinet | 10.1.30.170 | E44010-Encoder | EO Encoder Multiturn V2.x_1 | N/A | N/A | Output | `AW 140..143` | 32 |
|
|
|
@ -1,13 +1,13 @@
|
||||||
--- Log de Ejecución: x2_process_CAx.py ---
|
--- Log de Ejecución: x2_process_CAx.py ---
|
||||||
Grupo: IO_adaptation
|
Grupo: IO_adaptation
|
||||||
Directorio de Trabajo: D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia
|
Directorio de Trabajo: D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia
|
||||||
Inicio: 2025-06-07 14:29:10
|
Inicio: 2025-06-08 00:15:28
|
||||||
Fin: 2025-06-07 14:29:16
|
Fin: 2025-06-08 00:15:33
|
||||||
Duración: 0:00:06.140835
|
Duración: 0:00:04.525461
|
||||||
Estado: SUCCESS (Código de Salida: 0)
|
Estado: SUCCESS (Código de Salida: 0)
|
||||||
|
|
||||||
--- SALIDA ESTÁNDAR (STDOUT) ---
|
--- SALIDA ESTÁNDAR (STDOUT) ---
|
||||||
--- AML (CAx Export) to Hierarchical JSON and Obsidian MD Converter (v32.2 - Simplified IO Address Format (Separate Start/End)) ---
|
--- AML (CAx Export) to Hierarchical JSON and Obsidian MD Converter (v32.4 - Fixed Excel Integer Format for IO Addresses) ---
|
||||||
Using configured working directory: D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia
|
Using configured working directory: D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia
|
||||||
Using Working Directory for Output: D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia
|
Using Working Directory for Output: D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia
|
||||||
Input AML: D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\98050_PLC_01.aml
|
Input AML: D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\98050_PLC_01.aml
|
||||||
|
@ -17,45 +17,45 @@ Output IO Debug Tree MD: D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\980
|
||||||
Processing AML file: D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\98050_PLC_01.aml
|
Processing AML file: D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\98050_PLC_01.aml
|
||||||
Pass 1: Found 363 InternalElement(s). Populating device dictionary...
|
Pass 1: Found 363 InternalElement(s). Populating device dictionary...
|
||||||
Pass 2: Identifying PLCs and Networks (Refined v2)...
|
Pass 2: Identifying PLCs and Networks (Refined v2)...
|
||||||
Identified Network: PN/IE_1 (6ce86626-0043-4a58-b675-cc13ac87121c) Type: Ethernet/Profinet
|
Identified Network: PN/IE_1 (f9f048af-beb4-4e14-8a03-dc27e564649c) Type: Ethernet/Profinet
|
||||||
Identified PLC: A40510 (fc0d3bac-267e-488a-8dcf-7dc8599d80e8) - Type: CPU 1514SP T-2 PN OrderNo: 6ES7 514-2VN03-0AB0
|
Identified PLC: A40510 (fc0d3bac-267e-488a-8dcf-7dc8599d80e8) - Type: CPU 1514SP T-2 PN OrderNo: 6ES7 514-2VN03-0AB0
|
||||||
Pass 3: Processing InternalLinks (Robust Network Mapping & IO)...
|
Pass 3: Processing InternalLinks (Robust Network Mapping & IO)...
|
||||||
Found 103 InternalLink(s).
|
Found 103 InternalLink(s).
|
||||||
Mapping Device/Node 'E1' (NodeID:ab796923-4471-4a60-98f4-f8ea5920b3b9, Addr:10.1.30.11) to Network 'PN/IE_1'
|
Mapping Device/Node 'E1' (NodeID:49534400-9e59-4c19-996d-7ad00a2957e9, Addr:10.1.30.11) to Network 'PN/IE_1'
|
||||||
--> Found PLC in children: A40510 (ID: fc0d3bac-267e-488a-8dcf-7dc8599d80e8)
|
--> Found PLC in children: A40510 (ID: fc0d3bac-267e-488a-8dcf-7dc8599d80e8)
|
||||||
--> Associating Network 'PN/IE_1' with PLC 'A40510' (via Node 'E1' Addr: 10.1.30.11)
|
--> Associating Network 'PN/IE_1' with PLC 'A40510' (via Node 'E1' Addr: 10.1.30.11)
|
||||||
Mapping Device/Node 'IE1' (NodeID:c53ae31d-bee4-47ba-950d-15c31d2599b9, Addr:10.1.30.58) to Network 'PN/IE_1'
|
Mapping Device/Node 'IE1' (NodeID:051911c8-9591-4119-a3ee-d6be687b7f9d, Addr:10.1.30.58) to Network 'PN/IE_1'
|
||||||
Mapping Device/Node 'IE1' (NodeID:1a8366c9-7d4c-4e49-b0a3-77d445eabc8b, Addr:10.1.30.59) to Network 'PN/IE_1'
|
Mapping Device/Node 'IE1' (NodeID:83519e1a-0912-4ae5-845b-b82bc743a92c, Addr:10.1.30.59) to Network 'PN/IE_1'
|
||||||
Mapping Device/Node 'IE1' (NodeID:deeda41b-54d0-4c86-82c3-a311f753021e, Addr:10.1.30.60) to Network 'PN/IE_1'
|
Mapping Device/Node 'IE1' (NodeID:2ba93b89-6b43-4a92-850b-8110b9c2efcc, Addr:10.1.30.60) to Network 'PN/IE_1'
|
||||||
Mapping Device/Node 'IE1' (NodeID:8a916a9d-895e-4a12-9190-516ef6a8f191, Addr:10.1.30.61) to Network 'PN/IE_1'
|
Mapping Device/Node 'IE1' (NodeID:b31787f3-2682-4d09-affc-69db1e2b89d3, Addr:10.1.30.61) to Network 'PN/IE_1'
|
||||||
Mapping Device/Node 'IE1' (NodeID:c51471e0-9621-4ef7-b050-09bf4d695ea1, Addr:10.1.30.62) to Network 'PN/IE_1'
|
Mapping Device/Node 'IE1' (NodeID:ef087f66-fd57-4be7-93a7-19497f4f852c, Addr:10.1.30.62) to Network 'PN/IE_1'
|
||||||
Mapping Device/Node 'IE1' (NodeID:77ca312c-3dd0-46f6-bd64-5da69a99cf6f, Addr:10.1.30.63) to Network 'PN/IE_1'
|
Mapping Device/Node 'IE1' (NodeID:6fe53dd5-7093-4245-923f-f4bbce67fabf, Addr:10.1.30.63) to Network 'PN/IE_1'
|
||||||
Mapping Device/Node 'IE1' (NodeID:011019c6-5925-4544-87aa-27288c3aa70c, Addr:10.1.30.64) to Network 'PN/IE_1'
|
Mapping Device/Node 'IE1' (NodeID:59f51321-8469-447f-ace9-05e1495bbafd, Addr:10.1.30.64) to Network 'PN/IE_1'
|
||||||
Mapping Device/Node 'IE1' (NodeID:5ea1e894-b51c-44f9-8aff-80c58c6cb7ef, Addr:10.1.30.65) to Network 'PN/IE_1'
|
Mapping Device/Node 'IE1' (NodeID:60c861c6-1889-4bde-9d16-1c625116aece, Addr:10.1.30.65) to Network 'PN/IE_1'
|
||||||
Mapping Device/Node 'IE1' (NodeID:612916a9-7a26-4712-9de2-d3c7894db862, Addr:10.1.30.66) to Network 'PN/IE_1'
|
Mapping Device/Node 'IE1' (NodeID:4f6ad448-3a75-4e48-8107-83634ba6d192, Addr:10.1.30.66) to Network 'PN/IE_1'
|
||||||
Mapping Device/Node 'IE1' (NodeID:7be7cf9f-f7af-418c-8fe4-96b4a97a581d, Addr:10.1.30.31) to Network 'PN/IE_1'
|
Mapping Device/Node 'IE1' (NodeID:b2153a8e-6526-4831-b2a1-5cf3da07c062, Addr:10.1.30.31) to Network 'PN/IE_1'
|
||||||
Mapping Device/Node 'IE1' (NodeID:135492a8-02ab-4236-92ce-7a5585538297, Addr:10.1.30.32) to Network 'PN/IE_1'
|
Mapping Device/Node 'IE1' (NodeID:08066980-9963-4ca3-9a5d-1d9de9b611a3, Addr:10.1.30.32) to Network 'PN/IE_1'
|
||||||
Mapping Device/Node 'IE1' (NodeID:b7a06147-6428-4d95-ba0d-834fad49a1ae, Addr:10.1.30.170) to Network 'PN/IE_1'
|
Mapping Device/Node 'IE1' (NodeID:2acb9ba4-f0f9-4fc6-9fd9-4592c1c8ef5a, Addr:10.1.30.170) to Network 'PN/IE_1'
|
||||||
Mapping Device/Node 'IE1' (NodeID:7ce83bdf-dc4d-40f0-85c8-a246dd2c44be, Addr:10.1.30.33) to Network 'PN/IE_1'
|
Mapping Device/Node 'IE1' (NodeID:feda1ddb-816d-40bd-a88c-8b1bc310c424, Addr:10.1.30.33) to Network 'PN/IE_1'
|
||||||
Mapping Device/Node 'IE1' (NodeID:e9a07506-2869-4c34-8541-ee021d1623f0, Addr:10.1.30.34) to Network 'PN/IE_1'
|
Mapping Device/Node 'IE1' (NodeID:80a42e65-b1b1-4a48-b4ea-f95ca4032021, Addr:10.1.30.34) to Network 'PN/IE_1'
|
||||||
Mapping Device/Node 'IE1' (NodeID:3dd0f886-c3d0-4628-804b-ae18cf5931e8, Addr:10.1.30.35) to Network 'PN/IE_1'
|
Mapping Device/Node 'IE1' (NodeID:082ca69e-92aa-43c5-982b-2b134e5ca9ea, Addr:10.1.30.35) to Network 'PN/IE_1'
|
||||||
Mapping Device/Node 'IE1' (NodeID:67c3fa72-a956-4363-9a4d-e3300d7d1429, Addr:10.1.30.36) to Network 'PN/IE_1'
|
Mapping Device/Node 'IE1' (NodeID:96aef85c-66f1-4792-94fd-f9ad5bb41d62, Addr:10.1.30.36) to Network 'PN/IE_1'
|
||||||
Mapping Device/Node 'IE1' (NodeID:b35e73e8-a9ad-47e2-8ad5-00442c7a2df7, Addr:10.1.30.40) to Network 'PN/IE_1'
|
Mapping Device/Node 'IE1' (NodeID:9b791861-b139-4a7d-b7ba-ebe195bbaf2c, Addr:10.1.30.40) to Network 'PN/IE_1'
|
||||||
Mapping Device/Node 'IE1' (NodeID:867d0580-06cd-4722-a66f-8c5559b624f5, Addr:10.1.30.44) to Network 'PN/IE_1'
|
Mapping Device/Node 'IE1' (NodeID:5085a882-dc3c-4794-9c0a-4821a9ecbf24, Addr:10.1.30.44) to Network 'PN/IE_1'
|
||||||
Mapping Device/Node 'IE1' (NodeID:6f1b4062-80ac-4d1a-b351-546c9d0157e2, Addr:10.1.30.41) to Network 'PN/IE_1'
|
Mapping Device/Node 'IE1' (NodeID:0ea5739f-aa85-46b8-958f-9b6ce2960d6d, Addr:10.1.30.41) to Network 'PN/IE_1'
|
||||||
Mapping Device/Node 'IE1' (NodeID:c0016a06-48cc-47af-83aa-d4a0a6cb44f6, Addr:10.1.30.42) to Network 'PN/IE_1'
|
Mapping Device/Node 'IE1' (NodeID:1f6cec79-c24c-4b0f-8aec-47d49ea1ce81, Addr:10.1.30.42) to Network 'PN/IE_1'
|
||||||
Mapping Device/Node 'IE1' (NodeID:07fa5e8f-ffcf-4d81-9897-5ff9f73d6125, Addr:10.1.30.43) to Network 'PN/IE_1'
|
Mapping Device/Node 'IE1' (NodeID:ab6516fc-5061-437d-bdc1-529d79d3d42a, Addr:10.1.30.43) to Network 'PN/IE_1'
|
||||||
Mapping Device/Node 'IE1' (NodeID:5e8a4449-c958-4397-8b71-877af262333b, Addr:10.1.30.37) to Network 'PN/IE_1'
|
Mapping Device/Node 'IE1' (NodeID:3f7bbecb-2bb9-42e8-8668-4a102c98873b, Addr:10.1.30.37) to Network 'PN/IE_1'
|
||||||
Mapping Device/Node 'IE1' (NodeID:79096325-dcb8-4650-bc44-2c9735a93f52, Addr:10.1.30.45) to Network 'PN/IE_1'
|
Mapping Device/Node 'IE1' (NodeID:6807d26a-ff0f-4ce7-89b9-8785cf5310ae, Addr:10.1.30.45) to Network 'PN/IE_1'
|
||||||
Mapping Device/Node 'IE1' (NodeID:957e5975-eafe-477c-a682-bebf330a2868, Addr:10.1.30.46) to Network 'PN/IE_1'
|
Mapping Device/Node 'IE1' (NodeID:4c58e397-5fda-4076-bd52-374ba80460cb, Addr:10.1.30.46) to Network 'PN/IE_1'
|
||||||
Mapping Device/Node 'IE1' (NodeID:379ccd79-27b4-4b53-a552-3da783bc5b25, Addr:10.1.30.47) to Network 'PN/IE_1'
|
Mapping Device/Node 'IE1' (NodeID:36da4ca9-6dc1-489a-bbdc-d124bf125dad, Addr:10.1.30.47) to Network 'PN/IE_1'
|
||||||
Mapping Device/Node 'IE1' (NodeID:b53dd719-e8af-431f-b837-a0903ffb3a76, Addr:10.1.30.48) to Network 'PN/IE_1'
|
Mapping Device/Node 'IE1' (NodeID:02213f0f-cc1f-4d97-ba86-eb3d11f7cb5b, Addr:10.1.30.48) to Network 'PN/IE_1'
|
||||||
Mapping Device/Node 'IE1' (NodeID:0f28d88a-5208-4fc4-8ee1-f1bb33a947e8, Addr:10.1.30.49) to Network 'PN/IE_1'
|
Mapping Device/Node 'IE1' (NodeID:628bab85-5b77-4335-9444-48f51dec6e66, Addr:10.1.30.49) to Network 'PN/IE_1'
|
||||||
Mapping Device/Node 'IE1' (NodeID:d1f8ea18-50d2-410e-9966-136d8a79471d, Addr:10.1.30.70) to Network 'PN/IE_1'
|
Mapping Device/Node 'IE1' (NodeID:5800b36d-59bb-43f6-8857-5b616730246d, Addr:10.1.30.70) to Network 'PN/IE_1'
|
||||||
Mapping Device/Node 'IE1' (NodeID:1c86a627-5646-45e7-9c21-5d18d6544568, Addr:10.1.30.71) to Network 'PN/IE_1'
|
Mapping Device/Node 'IE1' (NodeID:b68a427c-e7f6-459a-9e6a-39b76a4497ad, Addr:10.1.30.71) to Network 'PN/IE_1'
|
||||||
Mapping Device/Node 'IE1' (NodeID:e80a9939-59d7-44e0-9a46-1fade44e1b78, Addr:10.1.30.72) to Network 'PN/IE_1'
|
Mapping Device/Node 'IE1' (NodeID:d4bad7e1-0461-4dbb-b797-cb45a75225d9, Addr:10.1.30.72) to Network 'PN/IE_1'
|
||||||
Mapping Device/Node 'IE1' (NodeID:8c51fa26-883a-468c-8c36-c0e1b31852e4, Addr:10.1.30.74) to Network 'PN/IE_1'
|
Mapping Device/Node 'IE1' (NodeID:145f1526-6b77-4ea7-968b-de89a7bbeda2, Addr:10.1.30.74) to Network 'PN/IE_1'
|
||||||
Mapping Device/Node 'IE1' (NodeID:17be2ccc-dede-4187-ba77-1ad8499a7349, Addr:10.1.30.73) to Network 'PN/IE_1'
|
Mapping Device/Node 'IE1' (NodeID:8cde4014-94bb-47be-aacd-32f1915152d2, Addr:10.1.30.73) to Network 'PN/IE_1'
|
||||||
Data extraction and structuring complete.
|
Data extraction and structuring complete.
|
||||||
Generating JSON output: D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\98050_PLC_01.hierarchical.json
|
Generating JSON output: D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\98050_PLC_01.hierarchical.json
|
||||||
JSON data written successfully.
|
JSON data written successfully.
|
||||||
|
|
|
@ -1,18 +1,21 @@
|
||||||
--- Log de Ejecución: x3_excel_to_md.py ---
|
--- Log de Ejecución: x3_excel_to_md.py ---
|
||||||
Grupo: IO_adaptation
|
Grupo: IO_adaptation
|
||||||
Directorio de Trabajo: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2
|
Directorio de Trabajo: D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia
|
||||||
Inicio: 2025-05-15 11:58:03
|
Inicio: 2025-06-08 13:21:43
|
||||||
Fin: 2025-05-15 11:58:05
|
Fin: 2025-06-08 13:22:12
|
||||||
Duración: 0:00:01.664065
|
Duración: 0:00:29.516302
|
||||||
Estado: SUCCESS (Código de Salida: 0)
|
Estado: SUCCESS (Código de Salida: 0)
|
||||||
|
|
||||||
--- SALIDA ESTÁNDAR (STDOUT) ---
|
--- SALIDA ESTÁNDAR (STDOUT) ---
|
||||||
Usando directorio de trabajo: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2
|
Usando directorio de trabajo: D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia
|
||||||
Configuración de paths cargada desde: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2\io_paths_config.json
|
Configuración de paths cargada desde: D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\io_paths_config.json
|
||||||
Usando archivo Excel predeterminado: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2\PLCTags.xlsx
|
Archivo PLCTags.xlsx no encontrado. Seleccione el archivo Excel exportado de TIA Portal:
|
||||||
Procesando archivo Excel: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2\PLCTags.xlsx...
|
Procesando archivo Excel: D:/Trabajo/VM/44 - 98050 - Fiera/Reporte/ExportsTia/PLCTagsv_02.xlsx...
|
||||||
Paths configurados para procesar: ['Inputs', 'Outputs', 'OutputsFesto', 'IO Not in Hardware\\InputsMaster', 'IO Not in Hardware\\OutputsMaster']
|
Paths configurados para procesar: ['Inputs', 'Outputs', 'OutputsFesto', 'IO Not in Hardware\\InputsMaster', 'IO Not in Hardware\\OutputsMaster']
|
||||||
¡Éxito! Archivo Excel convertido a Markdown en: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2\Master IO Tags.md
|
No se encontraron entradas para el path: OutputsFesto
|
||||||
|
No se encontraron entradas para el path: IO Not in Hardware\InputsMaster
|
||||||
|
No se encontraron entradas para el path: IO Not in Hardware\OutputsMaster
|
||||||
|
¡Éxito! Archivo Excel convertido a Markdown en: D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\Master IO Tags.md
|
||||||
|
|
||||||
--- ERRORES (STDERR) ---
|
--- ERRORES (STDERR) ---
|
||||||
Ninguno
|
Ninguno
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
--- Log de Ejecución: x4_prompt_generator.py ---
|
--- Log de Ejecución: x4_prompt_generator.py ---
|
||||||
Grupo: IO_adaptation
|
Grupo: IO_adaptation
|
||||||
Directorio de Trabajo: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2
|
Directorio de Trabajo: D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia
|
||||||
Inicio: 2025-05-15 14:05:02
|
Inicio: 2025-06-08 11:05:58
|
||||||
Fin: 2025-05-15 14:05:04
|
Fin: 2025-06-08 11:06:03
|
||||||
Duración: 0:00:01.643930
|
Duración: 0:00:04.909042
|
||||||
Estado: SUCCESS (Código de Salida: 0)
|
Estado: SUCCESS (Código de Salida: 0)
|
||||||
|
|
||||||
--- SALIDA ESTÁNDAR (STDOUT) ---
|
--- SALIDA ESTÁNDAR (STDOUT) ---
|
||||||
Generador de prompt para adaptación de IO
|
Generador de prompt para adaptación de IO
|
||||||
=========================================
|
=========================================
|
||||||
Usando directorio de trabajo: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2
|
Usando directorio de trabajo: D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia
|
||||||
Usando ruta de Obsidian desde configuración: C:\Users\migue\OneDrive\Miguel\Obsidean\Trabajo\VM\04-SIDEL\00 - MASTER\MIXER\IO
|
Usando ruta de Obsidian desde configuración: C:\Users\migue\OneDrive\Miguel\Obsidean\Trabajo\VM\04-SIDEL\00 - MASTER\MIXER\IO
|
||||||
Usando carpeta de equivalencias en Obsidian: C:\Users\migue\OneDrive\Miguel\Obsidean\Trabajo\VM\04-SIDEL\00 - MASTER\MIXER\IO
|
Usando carpeta de equivalencias en Obsidian: C:\Users\migue\OneDrive\Miguel\Obsidean\Trabajo\VM\04-SIDEL\00 - MASTER\MIXER\IO
|
||||||
¡Prompt generado y copiado al portapapeles con éxito!
|
¡Prompt generado y copiado al portapapeles con éxito!
|
||||||
Prompt guardado en: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2\IO_Adaptation_Prompt.txt
|
Prompt guardado en: D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\IO_Adaptation_Prompt.txt
|
||||||
|
|
||||||
--- ERRORES (STDERR) ---
|
--- ERRORES (STDERR) ---
|
||||||
Ninguno
|
Ninguno
|
||||||
|
|
|
@ -0,0 +1,657 @@
|
||||||
|
--- Log de Ejecución: x7_update_CAx.py ---
|
||||||
|
Grupo: IO_adaptation
|
||||||
|
Directorio de Trabajo: D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia
|
||||||
|
Inicio: 2025-06-07 18:57:44
|
||||||
|
Fin: 2025-06-07 18:57:53
|
||||||
|
Duración: 0:00:08.646157
|
||||||
|
Estado: SUCCESS (Código de Salida: 0)
|
||||||
|
|
||||||
|
--- SALIDA ESTÁNDAR (STDOUT) ---
|
||||||
|
--- Actualizador de AML desde Excel Modificado (v1.4 - Enhanced Address Element Search with Debug) ---
|
||||||
|
Directorio de trabajo: D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia
|
||||||
|
|
||||||
|
1. Seleccione el archivo AML original:
|
||||||
|
|
||||||
|
2. Seleccione el archivo Excel modificado:
|
||||||
|
|
||||||
|
Archivo AML original: D:/Trabajo/VM/44 - 98050 - Fiera/Reporte/ExportsTia/98050_PLC_01.aml
|
||||||
|
Archivo Excel modificado: D:/Trabajo/VM/44 - 98050 - Fiera/Reporte/ExportsTia/A40510/Documentation/98050_PLC_01_IO_Report.xlsx
|
||||||
|
|
||||||
|
Usando directorio temporal: C:\Users\migue\AppData\Local\Temp\tmplzmtjbwx
|
||||||
|
Generando Excel de referencia desde AML original...
|
||||||
|
Pass 1: Found 363 InternalElement(s). Populating device dictionary...
|
||||||
|
Pass 2: Identifying PLCs and Networks (Refined v2)...
|
||||||
|
Identified Network: PN/IE_1 (6ce86626-0043-4a58-b675-cc13ac87121c) Type: Ethernet/Profinet
|
||||||
|
Identified PLC: A40510 (fc0d3bac-267e-488a-8dcf-7dc8599d80e8) - Type: CPU 1514SP T-2 PN OrderNo: 6ES7 514-2VN03-0AB0
|
||||||
|
Pass 3: Processing InternalLinks (Robust Network Mapping & IO)...
|
||||||
|
Found 103 InternalLink(s).
|
||||||
|
Mapping Device/Node 'E1' (NodeID:ab796923-4471-4a60-98f4-f8ea5920b3b9, Addr:10.1.30.11) to Network 'PN/IE_1'
|
||||||
|
--> Found PLC in children: A40510 (ID: fc0d3bac-267e-488a-8dcf-7dc8599d80e8)
|
||||||
|
--> Associating Network 'PN/IE_1' with PLC 'A40510' (via Node 'E1' Addr: 10.1.30.11)
|
||||||
|
Mapping Device/Node 'IE1' (NodeID:c53ae31d-bee4-47ba-950d-15c31d2599b9, Addr:10.1.30.58) to Network 'PN/IE_1'
|
||||||
|
Mapping Device/Node 'IE1' (NodeID:1a8366c9-7d4c-4e49-b0a3-77d445eabc8b, Addr:10.1.30.59) to Network 'PN/IE_1'
|
||||||
|
Mapping Device/Node 'IE1' (NodeID:deeda41b-54d0-4c86-82c3-a311f753021e, Addr:10.1.30.60) to Network 'PN/IE_1'
|
||||||
|
Mapping Device/Node 'IE1' (NodeID:8a916a9d-895e-4a12-9190-516ef6a8f191, Addr:10.1.30.61) to Network 'PN/IE_1'
|
||||||
|
Mapping Device/Node 'IE1' (NodeID:c51471e0-9621-4ef7-b050-09bf4d695ea1, Addr:10.1.30.62) to Network 'PN/IE_1'
|
||||||
|
Mapping Device/Node 'IE1' (NodeID:77ca312c-3dd0-46f6-bd64-5da69a99cf6f, Addr:10.1.30.63) to Network 'PN/IE_1'
|
||||||
|
Mapping Device/Node 'IE1' (NodeID:011019c6-5925-4544-87aa-27288c3aa70c, Addr:10.1.30.64) to Network 'PN/IE_1'
|
||||||
|
Mapping Device/Node 'IE1' (NodeID:5ea1e894-b51c-44f9-8aff-80c58c6cb7ef, Addr:10.1.30.65) to Network 'PN/IE_1'
|
||||||
|
Mapping Device/Node 'IE1' (NodeID:612916a9-7a26-4712-9de2-d3c7894db862, Addr:10.1.30.66) to Network 'PN/IE_1'
|
||||||
|
Mapping Device/Node 'IE1' (NodeID:7be7cf9f-f7af-418c-8fe4-96b4a97a581d, Addr:10.1.30.31) to Network 'PN/IE_1'
|
||||||
|
Mapping Device/Node 'IE1' (NodeID:135492a8-02ab-4236-92ce-7a5585538297, Addr:10.1.30.32) to Network 'PN/IE_1'
|
||||||
|
Mapping Device/Node 'IE1' (NodeID:b7a06147-6428-4d95-ba0d-834fad49a1ae, Addr:10.1.30.170) to Network 'PN/IE_1'
|
||||||
|
Mapping Device/Node 'IE1' (NodeID:7ce83bdf-dc4d-40f0-85c8-a246dd2c44be, Addr:10.1.30.33) to Network 'PN/IE_1'
|
||||||
|
Mapping Device/Node 'IE1' (NodeID:e9a07506-2869-4c34-8541-ee021d1623f0, Addr:10.1.30.34) to Network 'PN/IE_1'
|
||||||
|
Mapping Device/Node 'IE1' (NodeID:3dd0f886-c3d0-4628-804b-ae18cf5931e8, Addr:10.1.30.35) to Network 'PN/IE_1'
|
||||||
|
Mapping Device/Node 'IE1' (NodeID:67c3fa72-a956-4363-9a4d-e3300d7d1429, Addr:10.1.30.36) to Network 'PN/IE_1'
|
||||||
|
Mapping Device/Node 'IE1' (NodeID:b35e73e8-a9ad-47e2-8ad5-00442c7a2df7, Addr:10.1.30.40) to Network 'PN/IE_1'
|
||||||
|
Mapping Device/Node 'IE1' (NodeID:867d0580-06cd-4722-a66f-8c5559b624f5, Addr:10.1.30.44) to Network 'PN/IE_1'
|
||||||
|
Mapping Device/Node 'IE1' (NodeID:6f1b4062-80ac-4d1a-b351-546c9d0157e2, Addr:10.1.30.41) to Network 'PN/IE_1'
|
||||||
|
Mapping Device/Node 'IE1' (NodeID:c0016a06-48cc-47af-83aa-d4a0a6cb44f6, Addr:10.1.30.42) to Network 'PN/IE_1'
|
||||||
|
Mapping Device/Node 'IE1' (NodeID:07fa5e8f-ffcf-4d81-9897-5ff9f73d6125, Addr:10.1.30.43) to Network 'PN/IE_1'
|
||||||
|
Mapping Device/Node 'IE1' (NodeID:5e8a4449-c958-4397-8b71-877af262333b, Addr:10.1.30.37) to Network 'PN/IE_1'
|
||||||
|
Mapping Device/Node 'IE1' (NodeID:79096325-dcb8-4650-bc44-2c9735a93f52, Addr:10.1.30.45) to Network 'PN/IE_1'
|
||||||
|
Mapping Device/Node 'IE1' (NodeID:957e5975-eafe-477c-a682-bebf330a2868, Addr:10.1.30.46) to Network 'PN/IE_1'
|
||||||
|
Mapping Device/Node 'IE1' (NodeID:379ccd79-27b4-4b53-a552-3da783bc5b25, Addr:10.1.30.47) to Network 'PN/IE_1'
|
||||||
|
Mapping Device/Node 'IE1' (NodeID:b53dd719-e8af-431f-b837-a0903ffb3a76, Addr:10.1.30.48) to Network 'PN/IE_1'
|
||||||
|
Mapping Device/Node 'IE1' (NodeID:0f28d88a-5208-4fc4-8ee1-f1bb33a947e8, Addr:10.1.30.49) to Network 'PN/IE_1'
|
||||||
|
Mapping Device/Node 'IE1' (NodeID:d1f8ea18-50d2-410e-9966-136d8a79471d, Addr:10.1.30.70) to Network 'PN/IE_1'
|
||||||
|
Mapping Device/Node 'IE1' (NodeID:1c86a627-5646-45e7-9c21-5d18d6544568, Addr:10.1.30.71) to Network 'PN/IE_1'
|
||||||
|
Mapping Device/Node 'IE1' (NodeID:e80a9939-59d7-44e0-9a46-1fade44e1b78, Addr:10.1.30.72) to Network 'PN/IE_1'
|
||||||
|
Mapping Device/Node 'IE1' (NodeID:8c51fa26-883a-468c-8c36-c0e1b31852e4, Addr:10.1.30.74) to Network 'PN/IE_1'
|
||||||
|
Mapping Device/Node 'IE1' (NodeID:17be2ccc-dede-4187-ba77-1ad8499a7349, Addr:10.1.30.73) to Network 'PN/IE_1'
|
||||||
|
Data extraction and structuring complete.
|
||||||
|
Generating Excel IO report for PLC: A40510
|
||||||
|
Excel IO report saved to: C:\Users\migue\AppData\Local\Temp\tmplzmtjbwx\temp_plc_fc0d3bac-267e-488a-8dcf-7dc8599d80e8.xlsx
|
||||||
|
Total rows in report: 33
|
||||||
|
Comparando archivos Excel...
|
||||||
|
Estructura básica validada correctamente.
|
||||||
|
Detectados 22 dispositivos con cambios.
|
||||||
|
A40510+U30210-AxisY: ['IO Input Start Address', 'IO Output Start Address']
|
||||||
|
A40510+E44010-Encoder: ['IO Input Start Address', 'IO Output Start Address']
|
||||||
|
A40510+U30310: ['IO Input Start Address', 'IO Output Start Address']
|
||||||
|
A40510+U30410: ['IO Input Start Address', 'IO Output Start Address']
|
||||||
|
A40510+U30510: ['IO Input Start Address', 'IO Output Start Address']
|
||||||
|
A40510+U30610: ['IO Input Start Address', 'IO Output Start Address']
|
||||||
|
A40510+M31010: ['IO Input Start Address', 'IO Output Start Address']
|
||||||
|
A40510+M31410: ['IO Input Start Address', 'IO Output Start Address']
|
||||||
|
A40510+M31110: ['IO Input Start Address', 'IO Output Start Address']
|
||||||
|
A40510+M31210: ['IO Input Start Address', 'IO Output Start Address']
|
||||||
|
A40510+M31310: ['IO Input Start Address', 'IO Output Start Address']
|
||||||
|
A40510+M30710: ['IO Input Start Address', 'IO Output Start Address']
|
||||||
|
A40510+M31510: ['IO Input Start Address', 'IO Output Start Address']
|
||||||
|
A40510+M31610: ['IO Input Start Address', 'IO Output Start Address']
|
||||||
|
A40510+M31710: ['IO Input Start Address', 'IO Output Start Address']
|
||||||
|
A40510+M31810: ['IO Input Start Address', 'IO Output Start Address']
|
||||||
|
A40510+M31910: ['IO Input Start Address', 'IO Output Start Address']
|
||||||
|
A40510+M34010: ['IO Input Start Address', 'IO Output Start Address']
|
||||||
|
A40510+M34110: ['IO Input Start Address', 'IO Output Start Address']
|
||||||
|
A40510+M34210: ['IO Input Start Address', 'IO Output Start Address']
|
||||||
|
A40510+M34410: ['IO Input Start Address', 'IO Output Start Address']
|
||||||
|
A40510+M34310: ['IO Input Start Address', 'IO Output Start Address']
|
||||||
|
|
||||||
|
Cargando archivo AML original...
|
||||||
|
Aplicando cambios al archivo AML...
|
||||||
|
Procesando cambios para: A40510+U30210-AxisY
|
||||||
|
Debug: Encontrado dispositivo - node_id: 135492a8-02ab-4236-92ce-7a5585538297, display_id: 0eef2113-ec3f-4c2f-8448-fa7456a6140d
|
||||||
|
Debug: Usando elemento XML con ID 0eef2113-ec3f-4c2f-8448-fa7456a6140d
|
||||||
|
Debug: Buscando elementos Address en dispositivo U30210-AxisY
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: ¡Encontrado elemento Input compatible!
|
||||||
|
✓ IO Input Start Address actualizada: 120 -> 112
|
||||||
|
Debug: Buscando elementos Address en dispositivo U30210-AxisY
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: Revisando sub-elemento: 2
|
||||||
|
Debug: Encontrado IoType: Output
|
||||||
|
Debug: ¡Encontrado elemento Output compatible!
|
||||||
|
✓ IO Output Start Address actualizada: 120 -> 112
|
||||||
|
Procesando cambios para: A40510+E44010-Encoder
|
||||||
|
Debug: Encontrado dispositivo - node_id: b7a06147-6428-4d95-ba0d-834fad49a1ae, display_id: e59b0b92-6c37-45d5-aa9b-8dae625e5272
|
||||||
|
Debug: Usando elemento XML con ID e59b0b92-6c37-45d5-aa9b-8dae625e5272
|
||||||
|
Debug: Buscando elementos Address en dispositivo E44010-Encoder
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: ¡Encontrado elemento Input compatible!
|
||||||
|
✓ IO Input Start Address actualizada: 140 -> 574
|
||||||
|
Debug: Buscando elementos Address en dispositivo E44010-Encoder
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: Revisando sub-elemento: 2
|
||||||
|
Debug: Encontrado IoType: Output
|
||||||
|
Debug: ¡Encontrado elemento Output compatible!
|
||||||
|
✓ IO Output Start Address actualizada: 140 -> 574
|
||||||
|
Procesando cambios para: A40510+U30310
|
||||||
|
Debug: Encontrado dispositivo - node_id: 7ce83bdf-dc4d-40f0-85c8-a246dd2c44be, display_id: 98a3e87d-176b-42b9-a606-fd97b54bc54b
|
||||||
|
Debug: Usando elemento XML con ID 98a3e87d-176b-42b9-a606-fd97b54bc54b
|
||||||
|
Debug: Buscando elementos Address en dispositivo U30310
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: ¡Encontrado elemento Input compatible!
|
||||||
|
✓ IO Input Start Address actualizada: 4 -> 124
|
||||||
|
Debug: Buscando elementos Address en dispositivo U30310
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: Revisando sub-elemento: 2
|
||||||
|
Debug: Encontrado IoType: Output
|
||||||
|
Debug: ¡Encontrado elemento Output compatible!
|
||||||
|
✓ IO Output Start Address actualizada: 3 -> 124
|
||||||
|
Procesando cambios para: A40510+U30410
|
||||||
|
Debug: Encontrado dispositivo - node_id: e9a07506-2869-4c34-8541-ee021d1623f0, display_id: 1fcdf8b4-7c90-48e0-bb72-f29eef363705
|
||||||
|
Debug: Usando elemento XML con ID 1fcdf8b4-7c90-48e0-bb72-f29eef363705
|
||||||
|
Debug: Buscando elementos Address en dispositivo U30410
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: ¡Encontrado elemento Input compatible!
|
||||||
|
✓ IO Input Start Address actualizada: 52 -> 150
|
||||||
|
Debug: Buscando elementos Address en dispositivo U30410
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: Revisando sub-elemento: 2
|
||||||
|
Debug: Encontrado IoType: Output
|
||||||
|
Debug: ¡Encontrado elemento Output compatible!
|
||||||
|
✓ IO Output Start Address actualizada: 51 -> 150
|
||||||
|
Procesando cambios para: A40510+U30510
|
||||||
|
Debug: Encontrado dispositivo - node_id: 3dd0f886-c3d0-4628-804b-ae18cf5931e8, display_id: 44004215-6e6f-456c-9c97-164ee1f8e7b7
|
||||||
|
Debug: Usando elemento XML con ID 44004215-6e6f-456c-9c97-164ee1f8e7b7
|
||||||
|
Debug: Buscando elementos Address en dispositivo U30510
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: ¡Encontrado elemento Input compatible!
|
||||||
|
✓ IO Input Start Address actualizada: 156 -> 176
|
||||||
|
Debug: Buscando elementos Address en dispositivo U30510
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: Revisando sub-elemento: 2
|
||||||
|
Debug: Encontrado IoType: Output
|
||||||
|
Debug: ¡Encontrado elemento Output compatible!
|
||||||
|
✓ IO Output Start Address actualizada: 144 -> 176
|
||||||
|
Procesando cambios para: A40510+U30610
|
||||||
|
Debug: Encontrado dispositivo - node_id: 67c3fa72-a956-4363-9a4d-e3300d7d1429, display_id: 2ea5ad51-0411-413d-8bb5-dfd0655592cf
|
||||||
|
Debug: Usando elemento XML con ID 2ea5ad51-0411-413d-8bb5-dfd0655592cf
|
||||||
|
Debug: Buscando elementos Address en dispositivo U30610
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: ¡Encontrado elemento Input compatible!
|
||||||
|
✓ IO Input Start Address actualizada: 204 -> 202
|
||||||
|
Debug: Buscando elementos Address en dispositivo U30610
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: Revisando sub-elemento: 2
|
||||||
|
Debug: Encontrado IoType: Output
|
||||||
|
Debug: ¡Encontrado elemento Output compatible!
|
||||||
|
✓ IO Output Start Address actualizada: 192 -> 202
|
||||||
|
Procesando cambios para: A40510+M31010
|
||||||
|
Debug: Encontrado dispositivo - node_id: b35e73e8-a9ad-47e2-8ad5-00442c7a2df7, display_id: 4e0722c0-9114-40bf-8452-733e5d275591
|
||||||
|
Debug: Usando elemento XML con ID 4e0722c0-9114-40bf-8452-733e5d275591
|
||||||
|
Debug: Buscando elementos Address en dispositivo M31010
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: ¡Encontrado elemento Input compatible!
|
||||||
|
✓ IO Input Start Address actualizada: 272 -> 252
|
||||||
|
Debug: Buscando elementos Address en dispositivo M31010
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: Revisando sub-elemento: 2
|
||||||
|
Debug: Encontrado IoType: Output
|
||||||
|
Debug: ¡Encontrado elemento Output compatible!
|
||||||
|
✓ IO Output Start Address actualizada: 272 -> 252
|
||||||
|
Procesando cambios para: A40510+M31410
|
||||||
|
Debug: Encontrado dispositivo - node_id: 867d0580-06cd-4722-a66f-8c5559b624f5, display_id: 6530fefc-0f00-45c5-b33a-9c009bf83e7b
|
||||||
|
Debug: Usando elemento XML con ID 6530fefc-0f00-45c5-b33a-9c009bf83e7b
|
||||||
|
Debug: Buscando elementos Address en dispositivo M31410
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: ¡Encontrado elemento Input compatible!
|
||||||
|
✓ IO Input Start Address actualizada: 288 -> 334
|
||||||
|
Debug: Buscando elementos Address en dispositivo M31410
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: Revisando sub-elemento: 2
|
||||||
|
Debug: Encontrado IoType: Output
|
||||||
|
Debug: ¡Encontrado elemento Output compatible!
|
||||||
|
✓ IO Output Start Address actualizada: 288 -> 334
|
||||||
|
Procesando cambios para: A40510+M31110
|
||||||
|
Debug: Encontrado dispositivo - node_id: 6f1b4062-80ac-4d1a-b351-546c9d0157e2, display_id: 95cedabf-d2b0-4d17-a36d-668d1b6db6d8
|
||||||
|
Debug: Usando elemento XML con ID 95cedabf-d2b0-4d17-a36d-668d1b6db6d8
|
||||||
|
Debug: Buscando elementos Address en dispositivo M31110
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: ¡Encontrado elemento Input compatible!
|
||||||
|
✓ IO Input Start Address actualizada: 4000 -> 262
|
||||||
|
Debug: Buscando elementos Address en dispositivo M31110
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: Revisando sub-elemento: 2
|
||||||
|
Debug: Encontrado IoType: Output
|
||||||
|
Debug: ¡Encontrado elemento Output compatible!
|
||||||
|
✓ IO Output Start Address actualizada: 4000 -> 262
|
||||||
|
Procesando cambios para: A40510+M31210
|
||||||
|
Debug: Encontrado dispositivo - node_id: c0016a06-48cc-47af-83aa-d4a0a6cb44f6, display_id: 1739a036-2231-4791-947b-9fa19eac922e
|
||||||
|
Debug: Usando elemento XML con ID 1739a036-2231-4791-947b-9fa19eac922e
|
||||||
|
Debug: Buscando elementos Address en dispositivo M31210
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: ¡Encontrado elemento Input compatible!
|
||||||
|
✓ IO Input Start Address actualizada: 4022 -> 286
|
||||||
|
Debug: Buscando elementos Address en dispositivo M31210
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: Revisando sub-elemento: 2
|
||||||
|
Debug: Encontrado IoType: Output
|
||||||
|
Debug: ¡Encontrado elemento Output compatible!
|
||||||
|
✓ IO Output Start Address actualizada: 4044 -> 286
|
||||||
|
Procesando cambios para: A40510+M31310
|
||||||
|
Debug: Encontrado dispositivo - node_id: 07fa5e8f-ffcf-4d81-9897-5ff9f73d6125, display_id: 90c971fa-0bdd-4dba-8d04-f6eb4dd940cc
|
||||||
|
Debug: Usando elemento XML con ID 90c971fa-0bdd-4dba-8d04-f6eb4dd940cc
|
||||||
|
Debug: Buscando elementos Address en dispositivo M31310
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: ¡Encontrado elemento Input compatible!
|
||||||
|
✓ IO Input Start Address actualizada: 4044 -> 310
|
||||||
|
Debug: Buscando elementos Address en dispositivo M31310
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: Revisando sub-elemento: 2
|
||||||
|
Debug: Encontrado IoType: Output
|
||||||
|
Debug: ¡Encontrado elemento Output compatible!
|
||||||
|
✓ IO Output Start Address actualizada: 4088 -> 310
|
||||||
|
Procesando cambios para: A40510+M30710
|
||||||
|
Debug: Encontrado dispositivo - node_id: 5e8a4449-c958-4397-8b71-877af262333b, display_id: b2f6e277-b969-4581-b3ed-4ca0bafe9994
|
||||||
|
Debug: Usando elemento XML con ID b2f6e277-b969-4581-b3ed-4ca0bafe9994
|
||||||
|
Debug: Buscando elementos Address en dispositivo M30710
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: ¡Encontrado elemento Input compatible!
|
||||||
|
✓ IO Input Start Address actualizada: 4066 -> 228
|
||||||
|
Debug: Buscando elementos Address en dispositivo M30710
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: Revisando sub-elemento: 2
|
||||||
|
Debug: Encontrado IoType: Output
|
||||||
|
Debug: ¡Encontrado elemento Output compatible!
|
||||||
|
✓ IO Output Start Address actualizada: 4132 -> 228
|
||||||
|
Procesando cambios para: A40510+M31510
|
||||||
|
Debug: Encontrado dispositivo - node_id: 79096325-dcb8-4650-bc44-2c9735a93f52, display_id: d6fa2c62-51ab-4f68-a0f9-d86b2d52c1a9
|
||||||
|
Debug: Usando elemento XML con ID d6fa2c62-51ab-4f68-a0f9-d86b2d52c1a9
|
||||||
|
Debug: Buscando elementos Address en dispositivo M31510
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: ¡Encontrado elemento Input compatible!
|
||||||
|
✓ IO Input Start Address actualizada: 304 -> 344
|
||||||
|
Debug: Buscando elementos Address en dispositivo M31510
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: Revisando sub-elemento: 2
|
||||||
|
Debug: Encontrado IoType: Output
|
||||||
|
Debug: ¡Encontrado elemento Output compatible!
|
||||||
|
✓ IO Output Start Address actualizada: 304 -> 344
|
||||||
|
Procesando cambios para: A40510+M31610
|
||||||
|
Debug: Encontrado dispositivo - node_id: 957e5975-eafe-477c-a682-bebf330a2868, display_id: 0a03a25f-121e-4e6a-ab81-f017d170ba52
|
||||||
|
Debug: Usando elemento XML con ID 0a03a25f-121e-4e6a-ab81-f017d170ba52
|
||||||
|
Debug: Buscando elementos Address en dispositivo M31610
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: ¡Encontrado elemento Input compatible!
|
||||||
|
✓ IO Input Start Address actualizada: 4088 -> 354
|
||||||
|
Debug: Buscando elementos Address en dispositivo M31610
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: Revisando sub-elemento: 2
|
||||||
|
Debug: Encontrado IoType: Output
|
||||||
|
Debug: ¡Encontrado elemento Output compatible!
|
||||||
|
✓ IO Output Start Address actualizada: 4176 -> 354
|
||||||
|
Procesando cambios para: A40510+M31710
|
||||||
|
Debug: Encontrado dispositivo - node_id: 379ccd79-27b4-4b53-a552-3da783bc5b25, display_id: 8d6214bd-7a77-462f-a2bf-8de1dccc0db2
|
||||||
|
Debug: Usando elemento XML con ID 8d6214bd-7a77-462f-a2bf-8de1dccc0db2
|
||||||
|
Debug: Buscando elementos Address en dispositivo M31710
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: ¡Encontrado elemento Input compatible!
|
||||||
|
✓ IO Input Start Address actualizada: 4110 -> 378
|
||||||
|
Debug: Buscando elementos Address en dispositivo M31710
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: Revisando sub-elemento: 2
|
||||||
|
Debug: Encontrado IoType: Output
|
||||||
|
Debug: ¡Encontrado elemento Output compatible!
|
||||||
|
✓ IO Output Start Address actualizada: 4220 -> 378
|
||||||
|
Procesando cambios para: A40510+M31810
|
||||||
|
Debug: Encontrado dispositivo - node_id: b53dd719-e8af-431f-b837-a0903ffb3a76, display_id: 9d4ba8bc-a7e7-40a0-99d1-f2fd88a6b00d
|
||||||
|
Debug: Usando elemento XML con ID 9d4ba8bc-a7e7-40a0-99d1-f2fd88a6b00d
|
||||||
|
Debug: Buscando elementos Address en dispositivo M31810
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: ¡Encontrado elemento Input compatible!
|
||||||
|
✓ IO Input Start Address actualizada: 4132 -> 402
|
||||||
|
Debug: Buscando elementos Address en dispositivo M31810
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: Revisando sub-elemento: 2
|
||||||
|
Debug: Encontrado IoType: Output
|
||||||
|
Debug: ¡Encontrado elemento Output compatible!
|
||||||
|
✓ IO Output Start Address actualizada: 4264 -> 402
|
||||||
|
Procesando cambios para: A40510+M31910
|
||||||
|
Debug: Encontrado dispositivo - node_id: 0f28d88a-5208-4fc4-8ee1-f1bb33a947e8, display_id: 0c0c14f0-df2b-4c5e-8163-f7cb58788dae
|
||||||
|
Debug: Usando elemento XML con ID 0c0c14f0-df2b-4c5e-8163-f7cb58788dae
|
||||||
|
Debug: Buscando elementos Address en dispositivo M31910
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: ¡Encontrado elemento Input compatible!
|
||||||
|
✓ IO Input Start Address actualizada: 4154 -> 426
|
||||||
|
Debug: Buscando elementos Address en dispositivo M31910
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: Revisando sub-elemento: 2
|
||||||
|
Debug: Encontrado IoType: Output
|
||||||
|
Debug: ¡Encontrado elemento Output compatible!
|
||||||
|
✓ IO Output Start Address actualizada: 4308 -> 426
|
||||||
|
Procesando cambios para: A40510+M34010
|
||||||
|
Debug: Encontrado dispositivo - node_id: d1f8ea18-50d2-410e-9966-136d8a79471d, display_id: a01c051b-9abc-4947-9632-6dcad7da84b8
|
||||||
|
Debug: Usando elemento XML con ID a01c051b-9abc-4947-9632-6dcad7da84b8
|
||||||
|
Debug: Buscando elementos Address en dispositivo M34010
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: ¡Encontrado elemento Input compatible!
|
||||||
|
✓ IO Input Start Address actualizada: 4176 -> 468
|
||||||
|
Debug: Buscando elementos Address en dispositivo M34010
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: Revisando sub-elemento: 2
|
||||||
|
Debug: Encontrado IoType: Output
|
||||||
|
Debug: ¡Encontrado elemento Output compatible!
|
||||||
|
✓ IO Output Start Address actualizada: 4352 -> 468
|
||||||
|
Procesando cambios para: A40510+M34110
|
||||||
|
Debug: Encontrado dispositivo - node_id: 1c86a627-5646-45e7-9c21-5d18d6544568, display_id: d2440b5d-132e-4d66-986c-fe42a8ff4f74
|
||||||
|
Debug: Usando elemento XML con ID d2440b5d-132e-4d66-986c-fe42a8ff4f74
|
||||||
|
Debug: Buscando elementos Address en dispositivo M34110
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: ¡Encontrado elemento Input compatible!
|
||||||
|
✓ IO Input Start Address actualizada: 4198 -> 492
|
||||||
|
Debug: Buscando elementos Address en dispositivo M34110
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: Revisando sub-elemento: 2
|
||||||
|
Debug: Encontrado IoType: Output
|
||||||
|
Debug: ¡Encontrado elemento Output compatible!
|
||||||
|
✓ IO Output Start Address actualizada: 4396 -> 492
|
||||||
|
Procesando cambios para: A40510+M34210
|
||||||
|
Debug: Encontrado dispositivo - node_id: e80a9939-59d7-44e0-9a46-1fade44e1b78, display_id: 041fea68-1b2b-4087-be60-b254def81cf6
|
||||||
|
Debug: Usando elemento XML con ID 041fea68-1b2b-4087-be60-b254def81cf6
|
||||||
|
Debug: Buscando elementos Address en dispositivo M34210
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: ¡Encontrado elemento Input compatible!
|
||||||
|
✓ IO Input Start Address actualizada: 4220 -> 516
|
||||||
|
Debug: Buscando elementos Address en dispositivo M34210
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: Revisando sub-elemento: 2
|
||||||
|
Debug: Encontrado IoType: Output
|
||||||
|
Debug: ¡Encontrado elemento Output compatible!
|
||||||
|
✓ IO Output Start Address actualizada: 4440 -> 516
|
||||||
|
Procesando cambios para: A40510+M34410
|
||||||
|
Debug: Encontrado dispositivo - node_id: 8c51fa26-883a-468c-8c36-c0e1b31852e4, display_id: 28037fc6-dc45-4ec9-bea0-eafb922f6c6e
|
||||||
|
Debug: Usando elemento XML con ID 28037fc6-dc45-4ec9-bea0-eafb922f6c6e
|
||||||
|
Debug: Buscando elementos Address en dispositivo M34410
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: ¡Encontrado elemento Input compatible!
|
||||||
|
✓ IO Input Start Address actualizada: 362 -> 564
|
||||||
|
Debug: Buscando elementos Address en dispositivo M34410
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: Revisando sub-elemento: 2
|
||||||
|
Debug: Encontrado IoType: Output
|
||||||
|
Debug: ¡Encontrado elemento Output compatible!
|
||||||
|
✓ IO Output Start Address actualizada: 340 -> 564
|
||||||
|
Procesando cambios para: A40510+M34310
|
||||||
|
Debug: Encontrado dispositivo - node_id: 17be2ccc-dede-4187-ba77-1ad8499a7349, display_id: 7a77a815-8c59-4cfd-81fe-d851a8e57aea
|
||||||
|
Debug: Usando elemento XML con ID 7a77a815-8c59-4cfd-81fe-d851a8e57aea
|
||||||
|
Debug: Buscando elementos Address en dispositivo M34310
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: ¡Encontrado elemento Input compatible!
|
||||||
|
✓ IO Input Start Address actualizada: 4242 -> 540
|
||||||
|
Debug: Buscando elementos Address en dispositivo M34310
|
||||||
|
Debug: No se encontró Address directo, buscando en elementos hijos...
|
||||||
|
Debug: No se encontró Address en hijos, buscando en elementos padre...
|
||||||
|
Debug: Encontrados 1 elemento(s) Address
|
||||||
|
Debug: Explorando Address element...
|
||||||
|
Debug: Encontrados 2 sub-elementos en Address
|
||||||
|
Debug: Revisando sub-elemento: 1
|
||||||
|
Debug: Encontrado IoType: Input
|
||||||
|
Debug: Revisando sub-elemento: 2
|
||||||
|
Debug: Encontrado IoType: Output
|
||||||
|
Debug: ¡Encontrado elemento Output compatible!
|
||||||
|
✓ IO Output Start Address actualizada: 4484 -> 540
|
||||||
|
Total de cambios aplicados: 44
|
||||||
|
Archivo AML actualizado guardado en: D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\98050_PLC_01_updated.aml
|
||||||
|
|
||||||
|
¡Proceso completado exitosamente!
|
||||||
|
Archivo AML actualizado: D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\98050_PLC_01_updated.aml
|
||||||
|
|
||||||
|
--- ERRORES (STDERR) ---
|
||||||
|
D:\Proyectos\Scripts\ParamManagerScripts\backend\script_groups\IO_adaptation\x7_update_CAx.py:532: FutureWarning: Truth-testing of elements was a source of confusion and will always return True in future versions. Use specific 'len(elem)' or 'elem is not None' test instead.
|
||||||
|
if target_io_element:
|
||||||
|
D:\Proyectos\Scripts\ParamManagerScripts\backend\script_groups\IO_adaptation\x7_update_CAx.py:535: FutureWarning: Truth-testing of elements was a source of confusion and will always return True in future versions. Use specific 'len(elem)' or 'elem is not None' test instead.
|
||||||
|
if not target_io_element:
|
||||||
|
|
||||||
|
--- FIN DEL LOG ---
|
|
@ -70,5 +70,23 @@
|
||||||
"short_description": "Sin descripción corta.",
|
"short_description": "Sin descripción corta.",
|
||||||
"long_description": "",
|
"long_description": "",
|
||||||
"hidden": false
|
"hidden": false
|
||||||
|
},
|
||||||
|
"debug_hierarchy.py": {
|
||||||
|
"display_name": "debug_hierarchy",
|
||||||
|
"short_description": "Sin descripción corta.",
|
||||||
|
"long_description": "",
|
||||||
|
"hidden": false
|
||||||
|
},
|
||||||
|
"debug_io_processing.py": {
|
||||||
|
"display_name": "debug_io_processing",
|
||||||
|
"short_description": "Sin descripción corta.",
|
||||||
|
"long_description": "",
|
||||||
|
"hidden": false
|
||||||
|
},
|
||||||
|
"debug_table_generation.py": {
|
||||||
|
"display_name": "debug_table_generation",
|
||||||
|
"short_description": "Sin descripción corta.",
|
||||||
|
"long_description": "",
|
||||||
|
"hidden": false
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -554,10 +554,131 @@ def generate_io_excel_report(project_data, excel_file_path, target_plc_id, outpu
|
||||||
# Lista para almacenar todas las filas del Excel
|
# Lista para almacenar todas las filas del Excel
|
||||||
excel_rows = []
|
excel_rows = []
|
||||||
|
|
||||||
|
# v32.5: First, process PLC's local modules (modules in the same rack/structure as the PLC)
|
||||||
|
plc_parent_id = plc_info.get("parent_id")
|
||||||
|
if plc_parent_id:
|
||||||
|
# Find sibling modules in the same parent structure (rack)
|
||||||
|
for dev_id, dev_info in project_data.get("devices", {}).items():
|
||||||
|
if dev_info.get("parent_id") == plc_parent_id and dev_id != target_plc_id:
|
||||||
|
# This is a sibling module of the PLC
|
||||||
|
module_context = {
|
||||||
|
"id": dev_id,
|
||||||
|
"name": dev_info.get("name", dev_id),
|
||||||
|
"order_number": dev_info.get("order_number", "N/A"),
|
||||||
|
"type_name": dev_info.get("type_name", "N/A")
|
||||||
|
}
|
||||||
|
module_ios = find_io_recursively(dev_id, project_data, module_context)
|
||||||
|
if module_ios:
|
||||||
|
# Agrupar IOs por módulo para este módulo local
|
||||||
|
ios_by_module = {}
|
||||||
|
for addr_info in module_ios:
|
||||||
|
module_id = addr_info.get("module_id")
|
||||||
|
if module_id not in ios_by_module:
|
||||||
|
ios_by_module[module_id] = {
|
||||||
|
'module_info': {
|
||||||
|
'name': addr_info.get('module_name', '?'),
|
||||||
|
'type': addr_info.get('module_type_name', 'N/A'),
|
||||||
|
'order': addr_info.get('module_order_number', 'N/A'),
|
||||||
|
'position': addr_info.get('module_pos', 'N/A')
|
||||||
|
},
|
||||||
|
'inputs': [],
|
||||||
|
'outputs': []
|
||||||
|
}
|
||||||
|
|
||||||
|
# Clasificar IO como input u output
|
||||||
|
io_type = addr_info.get("type", "").lower()
|
||||||
|
if io_type == "input":
|
||||||
|
ios_by_module[module_id]['inputs'].append(addr_info)
|
||||||
|
elif io_type == "output":
|
||||||
|
ios_by_module[module_id]['outputs'].append(addr_info)
|
||||||
|
|
||||||
|
# Crear una fila por cada módulo local con IOs
|
||||||
|
for module_id, module_data in ios_by_module.items():
|
||||||
|
module_info = module_data['module_info']
|
||||||
|
|
||||||
|
# Calcular direcciones de entrada - Start + Word Count
|
||||||
|
input_start_addr = 'N/A'
|
||||||
|
input_word_count = 0
|
||||||
|
total_input_bits = 0
|
||||||
|
|
||||||
|
for addr_info in module_data['inputs']:
|
||||||
|
start_str = addr_info.get("start", "?")
|
||||||
|
length_str = addr_info.get("length", "?")
|
||||||
|
try:
|
||||||
|
start_byte = int(start_str)
|
||||||
|
length_bits = int(length_str)
|
||||||
|
length_bytes = math.ceil(length_bits / 8.0)
|
||||||
|
if length_bits > 0 and length_bytes == 0:
|
||||||
|
length_bytes = 1
|
||||||
|
|
||||||
|
# Para múltiples rangos, tomar el primer inicio y sumar words
|
||||||
|
if input_start_addr == 'N/A':
|
||||||
|
input_start_addr = start_byte
|
||||||
|
else:
|
||||||
|
input_start_addr = min(input_start_addr, start_byte)
|
||||||
|
|
||||||
|
# Convertir bytes a words (asumiendo words de 2 bytes)
|
||||||
|
word_count = math.ceil(length_bytes / 2.0)
|
||||||
|
input_word_count += word_count
|
||||||
|
total_input_bits += length_bits
|
||||||
|
except:
|
||||||
|
# En caso de error, mantener N/A
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Calcular direcciones de salida - Start + Word Count
|
||||||
|
output_start_addr = 'N/A'
|
||||||
|
output_word_count = 0
|
||||||
|
total_output_bits = 0
|
||||||
|
|
||||||
|
for addr_info in module_data['outputs']:
|
||||||
|
start_str = addr_info.get("start", "?")
|
||||||
|
length_str = addr_info.get("length", "?")
|
||||||
|
try:
|
||||||
|
start_byte = int(start_str)
|
||||||
|
length_bits = int(length_str)
|
||||||
|
length_bytes = math.ceil(length_bits / 8.0)
|
||||||
|
if length_bits > 0 and length_bytes == 0:
|
||||||
|
length_bytes = 1
|
||||||
|
|
||||||
|
# Para múltiples rangos, tomar el primer inicio y sumar words
|
||||||
|
if output_start_addr == 'N/A':
|
||||||
|
output_start_addr = start_byte
|
||||||
|
else:
|
||||||
|
output_start_addr = min(output_start_addr, start_byte)
|
||||||
|
|
||||||
|
# Convertir bytes a words (asumiendo words de 2 bytes)
|
||||||
|
word_count = math.ceil(length_bytes / 2.0)
|
||||||
|
output_word_count += word_count
|
||||||
|
total_output_bits += length_bits
|
||||||
|
except:
|
||||||
|
# En caso de error, mantener N/A
|
||||||
|
pass
|
||||||
|
|
||||||
|
excel_rows.append({
|
||||||
|
'PLC Name': plc_name,
|
||||||
|
'Network Path': f"Local I/O -> {module_info['name']}",
|
||||||
|
'Network Type': 'Local I/O',
|
||||||
|
'Device Address': 'Local',
|
||||||
|
'Device Name': f"PLC {plc_name}",
|
||||||
|
'Device Type': module_info['type'],
|
||||||
|
'Order Number': module_info['order'],
|
||||||
|
'Firmware Version': 'N/A',
|
||||||
|
'Position': module_info['position'],
|
||||||
|
'IO Input Start Address': input_start_addr,
|
||||||
|
'IO Input Word Count': input_word_count if input_word_count > 0 else 'N/A',
|
||||||
|
'IO Output Start Address': output_start_addr,
|
||||||
|
'IO Output Word Count': output_word_count if output_word_count > 0 else 'N/A',
|
||||||
|
'Total Input Bits': total_input_bits,
|
||||||
|
'Total Output Bits': total_output_bits,
|
||||||
|
'Module Name': module_info['name'],
|
||||||
|
'Module Type': module_info['type'],
|
||||||
|
'Module Order Number': module_info['order']
|
||||||
|
})
|
||||||
|
|
||||||
# Procesar las redes conectadas al PLC
|
# Procesar las redes conectadas al PLC
|
||||||
plc_networks = plc_info.get("connected_networks", {})
|
plc_networks = plc_info.get("connected_networks", {})
|
||||||
|
|
||||||
if not plc_networks:
|
if not plc_networks and not excel_rows:
|
||||||
# Si no hay redes, crear una fila básica del PLC
|
# Si no hay redes, crear una fila básica del PLC
|
||||||
excel_rows.append({
|
excel_rows.append({
|
||||||
'PLC Name': plc_name,
|
'PLC Name': plc_name,
|
||||||
|
@ -570,9 +691,9 @@ def generate_io_excel_report(project_data, excel_file_path, target_plc_id, outpu
|
||||||
'Firmware Version': plc_info.get("firmware_version", "N/A"),
|
'Firmware Version': plc_info.get("firmware_version", "N/A"),
|
||||||
'Position': plc_info.get("position", "N/A"),
|
'Position': plc_info.get("position", "N/A"),
|
||||||
'IO Input Start Address': 'N/A',
|
'IO Input Start Address': 'N/A',
|
||||||
'IO Input End Address': 'N/A',
|
'IO Input Word Count': 'N/A',
|
||||||
'IO Output Start Address': 'N/A',
|
'IO Output Start Address': 'N/A',
|
||||||
'IO Output End Address': 'N/A',
|
'IO Output Word Count': 'N/A',
|
||||||
'Total Input Bits': 0,
|
'Total Input Bits': 0,
|
||||||
'Total Output Bits': 0,
|
'Total Output Bits': 0,
|
||||||
'Module Name': 'N/A',
|
'Module Name': 'N/A',
|
||||||
|
@ -619,9 +740,9 @@ def generate_io_excel_report(project_data, excel_file_path, target_plc_id, outpu
|
||||||
'Firmware Version': plc_info.get("firmware_version", "N/A"),
|
'Firmware Version': plc_info.get("firmware_version", "N/A"),
|
||||||
'Position': plc_info.get("position", "N/A"),
|
'Position': plc_info.get("position", "N/A"),
|
||||||
'IO Input Start Address': 'N/A',
|
'IO Input Start Address': 'N/A',
|
||||||
'IO Input End Address': 'N/A',
|
'IO Input Word Count': 'N/A',
|
||||||
'IO Output Start Address': 'N/A',
|
'IO Output Start Address': 'N/A',
|
||||||
'IO Output End Address': 'N/A',
|
'IO Output Word Count': 'N/A',
|
||||||
'Total Input Bits': 0,
|
'Total Input Bits': 0,
|
||||||
'Total Output Bits': 0,
|
'Total Output Bits': 0,
|
||||||
'Module Name': 'PLC Main Unit',
|
'Module Name': 'PLC Main Unit',
|
||||||
|
@ -721,9 +842,9 @@ def generate_io_excel_report(project_data, excel_file_path, target_plc_id, outpu
|
||||||
for module_id, module_data in ios_by_module.items():
|
for module_id, module_data in ios_by_module.items():
|
||||||
module_info = module_data['module_info']
|
module_info = module_data['module_info']
|
||||||
|
|
||||||
# Calcular direcciones de entrada - formato simplificado
|
# Calcular direcciones de entrada - Start + Word Count
|
||||||
input_start_addr = 'N/A'
|
input_start_addr = 'N/A'
|
||||||
input_end_addr = 'N/A'
|
input_word_count = 0
|
||||||
total_input_bits = 0
|
total_input_bits = 0
|
||||||
|
|
||||||
for addr_info in module_data['inputs']:
|
for addr_info in module_data['inputs']:
|
||||||
|
@ -735,24 +856,24 @@ def generate_io_excel_report(project_data, excel_file_path, target_plc_id, outpu
|
||||||
length_bytes = math.ceil(length_bits / 8.0)
|
length_bytes = math.ceil(length_bits / 8.0)
|
||||||
if length_bits > 0 and length_bytes == 0:
|
if length_bits > 0 and length_bytes == 0:
|
||||||
length_bytes = 1
|
length_bytes = 1
|
||||||
end_byte = start_byte + length_bytes - 1
|
|
||||||
|
|
||||||
# Para múltiples rangos, tomar el primer inicio y último fin
|
# Para múltiples rangos, tomar el primer inicio y sumar words
|
||||||
if input_start_addr == 'N/A':
|
if input_start_addr == 'N/A':
|
||||||
input_start_addr = start_byte
|
input_start_addr = start_byte
|
||||||
input_end_addr = end_byte
|
|
||||||
else:
|
else:
|
||||||
input_start_addr = min(input_start_addr, start_byte)
|
input_start_addr = min(input_start_addr, start_byte)
|
||||||
input_end_addr = max(input_end_addr, end_byte)
|
|
||||||
|
|
||||||
|
# Convertir bytes a words (asumiendo words de 2 bytes)
|
||||||
|
word_count = math.ceil(length_bytes / 2.0)
|
||||||
|
input_word_count += word_count
|
||||||
total_input_bits += length_bits
|
total_input_bits += length_bits
|
||||||
except:
|
except:
|
||||||
# En caso de error, mantener N/A
|
# En caso de error, mantener N/A
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Calcular direcciones de salida - formato simplificado
|
# Calcular direcciones de salida - Start + Word Count
|
||||||
output_start_addr = 'N/A'
|
output_start_addr = 'N/A'
|
||||||
output_end_addr = 'N/A'
|
output_word_count = 0
|
||||||
total_output_bits = 0
|
total_output_bits = 0
|
||||||
|
|
||||||
for addr_info in module_data['outputs']:
|
for addr_info in module_data['outputs']:
|
||||||
|
@ -764,16 +885,16 @@ def generate_io_excel_report(project_data, excel_file_path, target_plc_id, outpu
|
||||||
length_bytes = math.ceil(length_bits / 8.0)
|
length_bytes = math.ceil(length_bits / 8.0)
|
||||||
if length_bits > 0 and length_bytes == 0:
|
if length_bits > 0 and length_bytes == 0:
|
||||||
length_bytes = 1
|
length_bytes = 1
|
||||||
end_byte = start_byte + length_bytes - 1
|
|
||||||
|
|
||||||
# Para múltiples rangos, tomar el primer inicio y último fin
|
# Para múltiples rangos, tomar el primer inicio y sumar words
|
||||||
if output_start_addr == 'N/A':
|
if output_start_addr == 'N/A':
|
||||||
output_start_addr = start_byte
|
output_start_addr = start_byte
|
||||||
output_end_addr = end_byte
|
|
||||||
else:
|
else:
|
||||||
output_start_addr = min(output_start_addr, start_byte)
|
output_start_addr = min(output_start_addr, start_byte)
|
||||||
output_end_addr = max(output_end_addr, end_byte)
|
|
||||||
|
|
||||||
|
# Convertir bytes a words (asumiendo words de 2 bytes)
|
||||||
|
word_count = math.ceil(length_bytes / 2.0)
|
||||||
|
output_word_count += word_count
|
||||||
total_output_bits += length_bits
|
total_output_bits += length_bits
|
||||||
except:
|
except:
|
||||||
# En caso de error, mantener N/A
|
# En caso de error, mantener N/A
|
||||||
|
@ -790,9 +911,9 @@ def generate_io_excel_report(project_data, excel_file_path, target_plc_id, outpu
|
||||||
'Firmware Version': firmware_version,
|
'Firmware Version': firmware_version,
|
||||||
'Position': device_position,
|
'Position': device_position,
|
||||||
'IO Input Start Address': input_start_addr,
|
'IO Input Start Address': input_start_addr,
|
||||||
'IO Input End Address': input_end_addr,
|
'IO Input Word Count': input_word_count if input_word_count > 0 else 'N/A',
|
||||||
'IO Output Start Address': output_start_addr,
|
'IO Output Start Address': output_start_addr,
|
||||||
'IO Output End Address': output_end_addr,
|
'IO Output Word Count': output_word_count if output_word_count > 0 else 'N/A',
|
||||||
'Total Input Bits': total_input_bits,
|
'Total Input Bits': total_input_bits,
|
||||||
'Total Output Bits': total_output_bits,
|
'Total Output Bits': total_output_bits,
|
||||||
'Module Name': module_info['name'],
|
'Module Name': module_info['name'],
|
||||||
|
@ -812,9 +933,9 @@ def generate_io_excel_report(project_data, excel_file_path, target_plc_id, outpu
|
||||||
'Firmware Version': firmware_version,
|
'Firmware Version': firmware_version,
|
||||||
'Position': device_position,
|
'Position': device_position,
|
||||||
'IO Input Start Address': 'N/A',
|
'IO Input Start Address': 'N/A',
|
||||||
'IO Input End Address': 'N/A',
|
'IO Input Word Count': 'N/A',
|
||||||
'IO Output Start Address': 'N/A',
|
'IO Output Start Address': 'N/A',
|
||||||
'IO Output End Address': 'N/A',
|
'IO Output Word Count': 'N/A',
|
||||||
'Total Input Bits': 0,
|
'Total Input Bits': 0,
|
||||||
'Total Output Bits': 0,
|
'Total Output Bits': 0,
|
||||||
'Module Name': 'N/A',
|
'Module Name': 'N/A',
|
||||||
|
@ -834,12 +955,24 @@ def generate_io_excel_report(project_data, excel_file_path, target_plc_id, outpu
|
||||||
'PLC Name', 'Network Path', 'Network Type', 'Device Address', 'Device Name',
|
'PLC Name', 'Network Path', 'Network Type', 'Device Address', 'Device Name',
|
||||||
'Device Type', 'Order Number', 'Firmware Version', 'Position',
|
'Device Type', 'Order Number', 'Firmware Version', 'Position',
|
||||||
'Module Name', 'Module Type', 'Module Order Number',
|
'Module Name', 'Module Type', 'Module Order Number',
|
||||||
'IO Input Start Address', 'IO Input End Address', 'IO Output Start Address', 'IO Output End Address',
|
'IO Input Start Address', 'IO Input Word Count', 'IO Output Start Address', 'IO Output Word Count',
|
||||||
'Total Input Bits', 'Total Output Bits', 'Unique_ID' # Agregar al final para compatibilidad
|
'Total Input Bits', 'Total Output Bits', 'Unique_ID' # Agregar al final para compatibilidad
|
||||||
]
|
]
|
||||||
df = df.reindex(columns=column_order)
|
df = df.reindex(columns=column_order)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
# Convertir columnas numéricas específicas a int para evitar decimales
|
||||||
|
numeric_columns = [
|
||||||
|
'IO Input Start Address', 'IO Input Word Count',
|
||||||
|
'IO Output Start Address', 'IO Output Word Count',
|
||||||
|
'Total Input Bits', 'Total Output Bits'
|
||||||
|
]
|
||||||
|
|
||||||
|
for col in numeric_columns:
|
||||||
|
if col in df.columns:
|
||||||
|
# Convertir a int manteniendo N/A como string
|
||||||
|
df[col] = df[col].apply(lambda x: int(x) if isinstance(x, (int, float)) and pd.notna(x) and x != 'N/A' else x)
|
||||||
|
|
||||||
# Guardar como Excel con formato
|
# Guardar como Excel con formato
|
||||||
with pd.ExcelWriter(excel_file_path, engine='openpyxl') as writer:
|
with pd.ExcelWriter(excel_file_path, engine='openpyxl') as writer:
|
||||||
df.to_excel(writer, sheet_name='IO Report', index=False)
|
df.to_excel(writer, sheet_name='IO Report', index=False)
|
||||||
|
@ -904,6 +1037,92 @@ def generate_markdown_tree(project_data, md_file_path, target_plc_id, output_roo
|
||||||
if firmware and firmware != "N/A":
|
if firmware and firmware != "N/A":
|
||||||
markdown_lines.append(f"- **Firmware:** `{firmware}`")
|
markdown_lines.append(f"- **Firmware:** `{firmware}`")
|
||||||
|
|
||||||
|
# v32.5: Process PLC's local modules (modules in the same rack/structure as the PLC)
|
||||||
|
plc_local_modules_io = []
|
||||||
|
plc_parent_id = plc_info.get("parent_id")
|
||||||
|
if plc_parent_id:
|
||||||
|
# Find sibling modules in the same parent structure (rack)
|
||||||
|
for dev_id, dev_info in project_data.get("devices", {}).items():
|
||||||
|
if dev_info.get("parent_id") == plc_parent_id and dev_id != target_plc_id:
|
||||||
|
# This is a sibling module of the PLC
|
||||||
|
module_context = {
|
||||||
|
"id": dev_id,
|
||||||
|
"name": dev_info.get("name", dev_id),
|
||||||
|
"order_number": dev_info.get("order_number", "N/A"),
|
||||||
|
"type_name": dev_info.get("type_name", "N/A")
|
||||||
|
}
|
||||||
|
module_ios = find_io_recursively(dev_id, project_data, module_context)
|
||||||
|
if module_ios:
|
||||||
|
for addr_info in module_ios:
|
||||||
|
# Add to table data
|
||||||
|
length_bits = 0
|
||||||
|
siemens_addr = "FMT_ERROR"
|
||||||
|
try:
|
||||||
|
start_byte = int(addr_info.get("start", "0"))
|
||||||
|
length_bits = int(addr_info.get("length", "0"))
|
||||||
|
io_type = addr_info.get("type", "?")
|
||||||
|
length_bytes = math.ceil(length_bits / 8.0)
|
||||||
|
if length_bits > 0 and length_bytes == 0:
|
||||||
|
length_bytes = 1
|
||||||
|
end_byte = start_byte + length_bytes - 1
|
||||||
|
prefix = "P?"
|
||||||
|
if io_type.lower() == "input":
|
||||||
|
prefix = "EW"
|
||||||
|
elif io_type.lower() == "output":
|
||||||
|
prefix = "AW"
|
||||||
|
siemens_addr = f"{prefix} {start_byte}..{end_byte}"
|
||||||
|
except Exception:
|
||||||
|
siemens_addr = f"FMT_ERROR({addr_info.get('start', '?')},{addr_info.get('length', '?')})"
|
||||||
|
|
||||||
|
plc_local_modules_io.append({
|
||||||
|
"Network": "PLC Local Modules",
|
||||||
|
"Network Type": "Local I/O",
|
||||||
|
"Device Address": "Local",
|
||||||
|
"Device Name": f"PLC {plc_info.get('name', target_plc_id)}",
|
||||||
|
"Sub-Device": addr_info.get('module_name', '?'),
|
||||||
|
"Sub-Device OrderNo": addr_info.get('module_order_number', 'N/A'),
|
||||||
|
"Sub-Device Type": addr_info.get('module_type_name', 'N/A'),
|
||||||
|
"IO Type": addr_info.get("type", "?"),
|
||||||
|
"IO Address": siemens_addr,
|
||||||
|
"Number of Bits": length_bits,
|
||||||
|
"SortKey": (
|
||||||
|
"PLC Local Modules", # Network name for sorting
|
||||||
|
[0], # Device sort key (always first)
|
||||||
|
(
|
||||||
|
int(addr_info.get("module_pos", "9999"))
|
||||||
|
if str(addr_info.get("module_pos", "9999")).isdigit()
|
||||||
|
else 9999
|
||||||
|
),
|
||||||
|
addr_info.get("module_name", ""),
|
||||||
|
addr_info.get("type", ""),
|
||||||
|
(
|
||||||
|
int(addr_info.get("start", "0"))
|
||||||
|
if str(addr_info.get("start", "0")).isdigit()
|
||||||
|
else float("inf")
|
||||||
|
),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
# Add PLC local modules to the main IO list
|
||||||
|
all_plc_io_for_table.extend(plc_local_modules_io)
|
||||||
|
|
||||||
|
# Show PLC local modules in markdown
|
||||||
|
if plc_local_modules_io:
|
||||||
|
markdown_lines.append("\n- **Local I/O Modules (same rack as PLC):**")
|
||||||
|
modules_by_name = {}
|
||||||
|
for io_data in plc_local_modules_io:
|
||||||
|
module_name = io_data["Sub-Device"]
|
||||||
|
if module_name not in modules_by_name:
|
||||||
|
modules_by_name[module_name] = []
|
||||||
|
modules_by_name[module_name].append(io_data)
|
||||||
|
|
||||||
|
for module_name in sorted(modules_by_name.keys()):
|
||||||
|
module_ios = modules_by_name[module_name]
|
||||||
|
first_io = module_ios[0]
|
||||||
|
markdown_lines.append(f" - **{module_name}** (Type: `{first_io['Sub-Device Type']}`, OrderNo: `{first_io['Sub-Device OrderNo']}`)")
|
||||||
|
for io_data in sorted(module_ios, key=lambda x: x['SortKey']):
|
||||||
|
markdown_lines.append(f" - `{io_data['IO Address']}` ({io_data['IO Type']}, {io_data['Number of Bits']} bits)")
|
||||||
|
|
||||||
plc_networks = plc_info.get("connected_networks", {})
|
plc_networks = plc_info.get("connected_networks", {})
|
||||||
markdown_lines.append("\n- **Networks:**")
|
markdown_lines.append("\n- **Networks:**")
|
||||||
if not plc_networks:
|
if not plc_networks:
|
||||||
|
@ -1530,7 +1749,7 @@ if __name__ == "__main__":
|
||||||
configs = {}
|
configs = {}
|
||||||
working_directory = None
|
working_directory = None
|
||||||
|
|
||||||
script_version = "v32.2 - Simplified IO Address Format (Separate Start/End)" # Updated version
|
script_version = "v32.5 - Include PLC Local Modules in IO Summary" # Updated version
|
||||||
print(
|
print(
|
||||||
f"--- AML (CAx Export) to Hierarchical JSON and Obsidian MD Converter ({script_version}) ---"
|
f"--- AML (CAx Export) to Hierarchical JSON and Obsidian MD Converter ({script_version}) ---"
|
||||||
)
|
)
|
||||||
|
|
|
@ -172,8 +172,8 @@ def compare_excel_files(reference_excel_path, modified_excel_path):
|
||||||
# Detectar cambios
|
# Detectar cambios
|
||||||
changes = {}
|
changes = {}
|
||||||
columns_to_monitor = [
|
columns_to_monitor = [
|
||||||
'Device Address', 'IO Input Start Address', 'IO Input End Address',
|
'Device Address', 'IO Input Start Address', 'IO Input Word Count',
|
||||||
'IO Output Start Address', 'IO Output End Address',
|
'IO Output Start Address', 'IO Output Word Count',
|
||||||
'Network Type', 'Device Type', 'Order Number', 'Firmware Version'
|
'Network Type', 'Device Type', 'Order Number', 'Firmware Version'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -184,8 +184,26 @@ def compare_excel_files(reference_excel_path, modified_excel_path):
|
||||||
row_changes = {}
|
row_changes = {}
|
||||||
for col in columns_to_monitor:
|
for col in columns_to_monitor:
|
||||||
if col in df_ref.columns and col in df_mod.columns:
|
if col in df_ref.columns and col in df_mod.columns:
|
||||||
ref_val = str(row_ref[col]).strip() if pd.notna(row_ref[col]) else 'N/A'
|
# Manejo especial para valores numéricos
|
||||||
mod_val = str(row_mod[col]).strip() if pd.notna(row_mod[col]) else 'N/A'
|
ref_raw = row_ref[col]
|
||||||
|
mod_raw = row_mod[col]
|
||||||
|
|
||||||
|
# Convertir a string, manejando floats apropiadamente
|
||||||
|
if pd.notna(ref_raw):
|
||||||
|
if isinstance(ref_raw, float) and ref_raw.is_integer():
|
||||||
|
ref_val = str(int(ref_raw))
|
||||||
|
else:
|
||||||
|
ref_val = str(ref_raw).strip()
|
||||||
|
else:
|
||||||
|
ref_val = 'N/A'
|
||||||
|
|
||||||
|
if pd.notna(mod_raw):
|
||||||
|
if isinstance(mod_raw, float) and mod_raw.is_integer():
|
||||||
|
mod_val = str(int(mod_raw))
|
||||||
|
else:
|
||||||
|
mod_val = str(mod_raw).strip()
|
||||||
|
else:
|
||||||
|
mod_val = 'N/A'
|
||||||
|
|
||||||
if ref_val != mod_val:
|
if ref_val != mod_val:
|
||||||
row_changes[col] = {
|
row_changes[col] = {
|
||||||
|
@ -203,6 +221,10 @@ def compare_excel_files(reference_excel_path, modified_excel_path):
|
||||||
print(f"Detectados {len(changes)} dispositivos con cambios.")
|
print(f"Detectados {len(changes)} dispositivos con cambios.")
|
||||||
for unique_id, change_info in changes.items():
|
for unique_id, change_info in changes.items():
|
||||||
print(f" {unique_id}: {list(change_info['changes'].keys())}")
|
print(f" {unique_id}: {list(change_info['changes'].keys())}")
|
||||||
|
# Debug: mostrar los primeros cambios para verificar valores
|
||||||
|
if len(changes) <= 5: # Solo mostrar detalles si son pocos cambios
|
||||||
|
for field, change_data in change_info['changes'].items():
|
||||||
|
print(f" {field}: {change_data['original']} → {change_data['modified']}")
|
||||||
|
|
||||||
return True, changes
|
return True, changes
|
||||||
|
|
||||||
|
@ -297,18 +319,28 @@ def apply_changes_to_aml(aml_tree, project_data, changes_dict):
|
||||||
# Encontrar el dispositivo en los datos del AML
|
# Encontrar el dispositivo en los datos del AML
|
||||||
device_info = find_device_in_aml(project_data, plc_name, device_name)
|
device_info = find_device_in_aml(project_data, plc_name, device_name)
|
||||||
if not device_info:
|
if not device_info:
|
||||||
print(f" ERROR: No se pudo encontrar el dispositivo en el AML")
|
print(f" ERROR: No se pudo encontrar el dispositivo '{device_name}' del PLC '{plc_name}' en el AML")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
print(f" Debug: Encontrado dispositivo - node_id: {device_info['node_id']}, display_id: {device_info['display_id']}")
|
||||||
|
|
||||||
# Encontrar el elemento XML correspondiente
|
# Encontrar el elemento XML correspondiente
|
||||||
device_id = device_info['node_id']
|
node_id = device_info['node_id']
|
||||||
xml_element = root.xpath(f".//*[@ID='{device_id}']")
|
display_id = device_info['display_id']
|
||||||
|
|
||||||
|
# Intentar primero con el display_id (el dispositivo real que contiene IOs)
|
||||||
|
xml_element = root.xpath(f".//*[@ID='{display_id}']")
|
||||||
|
|
||||||
if not xml_element:
|
if not xml_element:
|
||||||
print(f" ERROR: No se pudo encontrar el elemento XML con ID {device_id}")
|
# Si no se encuentra, intentar con el node_id
|
||||||
|
xml_element = root.xpath(f".//*[@ID='{node_id}']")
|
||||||
|
|
||||||
|
if not xml_element:
|
||||||
|
print(f" ERROR: No se pudo encontrar el elemento XML con ID {display_id} o {node_id}")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
device_element = xml_element[0]
|
device_element = xml_element[0]
|
||||||
|
print(f" Debug: Usando elemento XML con ID {device_element.get('ID', 'N/A')}")
|
||||||
|
|
||||||
# Aplicar cambios específicos
|
# Aplicar cambios específicos
|
||||||
for field, change_data in changes.items():
|
for field, change_data in changes.items():
|
||||||
|
@ -323,9 +355,9 @@ def apply_changes_to_aml(aml_tree, project_data, changes_dict):
|
||||||
else:
|
else:
|
||||||
print(f" ✗ Error actualizando dirección de red")
|
print(f" ✗ Error actualizando dirección de red")
|
||||||
|
|
||||||
elif field in ['IO Input Start Address', 'IO Input End Address', 'IO Output Start Address', 'IO Output End Address']:
|
elif field in ['IO Input Start Address', 'IO Input Word Count', 'IO Output Start Address', 'IO Output Word Count']:
|
||||||
# Cambiar direcciones IO específicas
|
# Cambiar direcciones IO específicas
|
||||||
if apply_io_address_change(device_element, field, original_val, modified_val, project_data, device_id):
|
if apply_io_address_change(device_element, field, original_val, modified_val, project_data, display_id):
|
||||||
print(f" ✓ {field} actualizada: {original_val} -> {modified_val}")
|
print(f" ✓ {field} actualizada: {original_val} -> {modified_val}")
|
||||||
changes_applied += 1
|
changes_applied += 1
|
||||||
else:
|
else:
|
||||||
|
@ -348,19 +380,25 @@ def apply_network_address_change(device_element, new_address):
|
||||||
Aplica cambio de dirección de red a un elemento del dispositivo.
|
Aplica cambio de dirección de red a un elemento del dispositivo.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
|
# Convertir new_address a string si es numérico
|
||||||
|
if isinstance(new_address, (int, float)):
|
||||||
|
address_str = str(new_address).rstrip('0').rstrip('.')
|
||||||
|
else:
|
||||||
|
address_str = str(new_address)
|
||||||
|
|
||||||
# Buscar atributo NetworkAddress
|
# Buscar atributo NetworkAddress
|
||||||
addr_attr = device_element.xpath("./*[local-name()='Attribute'][@Name='NetworkAddress']")
|
addr_attr = device_element.xpath("./*[local-name()='Attribute'][@Name='NetworkAddress']")
|
||||||
if addr_attr:
|
if addr_attr:
|
||||||
value_elem = addr_attr[0].xpath("./*[local-name()='Value']")
|
value_elem = addr_attr[0].xpath("./*[local-name()='Value']")
|
||||||
if value_elem:
|
if value_elem:
|
||||||
value_elem[0].text = new_address
|
value_elem[0].text = address_str
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# Si no existe, crear el atributo
|
# Si no existe, crear el atributo
|
||||||
attr_elem = ET.SubElement(device_element, "Attribute")
|
attr_elem = ET.SubElement(device_element, "Attribute")
|
||||||
attr_elem.set("Name", "NetworkAddress")
|
attr_elem.set("Name", "NetworkAddress")
|
||||||
value_elem = ET.SubElement(attr_elem, "Value")
|
value_elem = ET.SubElement(attr_elem, "Value")
|
||||||
value_elem.text = new_address
|
value_elem.text = address_str
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -406,102 +444,141 @@ def apply_device_attribute_change(device_element, field, new_value):
|
||||||
|
|
||||||
def apply_io_address_change(device_element, field, original_val, modified_val, project_data, device_id):
|
def apply_io_address_change(device_element, field, original_val, modified_val, project_data, device_id):
|
||||||
"""
|
"""
|
||||||
Aplica cambios a las direcciones IO individuales. Ahora es más simple
|
Aplica cambios a las direcciones IO usando Start Address + Word Count.
|
||||||
porque las direcciones están separadas en campos específicos.
|
Esto es más simple y directo que calcular End Addresses.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# Validar que el nuevo valor sea numérico o N/A
|
# Validar que el nuevo valor sea numérico o N/A
|
||||||
if modified_val != 'N/A' and modified_val != '':
|
if modified_val != 'N/A' and modified_val != '':
|
||||||
try:
|
try:
|
||||||
new_addr_value = int(modified_val)
|
# Manejar tanto floats como integers (pandas puede leer como float)
|
||||||
except ValueError:
|
if isinstance(modified_val, str):
|
||||||
print(f" Error: Valor de dirección no válido: {modified_val}")
|
# Si es string, intentar convertir
|
||||||
|
new_value = int(float(modified_val))
|
||||||
|
else:
|
||||||
|
# Si ya es numérico, convertir directamente
|
||||||
|
new_value = int(modified_val)
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
print(f" Error: Valor no válido: {modified_val} (tipo: {type(modified_val)})")
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
# Si es N/A, no hay dirección IO para este tipo
|
# Si es N/A, no hay dirección IO para este tipo
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# Determinar tipo de IO y si es start o end
|
# Determinar tipo de IO y si es start address o word count
|
||||||
is_input = "Input" in field
|
is_input = "Input" in field
|
||||||
is_start = "Start" in field
|
is_start_address = "Start Address" in field
|
||||||
|
is_word_count = "Word Count" in field
|
||||||
io_type = "Input" if is_input else "Output"
|
io_type = "Input" if is_input else "Output"
|
||||||
|
|
||||||
# Buscar la estructura IO en el dispositivo
|
# Buscar la estructura IO en el dispositivo - con múltiples estrategias
|
||||||
# Esto requiere encontrar los elementos Address y sus sub-atributos
|
print(f" Debug: Buscando elementos Address en dispositivo {device_element.get('Name', 'N/A')}")
|
||||||
|
|
||||||
|
# Estrategia 1: Buscar Address directamente en el elemento
|
||||||
address_elements = device_element.xpath("./*[local-name()='Attribute'][@Name='Address']")
|
address_elements = device_element.xpath("./*[local-name()='Attribute'][@Name='Address']")
|
||||||
|
|
||||||
if not address_elements:
|
if not address_elements:
|
||||||
print(f" No se encontró elemento Address en el dispositivo")
|
# Estrategia 2: Buscar en elementos hijos
|
||||||
|
print(f" Debug: No se encontró Address directo, buscando en elementos hijos...")
|
||||||
|
address_elements = device_element.xpath(".//*[local-name()='Attribute'][@Name='Address']")
|
||||||
|
|
||||||
|
if not address_elements:
|
||||||
|
# Estrategia 3: Buscar en elementos padre (tal vez los IOs están en el parent)
|
||||||
|
print(f" Debug: No se encontró Address en hijos, buscando en elementos padre...")
|
||||||
|
parent_elements = device_element.xpath("parent::*")
|
||||||
|
if parent_elements:
|
||||||
|
address_elements = parent_elements[0].xpath(".//*[local-name()='Attribute'][@Name='Address']")
|
||||||
|
|
||||||
|
if not address_elements:
|
||||||
|
print(f" ERROR: No se encontró elemento Address en el dispositivo o sus alrededores")
|
||||||
|
print(f" Debug: Atributos disponibles en este elemento:")
|
||||||
|
for attr in device_element.xpath("./*[local-name()='Attribute']"):
|
||||||
|
attr_name = attr.get('Name', 'N/A')
|
||||||
|
print(f" - {attr_name}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Buscar dentro del Address el sub-atributo correcto
|
print(f" Debug: Encontrados {len(address_elements)} elemento(s) Address")
|
||||||
address_element = address_elements[0]
|
|
||||||
io_subelements = address_element.xpath(f"./*[local-name()='Attribute']")
|
|
||||||
|
|
||||||
|
# Buscar dentro del Address el sub-atributo correcto
|
||||||
target_io_element = None
|
target_io_element = None
|
||||||
for io_sub in io_subelements:
|
|
||||||
# Verificar si es el tipo correcto (Input/Output)
|
# Buscar en todos los elementos Address encontrados
|
||||||
type_val = io_sub.xpath("./*[local-name()='Attribute'][@Name='IoType']/*[local-name()='Value']/text()")
|
for address_element in address_elements:
|
||||||
if type_val and type_val[0].lower() == io_type.lower():
|
print(f" Debug: Explorando Address element...")
|
||||||
target_io_element = io_sub
|
io_subelements = address_element.xpath(f"./*[local-name()='Attribute']")
|
||||||
|
|
||||||
|
print(f" Debug: Encontrados {len(io_subelements)} sub-elementos en Address")
|
||||||
|
|
||||||
|
for io_sub in io_subelements:
|
||||||
|
sub_name = io_sub.get('Name', 'N/A')
|
||||||
|
print(f" Debug: Revisando sub-elemento: {sub_name}")
|
||||||
|
|
||||||
|
# Verificar si es el tipo correcto (Input/Output)
|
||||||
|
type_val = io_sub.xpath("./*[local-name()='Attribute'][@Name='IoType']/*[local-name()='Value']/text()")
|
||||||
|
if type_val:
|
||||||
|
found_type = type_val[0]
|
||||||
|
print(f" Debug: Encontrado IoType: {found_type}")
|
||||||
|
if found_type.lower() == io_type.lower():
|
||||||
|
target_io_element = io_sub
|
||||||
|
print(f" Debug: ¡Encontrado elemento {io_type} compatible!")
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
# También revisar si el nombre del sub-elemento indica el tipo
|
||||||
|
if io_type.lower() in sub_name.lower():
|
||||||
|
print(f" Debug: Sub-elemento {sub_name} parece ser de tipo {io_type}")
|
||||||
|
target_io_element = io_sub
|
||||||
|
break
|
||||||
|
|
||||||
|
if target_io_element:
|
||||||
break
|
break
|
||||||
|
|
||||||
if not target_io_element:
|
if not target_io_element:
|
||||||
print(f" No se encontró elemento {io_type} en Address")
|
print(f" ERROR: No se encontró elemento {io_type} en ningún Address")
|
||||||
|
print(f" Debug: Elementos Address disponibles:")
|
||||||
|
for addr_elem in address_elements:
|
||||||
|
sub_attrs = addr_elem.xpath(f"./*[local-name()='Attribute']")
|
||||||
|
for sub in sub_attrs:
|
||||||
|
sub_name = sub.get('Name', 'N/A')
|
||||||
|
type_vals = sub.xpath("./*[local-name()='Attribute'][@Name='IoType']/*[local-name()='Value']/text()")
|
||||||
|
type_info = type_vals[0] if type_vals else "No IoType"
|
||||||
|
print(f" - {sub_name} (IoType: {type_info})")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Actualizar StartAddress o calcular Length según el campo
|
if is_start_address:
|
||||||
if is_start:
|
|
||||||
# Actualizar StartAddress
|
# Actualizar StartAddress
|
||||||
start_attr = target_io_element.xpath("./*[local-name()='Attribute'][@Name='StartAddress']")
|
start_attr = target_io_element.xpath("./*[local-name()='Attribute'][@Name='StartAddress']")
|
||||||
if start_attr:
|
if start_attr:
|
||||||
value_elem = start_attr[0].xpath("./*[local-name()='Value']")
|
value_elem = start_attr[0].xpath("./*[local-name()='Value']")
|
||||||
if value_elem:
|
if value_elem:
|
||||||
value_elem[0].text = str(new_addr_value)
|
value_elem[0].text = str(new_value)
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
# Crear StartAddress si no existe
|
# Crear StartAddress si no existe
|
||||||
start_attr_elem = ET.SubElement(target_io_element, "Attribute")
|
start_attr_elem = ET.SubElement(target_io_element, "Attribute")
|
||||||
start_attr_elem.set("Name", "StartAddress")
|
start_attr_elem.set("Name", "StartAddress")
|
||||||
value_elem = ET.SubElement(start_attr_elem, "Value")
|
value_elem = ET.SubElement(start_attr_elem, "Value")
|
||||||
value_elem.text = str(new_addr_value)
|
value_elem.text = str(new_value)
|
||||||
return True
|
return True
|
||||||
else:
|
|
||||||
# Es End Address - necesitamos calcular Length basándose en Start y End
|
elif is_word_count:
|
||||||
# Primero obtener StartAddress
|
# Actualizar Length basándose en Word Count
|
||||||
start_attr = target_io_element.xpath("./*[local-name()='Attribute'][@Name='StartAddress']/*[local-name()='Value']/text()")
|
# Convertir words a bits (1 word = 16 bits)
|
||||||
if start_attr:
|
length_bits = new_value * 16
|
||||||
try:
|
|
||||||
start_value = int(start_attr[0])
|
# Actualizar Length
|
||||||
# Length en bytes = (end - start + 1)
|
length_attr = target_io_element.xpath("./*[local-name()='Attribute'][@Name='Length']")
|
||||||
length_bytes = new_addr_value - start_value + 1
|
if length_attr:
|
||||||
if length_bytes > 0:
|
value_elem = length_attr[0].xpath("./*[local-name()='Value']")
|
||||||
# Convertir a bits (asumiendo 8 bits por byte)
|
if value_elem:
|
||||||
length_bits = length_bytes * 8
|
value_elem[0].text = str(length_bits)
|
||||||
|
return True
|
||||||
# Actualizar Length
|
|
||||||
length_attr = target_io_element.xpath("./*[local-name()='Attribute'][@Name='Length']")
|
|
||||||
if length_attr:
|
|
||||||
value_elem = length_attr[0].xpath("./*[local-name()='Value']")
|
|
||||||
if value_elem:
|
|
||||||
value_elem[0].text = str(length_bits)
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
# Crear Length si no existe
|
|
||||||
length_attr_elem = ET.SubElement(target_io_element, "Attribute")
|
|
||||||
length_attr_elem.set("Name", "Length")
|
|
||||||
value_elem = ET.SubElement(length_attr_elem, "Value")
|
|
||||||
value_elem.text = str(length_bits)
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
print(f" Error: End address ({new_addr_value}) debe ser mayor que start address ({start_value})")
|
|
||||||
return False
|
|
||||||
except ValueError:
|
|
||||||
print(f" Error: No se pudo convertir start address: {start_attr[0]}")
|
|
||||||
return False
|
|
||||||
else:
|
else:
|
||||||
print(f" Error: No se encontró StartAddress para calcular Length")
|
# Crear Length si no existe
|
||||||
return False
|
length_attr_elem = ET.SubElement(target_io_element, "Attribute")
|
||||||
|
length_attr_elem.set("Name", "Length")
|
||||||
|
value_elem = ET.SubElement(length_attr_elem, "Value")
|
||||||
|
value_elem.text = str(length_bits)
|
||||||
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -544,7 +621,7 @@ def main():
|
||||||
configs = {}
|
configs = {}
|
||||||
working_directory = None
|
working_directory = None
|
||||||
|
|
||||||
script_version = "v1.1 - Simplified IO Address Handling (Start/End Separated)"
|
script_version = "v1.4 - Enhanced Address Element Search with Debug"
|
||||||
print(f"--- Actualizador de AML desde Excel Modificado ({script_version}) ---")
|
print(f"--- Actualizador de AML desde Excel Modificado ({script_version}) ---")
|
||||||
|
|
||||||
# Validar directorio de trabajo
|
# Validar directorio de trabajo
|
||||||
|
|
|
@ -0,0 +1,324 @@
|
||||||
|
"""
|
||||||
|
export_logic_from_tia : Script para exportar el software de un PLC desde TIA Portal en archivos XML y SCL.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import tkinter as tk
|
||||||
|
from tkinter import filedialog
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
script_root = os.path.dirname(
|
||||||
|
os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
|
||||||
|
)
|
||||||
|
sys.path.append(script_root)
|
||||||
|
from backend.script_utils import load_configuration
|
||||||
|
|
||||||
|
# --- Configuration ---
|
||||||
|
TIA_PORTAL_VERSION = "18.0" # Target TIA Portal version (e.g., "18.0")
|
||||||
|
EXPORT_OPTIONS = None # Use default export options
|
||||||
|
KEEP_FOLDER_STRUCTURE = (
|
||||||
|
True # Replicate TIA project folder structure in export directory
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- TIA Scripting Import Handling ---
|
||||||
|
# Check if the TIA_SCRIPTING environment variable is set
|
||||||
|
if os.getenv("TIA_SCRIPTING"):
|
||||||
|
sys.path.append(os.getenv("TIA_SCRIPTING"))
|
||||||
|
else:
|
||||||
|
# Optional: Define a fallback path if the environment variable isn't set
|
||||||
|
# fallback_path = "C:\\path\\to\\your\\TIA_Scripting_binaries"
|
||||||
|
# if os.path.exists(fallback_path):
|
||||||
|
# sys.path.append(fallback_path)
|
||||||
|
pass # Allow import to fail if not found
|
||||||
|
|
||||||
|
try:
|
||||||
|
import siemens_tia_scripting as ts
|
||||||
|
|
||||||
|
EXPORT_OPTIONS = (
|
||||||
|
ts.Enums.ExportOptions.WithDefaults
|
||||||
|
) # Set default options now that 'ts' is imported
|
||||||
|
except ImportError:
|
||||||
|
print("ERROR: Failed to import 'siemens_tia_scripting'.")
|
||||||
|
print("Ensure:")
|
||||||
|
print(f"1. TIA Portal Openness for V{TIA_PORTAL_VERSION} is installed.")
|
||||||
|
print(
|
||||||
|
"2. The 'siemens_tia_scripting' Python module is installed (pip install ...) or"
|
||||||
|
)
|
||||||
|
print(
|
||||||
|
" the path to its binaries is set in the 'TIA_SCRIPTING' environment variable."
|
||||||
|
)
|
||||||
|
print(
|
||||||
|
"3. You are using a compatible Python version (e.g., 3.12.X as per documentation)."
|
||||||
|
)
|
||||||
|
sys.exit(1)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"An unexpected error occurred during import: {e}")
|
||||||
|
traceback.print_exc()
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# --- Functions ---
|
||||||
|
|
||||||
|
|
||||||
|
def select_project_file():
|
||||||
|
"""Opens a dialog to select a TIA Portal project file."""
|
||||||
|
root = tk.Tk()
|
||||||
|
root.withdraw() # Hide the main tkinter window
|
||||||
|
file_path = filedialog.askopenfilename(
|
||||||
|
title="Select TIA Portal Project File",
|
||||||
|
filetypes=[
|
||||||
|
(
|
||||||
|
f"TIA Portal V{TIA_PORTAL_VERSION} Projects",
|
||||||
|
f"*.ap{TIA_PORTAL_VERSION.split('.')[0]}",
|
||||||
|
)
|
||||||
|
], # e.g. *.ap18
|
||||||
|
)
|
||||||
|
root.destroy()
|
||||||
|
if not file_path:
|
||||||
|
print("No project file selected. Exiting.")
|
||||||
|
sys.exit(0)
|
||||||
|
return file_path
|
||||||
|
|
||||||
|
|
||||||
|
def select_export_directory():
|
||||||
|
"""Opens a dialog to select the export directory."""
|
||||||
|
root = tk.Tk()
|
||||||
|
root.withdraw() # Hide the main tkinter window
|
||||||
|
dir_path = filedialog.askdirectory(title="Select Export Directory")
|
||||||
|
root.destroy()
|
||||||
|
if not dir_path:
|
||||||
|
print("No export directory selected. Exiting.")
|
||||||
|
sys.exit(0)
|
||||||
|
return dir_path
|
||||||
|
|
||||||
|
|
||||||
|
def export_plc_data(plc, export_base_dir):
|
||||||
|
"""Exports Blocks, UDTs, and Tag Tables from a given PLC."""
|
||||||
|
plc_name = plc.get_name()
|
||||||
|
print(f"\n--- Processing PLC: {plc_name} ---")
|
||||||
|
|
||||||
|
# Define base export path for this PLC
|
||||||
|
plc_export_dir = os.path.join(export_base_dir, plc_name)
|
||||||
|
os.makedirs(plc_export_dir, exist_ok=True)
|
||||||
|
|
||||||
|
# --- Export Program Blocks ---
|
||||||
|
blocks_exported = 0
|
||||||
|
blocks_skipped = 0
|
||||||
|
print(f"\n[PLC: {plc_name}] Exporting Program Blocks...")
|
||||||
|
xml_blocks_path = os.path.join(plc_export_dir, "ProgramBlocks_XML")
|
||||||
|
scl_blocks_path = os.path.join(plc_export_dir, "ProgramBlocks_SCL")
|
||||||
|
os.makedirs(xml_blocks_path, exist_ok=True)
|
||||||
|
os.makedirs(scl_blocks_path, exist_ok=True)
|
||||||
|
print(f" XML Target: {xml_blocks_path}")
|
||||||
|
print(f" SCL Target: {scl_blocks_path}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
program_blocks = plc.get_program_blocks() #
|
||||||
|
print(f" Found {len(program_blocks)} program blocks.")
|
||||||
|
for block in program_blocks:
|
||||||
|
block_name = block.get_name() # Assuming get_name() exists
|
||||||
|
print(f" Processing block: {block_name}...")
|
||||||
|
try:
|
||||||
|
if not block.is_consistent(): #
|
||||||
|
print(f" Compiling block {block_name}...")
|
||||||
|
block.compile() #
|
||||||
|
if not block.is_consistent():
|
||||||
|
print(
|
||||||
|
f" WARNING: Block {block_name} inconsistent after compile. Skipping."
|
||||||
|
)
|
||||||
|
blocks_skipped += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
print(f" Exporting {block_name} as XML...")
|
||||||
|
block.export(
|
||||||
|
target_directory_path=xml_blocks_path, #
|
||||||
|
export_options=EXPORT_OPTIONS, #
|
||||||
|
export_format=ts.Enums.ExportFormats.SimaticML, #
|
||||||
|
keep_folder_structure=KEEP_FOLDER_STRUCTURE,
|
||||||
|
) #
|
||||||
|
|
||||||
|
try:
|
||||||
|
prog_language = block.get_property(name="ProgrammingLanguage")
|
||||||
|
if prog_language == "SCL":
|
||||||
|
print(f" Exporting {block_name} as SCL...")
|
||||||
|
block.export(
|
||||||
|
target_directory_path=scl_blocks_path,
|
||||||
|
export_options=EXPORT_OPTIONS,
|
||||||
|
export_format=ts.Enums.ExportFormats.ExternalSource, #
|
||||||
|
keep_folder_structure=KEEP_FOLDER_STRUCTURE,
|
||||||
|
)
|
||||||
|
except Exception as prop_ex:
|
||||||
|
print(
|
||||||
|
f" Could not get ProgrammingLanguage for {block_name}. Skipping SCL. Error: {prop_ex}"
|
||||||
|
)
|
||||||
|
|
||||||
|
blocks_exported += 1
|
||||||
|
except Exception as block_ex:
|
||||||
|
print(f" ERROR exporting block {block_name}: {block_ex}")
|
||||||
|
blocks_skipped += 1
|
||||||
|
print(
|
||||||
|
f" Program Blocks Export Summary: Exported={blocks_exported}, Skipped/Errors={blocks_skipped}"
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
print(f" ERROR processing Program Blocks: {e}")
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
# --- Export PLC Data Types (UDTs) ---
|
||||||
|
udts_exported = 0
|
||||||
|
udts_skipped = 0
|
||||||
|
print(f"\n[PLC: {plc_name}] Exporting PLC Data Types (UDTs)...")
|
||||||
|
udt_export_path = os.path.join(plc_export_dir, "PlcDataTypes")
|
||||||
|
os.makedirs(udt_export_path, exist_ok=True)
|
||||||
|
print(f" Target: {udt_export_path}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
udts = plc.get_user_data_types() #
|
||||||
|
print(f" Found {len(udts)} UDTs.")
|
||||||
|
for udt in udts:
|
||||||
|
udt_name = udt.get_name() #
|
||||||
|
print(f" Processing UDT: {udt_name}...")
|
||||||
|
try:
|
||||||
|
if not udt.is_consistent(): #
|
||||||
|
print(f" Compiling UDT {udt_name}...")
|
||||||
|
udt.compile() #
|
||||||
|
if not udt.is_consistent():
|
||||||
|
print(
|
||||||
|
f" WARNING: UDT {udt_name} inconsistent after compile. Skipping."
|
||||||
|
)
|
||||||
|
udts_skipped += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
print(f" Exporting {udt_name}...")
|
||||||
|
udt.export(
|
||||||
|
target_directory_path=udt_export_path, #
|
||||||
|
export_options=EXPORT_OPTIONS, #
|
||||||
|
# export_format defaults to SimaticML for UDTs
|
||||||
|
keep_folder_structure=KEEP_FOLDER_STRUCTURE,
|
||||||
|
) #
|
||||||
|
udts_exported += 1
|
||||||
|
except Exception as udt_ex:
|
||||||
|
print(f" ERROR exporting UDT {udt_name}: {udt_ex}")
|
||||||
|
udts_skipped += 1
|
||||||
|
print(
|
||||||
|
f" UDT Export Summary: Exported={udts_exported}, Skipped/Errors={udts_skipped}"
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
print(f" ERROR processing UDTs: {e}")
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
# --- Export PLC Tag Tables ---
|
||||||
|
tags_exported = 0
|
||||||
|
tags_skipped = 0
|
||||||
|
print(f"\n[PLC: {plc_name}] Exporting PLC Tag Tables...")
|
||||||
|
tags_export_path = os.path.join(plc_export_dir, "PlcTags")
|
||||||
|
os.makedirs(tags_export_path, exist_ok=True)
|
||||||
|
print(f" Target: {tags_export_path}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
tag_tables = plc.get_plc_tag_tables() #
|
||||||
|
print(f" Found {len(tag_tables)} Tag Tables.")
|
||||||
|
for table in tag_tables:
|
||||||
|
table_name = table.get_name() #
|
||||||
|
print(f" Processing Tag Table: {table_name}...")
|
||||||
|
try:
|
||||||
|
# Note: Consistency check might not be available/needed for tag tables like blocks/UDTs
|
||||||
|
print(f" Exporting {table_name}...")
|
||||||
|
table.export(
|
||||||
|
target_directory_path=tags_export_path, #
|
||||||
|
export_options=EXPORT_OPTIONS, #
|
||||||
|
# export_format defaults to SimaticML for Tag Tables
|
||||||
|
keep_folder_structure=KEEP_FOLDER_STRUCTURE,
|
||||||
|
) #
|
||||||
|
tags_exported += 1
|
||||||
|
except Exception as table_ex:
|
||||||
|
print(f" ERROR exporting Tag Table {table_name}: {table_ex}")
|
||||||
|
tags_skipped += 1
|
||||||
|
print(
|
||||||
|
f" Tag Table Export Summary: Exported={tags_exported}, Skipped/Errors={tags_skipped}"
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
print(f" ERROR processing Tag Tables: {e}")
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
print(f"\n--- Finished processing PLC: {plc_name} ---")
|
||||||
|
|
||||||
|
|
||||||
|
# --- Main Script ---
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
configs = load_configuration()
|
||||||
|
working_directory = configs.get("working_directory")
|
||||||
|
|
||||||
|
print("--- TIA Portal Data Exporter (Blocks, UDTs, Tags) ---")
|
||||||
|
|
||||||
|
# Validate working directory
|
||||||
|
if not working_directory or not os.path.isdir(working_directory):
|
||||||
|
print("ERROR: Working directory not set or invalid in configuration.")
|
||||||
|
print("Please configure the working directory using the main application.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# 1. Select Project File, Export Directory comes from config
|
||||||
|
project_file = select_project_file()
|
||||||
|
export_dir = working_directory # Use working directory from config
|
||||||
|
|
||||||
|
print(f"\nSelected Project: {project_file}")
|
||||||
|
print(f"Using Export Directory (Working Directory): {export_dir}")
|
||||||
|
|
||||||
|
portal_instance = None
|
||||||
|
project_object = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 2. Connect to TIA Portal
|
||||||
|
print(f"\nConnecting to TIA Portal V{TIA_PORTAL_VERSION}...")
|
||||||
|
portal_instance = ts.open_portal(
|
||||||
|
version=TIA_PORTAL_VERSION,
|
||||||
|
portal_mode=ts.Enums.PortalMode.WithGraphicalUserInterface,
|
||||||
|
)
|
||||||
|
print("Connected to TIA Portal.")
|
||||||
|
print(f"Portal Process ID: {portal_instance.get_process_id()}") #
|
||||||
|
|
||||||
|
# 3. Open Project
|
||||||
|
print(f"Opening project: {os.path.basename(project_file)}...")
|
||||||
|
project_object = portal_instance.open_project(project_file_path=project_file) #
|
||||||
|
if project_object is None:
|
||||||
|
print("Project might already be open, attempting to get handle...")
|
||||||
|
project_object = portal_instance.get_project() #
|
||||||
|
if project_object is None:
|
||||||
|
raise Exception("Failed to open or get the specified project.")
|
||||||
|
print("Project opened successfully.")
|
||||||
|
|
||||||
|
# 4. Get PLCs
|
||||||
|
plcs = project_object.get_plcs() #
|
||||||
|
if not plcs:
|
||||||
|
print("No PLC devices found in the project.")
|
||||||
|
else:
|
||||||
|
print(f"Found {len(plcs)} PLC(s). Starting export process...")
|
||||||
|
|
||||||
|
# 5. Iterate and Export Data for each PLC
|
||||||
|
for plc_device in plcs:
|
||||||
|
export_plc_data(
|
||||||
|
plc=plc_device, export_base_dir=export_dir
|
||||||
|
) # Pass export_dir
|
||||||
|
|
||||||
|
print("\nExport process completed.")
|
||||||
|
|
||||||
|
except ts.TiaException as tia_ex:
|
||||||
|
print(f"\nTIA Portal Openness Error: {tia_ex}")
|
||||||
|
traceback.print_exc()
|
||||||
|
except FileNotFoundError:
|
||||||
|
print(f"\nERROR: Project file not found at {project_file}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"\nAn unexpected error occurred: {e}")
|
||||||
|
traceback.print_exc()
|
||||||
|
finally:
|
||||||
|
# 6. Cleanup
|
||||||
|
if portal_instance:
|
||||||
|
try:
|
||||||
|
print("\nClosing TIA Portal...")
|
||||||
|
portal_instance.close_portal() #
|
||||||
|
print("TIA Portal closed.")
|
||||||
|
except Exception as close_ex:
|
||||||
|
print(f"Error during TIA Portal cleanup: {close_ex}")
|
||||||
|
|
||||||
|
print("\nScript finished.")
|
|
@ -0,0 +1,371 @@
|
||||||
|
"""
|
||||||
|
export_CAx_from_tia : Script que exporta los datos CAx de un proyecto de TIA Portal y genera un resumen en Markdown.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import tkinter as tk
|
||||||
|
from tkinter import filedialog
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import traceback
|
||||||
|
import xml.etree.ElementTree as ET # Library to parse XML (AML)
|
||||||
|
from pathlib import Path # Import Path
|
||||||
|
|
||||||
|
script_root = os.path.dirname(
|
||||||
|
os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
|
||||||
|
)
|
||||||
|
sys.path.append(script_root)
|
||||||
|
from backend.script_utils import load_configuration
|
||||||
|
|
||||||
|
# --- Configuration ---
|
||||||
|
# Supported TIA Portal versions mapping (extension -> version)
|
||||||
|
SUPPORTED_TIA_VERSIONS = {
|
||||||
|
".ap18": "18.0",
|
||||||
|
".ap19": "19.0",
|
||||||
|
".ap20": "20.0"
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- TIA Scripting Import Handling ---
|
||||||
|
# (Same import handling as the previous script)
|
||||||
|
if os.getenv("TIA_SCRIPTING"):
|
||||||
|
sys.path.append(os.getenv("TIA_SCRIPTING"))
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
import siemens_tia_scripting as ts
|
||||||
|
except ImportError:
|
||||||
|
print("ERROR: Failed to import 'siemens_tia_scripting'.")
|
||||||
|
print("Ensure TIA Openness, the module, and Python 3.12.X are set up.")
|
||||||
|
sys.exit(1)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"An unexpected error occurred during import: {e}")
|
||||||
|
traceback.print_exc()
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# --- Functions ---
|
||||||
|
|
||||||
|
|
||||||
|
def get_supported_filetypes():
|
||||||
|
"""Returns the supported file types for TIA Portal projects."""
|
||||||
|
filetypes = []
|
||||||
|
for ext, version in SUPPORTED_TIA_VERSIONS.items():
|
||||||
|
version_major = version.split('.')[0]
|
||||||
|
filetypes.append((f"TIA Portal V{version_major} Projects", f"*{ext}"))
|
||||||
|
|
||||||
|
# Add option to show all supported files
|
||||||
|
all_extensions = " ".join([f"*{ext}" for ext in SUPPORTED_TIA_VERSIONS.keys()])
|
||||||
|
filetypes.insert(0, ("All TIA Portal Projects", all_extensions))
|
||||||
|
|
||||||
|
return filetypes
|
||||||
|
|
||||||
|
|
||||||
|
def detect_tia_version(project_file_path):
|
||||||
|
"""Detects TIA Portal version based on file extension."""
|
||||||
|
file_path = Path(project_file_path)
|
||||||
|
file_extension = file_path.suffix.lower()
|
||||||
|
|
||||||
|
if file_extension in SUPPORTED_TIA_VERSIONS:
|
||||||
|
detected_version = SUPPORTED_TIA_VERSIONS[file_extension]
|
||||||
|
print(f"Detected TIA Portal version: {detected_version} (from extension {file_extension})")
|
||||||
|
return detected_version
|
||||||
|
else:
|
||||||
|
print(f"WARNING: Unrecognized file extension '{file_extension}'. Supported extensions: {list(SUPPORTED_TIA_VERSIONS.keys())}")
|
||||||
|
# Default to version 18.0 for backward compatibility
|
||||||
|
print("Defaulting to TIA Portal V18.0")
|
||||||
|
return "18.0"
|
||||||
|
|
||||||
|
|
||||||
|
def select_project_file():
|
||||||
|
"""Opens a dialog to select a TIA Portal project file."""
|
||||||
|
root = tk.Tk()
|
||||||
|
root.withdraw()
|
||||||
|
file_path = filedialog.askopenfilename(
|
||||||
|
title="Select TIA Portal Project File",
|
||||||
|
filetypes=get_supported_filetypes(),
|
||||||
|
)
|
||||||
|
root.destroy()
|
||||||
|
if not file_path:
|
||||||
|
print("No project file selected. Exiting.")
|
||||||
|
sys.exit(0)
|
||||||
|
return file_path
|
||||||
|
|
||||||
|
|
||||||
|
def select_output_directory():
|
||||||
|
"""Opens a dialog to select the output directory."""
|
||||||
|
root = tk.Tk()
|
||||||
|
root.withdraw()
|
||||||
|
dir_path = filedialog.askdirectory(
|
||||||
|
title="Select Output Directory for AML and MD files"
|
||||||
|
)
|
||||||
|
root.destroy()
|
||||||
|
if not dir_path:
|
||||||
|
print("No output directory selected. Exiting.")
|
||||||
|
sys.exit(0)
|
||||||
|
return dir_path
|
||||||
|
|
||||||
|
|
||||||
|
def find_elements(element, path):
|
||||||
|
"""Helper to find elements using namespaces commonly found in AML."""
|
||||||
|
# AutomationML namespaces often vary slightly or might be default
|
||||||
|
# This basic approach tries common prefixes or no prefix
|
||||||
|
namespaces = {
|
||||||
|
"": (
|
||||||
|
element.tag.split("}")[0][1:] if "}" in element.tag else ""
|
||||||
|
), # Default namespace if present
|
||||||
|
"caex": "http://www.dke.de/CAEX", # Common CAEX namespace
|
||||||
|
# Add other potential namespaces if needed based on file inspection
|
||||||
|
}
|
||||||
|
# Try finding with common prefixes or the default namespace
|
||||||
|
for prefix, uri in namespaces.items():
|
||||||
|
# Construct path with namespace URI if prefix is defined
|
||||||
|
namespaced_path = path
|
||||||
|
if prefix:
|
||||||
|
parts = path.split("/")
|
||||||
|
namespaced_parts = [
|
||||||
|
f"{{{uri}}}{part}" if part != "." else part for part in parts
|
||||||
|
]
|
||||||
|
namespaced_path = "/".join(namespaced_parts)
|
||||||
|
|
||||||
|
# Try findall with the constructed path
|
||||||
|
found = element.findall(namespaced_path)
|
||||||
|
if found:
|
||||||
|
return found # Return first successful find
|
||||||
|
|
||||||
|
# Fallback: try finding without explicit namespace (might work if default ns is used throughout)
|
||||||
|
# This might require adjusting the path string itself depending on the XML structure
|
||||||
|
try:
|
||||||
|
# Simple attempt without namespace handling if the above fails
|
||||||
|
return element.findall(path)
|
||||||
|
except (
|
||||||
|
SyntaxError
|
||||||
|
): # Handle potential errors if path isn't valid without namespaces
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def parse_aml_to_markdown(aml_file_path, md_file_path):
|
||||||
|
"""Parses the AML file and generates a Markdown summary."""
|
||||||
|
print(f"Parsing AML file: {aml_file_path}")
|
||||||
|
try:
|
||||||
|
tree = ET.parse(aml_file_path)
|
||||||
|
root = tree.getroot()
|
||||||
|
|
||||||
|
markdown_lines = ["# Project CAx Data Summary (AutomationML)", ""]
|
||||||
|
|
||||||
|
# Find InstanceHierarchy - usually contains the project structure
|
||||||
|
# Note: Namespace handling in ElementTree can be tricky. Adjust '{...}' part if needed.
|
||||||
|
# We will use a helper function 'find_elements' to try common patterns
|
||||||
|
instance_hierarchies = find_elements(
|
||||||
|
root, ".//InstanceHierarchy"
|
||||||
|
) # Common CAEX tag
|
||||||
|
|
||||||
|
if not instance_hierarchies:
|
||||||
|
markdown_lines.append("Could not find InstanceHierarchy in the AML file.")
|
||||||
|
print("Warning: Could not find InstanceHierarchy element.")
|
||||||
|
else:
|
||||||
|
# Assuming the first InstanceHierarchy is the main one
|
||||||
|
ih = instance_hierarchies[0]
|
||||||
|
markdown_lines.append(f"## Instance Hierarchy: {ih.get('Name', 'N/A')}")
|
||||||
|
markdown_lines.append("")
|
||||||
|
|
||||||
|
# Look for InternalElements which represent devices/components
|
||||||
|
internal_elements = find_elements(
|
||||||
|
ih, ".//InternalElement"
|
||||||
|
) # Common CAEX tag
|
||||||
|
|
||||||
|
if not internal_elements:
|
||||||
|
markdown_lines.append(
|
||||||
|
"No devices (InternalElement) found in InstanceHierarchy."
|
||||||
|
)
|
||||||
|
print("Info: No InternalElement tags found under InstanceHierarchy.")
|
||||||
|
else:
|
||||||
|
markdown_lines.append(
|
||||||
|
f"Found {len(internal_elements)} device(s)/component(s):"
|
||||||
|
)
|
||||||
|
markdown_lines.append("")
|
||||||
|
markdown_lines.append(
|
||||||
|
"| Name | SystemUnitClass | RefBaseSystemUnitPath | Attributes |"
|
||||||
|
)
|
||||||
|
markdown_lines.append("|---|---|---|---|")
|
||||||
|
|
||||||
|
for elem in internal_elements:
|
||||||
|
name = elem.get("Name", "N/A")
|
||||||
|
ref_path = elem.get(
|
||||||
|
"RefBaseSystemUnitPath", "N/A"
|
||||||
|
) # Path to class definition
|
||||||
|
|
||||||
|
# Try to get the class name from the RefBaseSystemUnitPath or SystemUnitClassLib
|
||||||
|
su_class_path = find_elements(
|
||||||
|
elem, ".//SystemUnitClass"
|
||||||
|
) # Check direct child first
|
||||||
|
su_class = (
|
||||||
|
su_class_path[0].get("Path", "N/A")
|
||||||
|
if su_class_path
|
||||||
|
else ref_path.split("/")[-1]
|
||||||
|
) # Fallback to last part of path
|
||||||
|
|
||||||
|
attributes_md = ""
|
||||||
|
attributes = find_elements(elem, ".//Attribute") # Find attributes
|
||||||
|
attr_list = []
|
||||||
|
for attr in attributes:
|
||||||
|
attr_name = attr.get("Name", "")
|
||||||
|
attr_value_elem = find_elements(
|
||||||
|
attr, ".//Value"
|
||||||
|
) # Get Value element
|
||||||
|
attr_value = (
|
||||||
|
attr_value_elem[0].text
|
||||||
|
if attr_value_elem and attr_value_elem[0].text
|
||||||
|
else "N/A"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Look for potential IP addresses (common attribute names)
|
||||||
|
if "Address" in attr_name or "IP" in attr_name:
|
||||||
|
attr_list.append(f"**{attr_name}**: {attr_value}")
|
||||||
|
else:
|
||||||
|
attr_list.append(f"{attr_name}: {attr_value}")
|
||||||
|
|
||||||
|
attributes_md = "<br>".join(attr_list) if attr_list else "None"
|
||||||
|
|
||||||
|
markdown_lines.append(
|
||||||
|
f"| {name} | {su_class} | `{ref_path}` | {attributes_md} |"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Write to Markdown file
|
||||||
|
with open(md_file_path, "w", encoding="utf-8") as f:
|
||||||
|
f.write("\n".join(markdown_lines))
|
||||||
|
print(f"Markdown summary written to: {md_file_path}")
|
||||||
|
|
||||||
|
except ET.ParseError as xml_err:
|
||||||
|
print(f"ERROR parsing XML file {aml_file_path}: {xml_err}")
|
||||||
|
with open(md_file_path, "w", encoding="utf-8") as f:
|
||||||
|
f.write(
|
||||||
|
f"# Error\n\nFailed to parse AML file: {os.path.basename(aml_file_path)}\n\nError: {xml_err}"
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"ERROR processing AML file {aml_file_path}: {e}")
|
||||||
|
traceback.print_exc()
|
||||||
|
with open(md_file_path, "w", encoding="utf-8") as f:
|
||||||
|
f.write(
|
||||||
|
f"# Error\n\nAn unexpected error occurred while processing AML file: {os.path.basename(aml_file_path)}\n\nError: {e}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# --- Main Script ---
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
configs = load_configuration()
|
||||||
|
working_directory = configs.get("working_directory")
|
||||||
|
|
||||||
|
print("--- TIA Portal Project CAx Exporter and Analyzer ---")
|
||||||
|
|
||||||
|
# Validate working directory
|
||||||
|
if not working_directory or not os.path.isdir(working_directory):
|
||||||
|
print("ERROR: Working directory not set or invalid in configuration.")
|
||||||
|
print("Please configure the working directory using the main application.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# 1. Select Project File, Output Directory comes from config
|
||||||
|
project_file = select_project_file()
|
||||||
|
output_dir = Path(
|
||||||
|
working_directory
|
||||||
|
) # Use working directory from config, ensure it's a Path object
|
||||||
|
|
||||||
|
print(f"\nSelected Project: {project_file}")
|
||||||
|
print(f"Using Output Directory (Working Directory): {output_dir}")
|
||||||
|
|
||||||
|
# 2. Detect TIA Portal version from project file
|
||||||
|
tia_version = detect_tia_version(project_file)
|
||||||
|
|
||||||
|
# Define output file names using Path object
|
||||||
|
project_path = Path(project_file)
|
||||||
|
project_base_name = project_path.stem # Get filename without extension
|
||||||
|
aml_file = output_dir / f"{project_base_name}_CAx_Export.aml"
|
||||||
|
md_file = output_dir / f"{project_base_name}_CAx_Summary.md"
|
||||||
|
log_file = (
|
||||||
|
output_dir / f"{project_base_name}_CAx_Export.log"
|
||||||
|
) # Log file for the export process
|
||||||
|
|
||||||
|
print(f"Will export CAx data to: {aml_file}")
|
||||||
|
print(f"Will generate summary to: {md_file}")
|
||||||
|
print(f"Export log file: {log_file}")
|
||||||
|
|
||||||
|
portal_instance = None
|
||||||
|
project_object = None
|
||||||
|
cax_export_successful = False
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 3. Connect to TIA Portal with detected version
|
||||||
|
print(f"\nConnecting to TIA Portal V{tia_version}...")
|
||||||
|
portal_instance = ts.open_portal(
|
||||||
|
version=tia_version,
|
||||||
|
portal_mode=ts.Enums.PortalMode.WithGraphicalUserInterface,
|
||||||
|
)
|
||||||
|
print("Connected.")
|
||||||
|
|
||||||
|
# 4. Open Project
|
||||||
|
print(
|
||||||
|
f"Opening project: {project_path.name}..."
|
||||||
|
) # Use Path object's name attribute
|
||||||
|
project_object = portal_instance.open_project(
|
||||||
|
project_file_path=str(project_path)
|
||||||
|
) # Pass path as string
|
||||||
|
if project_object is None:
|
||||||
|
print("Project might already be open, attempting to get handle...")
|
||||||
|
project_object = portal_instance.get_project()
|
||||||
|
if project_object is None:
|
||||||
|
raise Exception("Failed to open or get the specified project.")
|
||||||
|
print("Project opened.")
|
||||||
|
|
||||||
|
# 5. Export CAx Data (Project Level)
|
||||||
|
print(f"Exporting CAx data for the project to {aml_file}...")
|
||||||
|
# Ensure output directory exists (Path.mkdir handles this implicitly if needed later, but good practice)
|
||||||
|
output_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
# Pass paths as strings to the TIA function
|
||||||
|
export_result = project_object.export_cax_data(
|
||||||
|
export_file_path=str(aml_file), log_file_path=str(log_file)
|
||||||
|
)
|
||||||
|
|
||||||
|
if export_result:
|
||||||
|
print("CAx data exported successfully.")
|
||||||
|
cax_export_successful = True
|
||||||
|
else:
|
||||||
|
print("CAx data export failed. Check the log file for details:")
|
||||||
|
print(f" Log file: {log_file}")
|
||||||
|
# Write basic error message to MD file if export fails
|
||||||
|
with open(md_file, "w", encoding="utf-8") as f:
|
||||||
|
f.write(
|
||||||
|
f"# Error\n\nCAx data export failed. Check log file: {log_file}"
|
||||||
|
)
|
||||||
|
|
||||||
|
except ts.TiaException as tia_ex:
|
||||||
|
print(f"\nTIA Portal Openness Error: {tia_ex}")
|
||||||
|
traceback.print_exc()
|
||||||
|
except FileNotFoundError:
|
||||||
|
print(f"\nERROR: Project file not found at {project_file}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"\nAn unexpected error occurred during TIA interaction: {e}")
|
||||||
|
traceback.print_exc()
|
||||||
|
finally:
|
||||||
|
# Close TIA Portal before processing the file (or detach)
|
||||||
|
if portal_instance:
|
||||||
|
try:
|
||||||
|
print("\nClosing TIA Portal...")
|
||||||
|
portal_instance.close_portal()
|
||||||
|
print("TIA Portal closed.")
|
||||||
|
except Exception as close_ex:
|
||||||
|
print(f"Error during TIA Portal cleanup: {close_ex}")
|
||||||
|
|
||||||
|
# 6. Parse AML and Generate Markdown (only if export was successful)
|
||||||
|
if cax_export_successful:
|
||||||
|
if aml_file.exists(): # Use Path object's exists() method
|
||||||
|
parse_aml_to_markdown(aml_file, md_file)
|
||||||
|
else:
|
||||||
|
print(
|
||||||
|
f"ERROR: Export was reported successful, but AML file not found at {aml_file}"
|
||||||
|
)
|
||||||
|
with open(md_file, "w", encoding="utf-8") as f:
|
||||||
|
f.write(
|
||||||
|
f"# Error\n\nExport was reported successful, but AML file not found:\n{aml_file}"
|
||||||
|
)
|
||||||
|
|
||||||
|
print("\nScript finished.")
|
File diff suppressed because it is too large
Load Diff
|
@ -5,5 +5,5 @@
|
||||||
},
|
},
|
||||||
"level2": {},
|
"level2": {},
|
||||||
"level3": {},
|
"level3": {},
|
||||||
"working_directory": "C:\\Trabajo\\SIDEL\\09 - SAE452 - Diet as Regular - San Giovanni in Bosco\\Reporte\\SourceDoc\\SourcdSD"
|
"working_directory": "D:\\Trabajo\\VM\\44 - 98050 - Fiera\\Reporte\\ExportsTia\\Source"
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
"path": "C:\\Trabajo\\SIDEL\\09 - SAE452 - Diet as Regular - San Giovanni in Bosco\\Reporte\\SourceDoc\\SourcdSD",
|
"path": "D:\\Trabajo\\VM\\44 - 98050 - Fiera\\Reporte\\ExportsTia\\Source",
|
||||||
"history": [
|
"history": [
|
||||||
|
"D:\\Trabajo\\VM\\44 - 98050 - Fiera\\Reporte\\ExportsTia\\Source",
|
||||||
"C:\\Trabajo\\SIDEL\\09 - SAE452 - Diet as Regular - San Giovanni in Bosco\\Reporte\\SourceDoc\\SourcdSD",
|
"C:\\Trabajo\\SIDEL\\09 - SAE452 - Diet as Regular - San Giovanni in Bosco\\Reporte\\SourceDoc\\SourcdSD",
|
||||||
"C:\\Trabajo\\SIDEL\\09 - SAE452 - Diet as Regular - San Giovanni in Bosco\\Reporte\\SourceDoc\\SourceXML"
|
"C:\\Trabajo\\SIDEL\\09 - SAE452 - Diet as Regular - San Giovanni in Bosco\\Reporte\\SourceDoc\\SourceXML"
|
||||||
]
|
]
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -15,5 +15,5 @@
|
||||||
"xref_source_subdir": "source"
|
"xref_source_subdir": "source"
|
||||||
},
|
},
|
||||||
"level3": {},
|
"level3": {},
|
||||||
"working_directory": "C:\\Trabajo\\SIDEL\\09 - SAE452 - Diet as Regular - San Giovanni in Bosco\\Reporte\\SourceDoc\\SourceXML"
|
"working_directory": "D:\\Trabajo\\VM\\44 - 98050 - Fiera\\Reporte\\ExportsTia\\Source"
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
"path": "C:\\Trabajo\\SIDEL\\09 - SAE452 - Diet as Regular - San Giovanni in Bosco\\Reporte\\SourceDoc\\SourceXML",
|
"path": "D:\\Trabajo\\VM\\44 - 98050 - Fiera\\Reporte\\ExportsTia\\Source",
|
||||||
"history": [
|
"history": [
|
||||||
|
"D:\\Trabajo\\VM\\44 - 98050 - Fiera\\Reporte\\ExportsTia\\Source",
|
||||||
"C:\\Trabajo\\SIDEL\\09 - SAE452 - Diet as Regular - San Giovanni in Bosco\\Reporte\\SourceDoc\\SourceXML",
|
"C:\\Trabajo\\SIDEL\\09 - SAE452 - Diet as Regular - San Giovanni in Bosco\\Reporte\\SourceDoc\\SourceXML",
|
||||||
"C:\\Trabajo\\SIDEL\\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\\Reporte\\IOExport"
|
"C:\\Trabajo\\SIDEL\\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\\Reporte\\IOExport"
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,5 +1,213 @@
|
||||||
{
|
{
|
||||||
"history": [
|
"history": [
|
||||||
|
{
|
||||||
|
"id": "a599effd",
|
||||||
|
"group_id": "4",
|
||||||
|
"script_name": "x1.py",
|
||||||
|
"executed_date": "2025-06-12T19:59:02.082348Z",
|
||||||
|
"arguments": [],
|
||||||
|
"working_directory": "D:/Proyectos/Scripts/Siemens/Tia Portal Utils",
|
||||||
|
"python_env": "tia_scripting",
|
||||||
|
"executable_type": "pythonw.exe",
|
||||||
|
"status": "running",
|
||||||
|
"pid": 36824,
|
||||||
|
"execution_time": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "d722b721",
|
||||||
|
"group_id": "4",
|
||||||
|
"script_name": "x1.py",
|
||||||
|
"executed_date": "2025-06-12T09:27:11.172727Z",
|
||||||
|
"arguments": [],
|
||||||
|
"working_directory": "D:/Proyectos/Scripts/Siemens/Tia Portal Utils",
|
||||||
|
"python_env": "tia_scripting",
|
||||||
|
"executable_type": "pythonw.exe",
|
||||||
|
"status": "running",
|
||||||
|
"pid": 24964,
|
||||||
|
"execution_time": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "0a84ec87",
|
||||||
|
"group_id": "1",
|
||||||
|
"script_name": "calc.py",
|
||||||
|
"executed_date": "2025-06-12T09:24:00.527248Z",
|
||||||
|
"arguments": [],
|
||||||
|
"working_directory": "D:/Proyectos/Scripts/Calcv2",
|
||||||
|
"python_env": "tia_scripting",
|
||||||
|
"executable_type": "pythonw.exe",
|
||||||
|
"status": "running",
|
||||||
|
"pid": 15548,
|
||||||
|
"execution_time": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "6297e689",
|
||||||
|
"group_id": "4",
|
||||||
|
"script_name": "x1.py",
|
||||||
|
"executed_date": "2025-06-12T09:16:08.148925Z",
|
||||||
|
"arguments": [],
|
||||||
|
"working_directory": "D:/Proyectos/Scripts/Siemens/Tia Portal Utils",
|
||||||
|
"python_env": "tia_scripting",
|
||||||
|
"executable_type": "pythonw.exe",
|
||||||
|
"status": "running",
|
||||||
|
"pid": 16892,
|
||||||
|
"execution_time": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "79f5a9e6",
|
||||||
|
"group_id": "4",
|
||||||
|
"script_name": "x1.py",
|
||||||
|
"executed_date": "2025-06-12T09:07:06.392550Z",
|
||||||
|
"arguments": [],
|
||||||
|
"working_directory": "D:/Proyectos/Scripts/Siemens/Tia Portal Utils",
|
||||||
|
"python_env": "tia_scripting",
|
||||||
|
"executable_type": "pythonw.exe",
|
||||||
|
"status": "running",
|
||||||
|
"pid": 45652,
|
||||||
|
"execution_time": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "22e264cd",
|
||||||
|
"group_id": "4",
|
||||||
|
"script_name": "x1.py",
|
||||||
|
"executed_date": "2025-06-12T09:07:06.280903Z",
|
||||||
|
"arguments": [],
|
||||||
|
"working_directory": "D:/Proyectos/Scripts/Siemens/Tia Portal Utils",
|
||||||
|
"python_env": "tia_scripting",
|
||||||
|
"executable_type": "pythonw.exe",
|
||||||
|
"status": "running",
|
||||||
|
"pid": 25984,
|
||||||
|
"execution_time": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "589be793",
|
||||||
|
"group_id": "4",
|
||||||
|
"script_name": "x1.py",
|
||||||
|
"executed_date": "2025-06-11T23:17:19.621521Z",
|
||||||
|
"arguments": [],
|
||||||
|
"working_directory": "D:/Proyectos/Scripts/Siemens/Tia Portal Utils",
|
||||||
|
"python_env": "tia_scripting",
|
||||||
|
"executable_type": "python.exe",
|
||||||
|
"status": "success",
|
||||||
|
"pid": 25652,
|
||||||
|
"execution_time": 389.689278
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "6ca3fbde",
|
||||||
|
"group_id": "4",
|
||||||
|
"script_name": "x1.py",
|
||||||
|
"executed_date": "2025-06-11T23:17:06.940558Z",
|
||||||
|
"arguments": [],
|
||||||
|
"working_directory": "D:/Proyectos/Scripts/Siemens/Tia Portal Utils",
|
||||||
|
"python_env": "tia_scripting",
|
||||||
|
"executable_type": "pythonw.exe",
|
||||||
|
"status": "running",
|
||||||
|
"pid": 29496,
|
||||||
|
"execution_time": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "6f646ca2",
|
||||||
|
"group_id": "4",
|
||||||
|
"script_name": "x1.py",
|
||||||
|
"executed_date": "2025-06-11T23:16:59.013936Z",
|
||||||
|
"arguments": [],
|
||||||
|
"working_directory": "D:/Proyectos/Scripts/Siemens/Tia Portal Utils",
|
||||||
|
"python_env": "tia_scripting",
|
||||||
|
"executable_type": "python.exe",
|
||||||
|
"status": "success",
|
||||||
|
"pid": 38516,
|
||||||
|
"execution_time": 3.471176
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "88e35e8b",
|
||||||
|
"group_id": "2",
|
||||||
|
"script_name": "main.py",
|
||||||
|
"executed_date": "2025-06-11T14:00:34.786377Z",
|
||||||
|
"arguments": [],
|
||||||
|
"working_directory": "D:/Proyectos/Scripts/RS485/MaselliSimulatorApp",
|
||||||
|
"python_env": "tia_scripting",
|
||||||
|
"executable_type": "pythonw.exe",
|
||||||
|
"status": "running",
|
||||||
|
"pid": 404,
|
||||||
|
"execution_time": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "b373c77d",
|
||||||
|
"group_id": "2",
|
||||||
|
"script_name": "main.py",
|
||||||
|
"executed_date": "2025-06-11T13:51:11.750064Z",
|
||||||
|
"arguments": [],
|
||||||
|
"working_directory": "D:/Proyectos/Scripts/RS485/MaselliSimulatorApp",
|
||||||
|
"python_env": "tia_scripting",
|
||||||
|
"executable_type": "pythonw.exe",
|
||||||
|
"status": "running",
|
||||||
|
"pid": 24472,
|
||||||
|
"execution_time": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "455a8271",
|
||||||
|
"group_id": "2",
|
||||||
|
"script_name": "main.py",
|
||||||
|
"executed_date": "2025-06-10T15:45:56.713179Z",
|
||||||
|
"arguments": [],
|
||||||
|
"working_directory": "D:/Proyectos/Scripts/RS485/MaselliSimulatorApp",
|
||||||
|
"python_env": "tia_scripting",
|
||||||
|
"executable_type": "pythonw.exe",
|
||||||
|
"status": "running",
|
||||||
|
"pid": 16480,
|
||||||
|
"execution_time": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "a8b813b0",
|
||||||
|
"group_id": "2",
|
||||||
|
"script_name": "main.py",
|
||||||
|
"executed_date": "2025-06-10T15:40:39.728099Z",
|
||||||
|
"arguments": [],
|
||||||
|
"working_directory": "D:/Proyectos/Scripts/RS485/MaselliSimulatorApp",
|
||||||
|
"python_env": "tia_scripting",
|
||||||
|
"executable_type": "pythonw.exe",
|
||||||
|
"status": "running",
|
||||||
|
"pid": 36640,
|
||||||
|
"execution_time": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "7924a173",
|
||||||
|
"group_id": "2",
|
||||||
|
"script_name": "main.py",
|
||||||
|
"executed_date": "2025-06-10T15:36:55.303738Z",
|
||||||
|
"arguments": [],
|
||||||
|
"working_directory": "D:/Proyectos/Scripts/RS485/MaselliSimulatorApp",
|
||||||
|
"python_env": "tia_scripting",
|
||||||
|
"executable_type": "pythonw.exe",
|
||||||
|
"status": "running",
|
||||||
|
"pid": 15144,
|
||||||
|
"execution_time": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "c3796f4e",
|
||||||
|
"group_id": "2",
|
||||||
|
"script_name": "main.py",
|
||||||
|
"executed_date": "2025-06-10T15:36:18.822898Z",
|
||||||
|
"arguments": [],
|
||||||
|
"working_directory": "D:/Proyectos/Scripts/RS485/MaselliSimulatorApp",
|
||||||
|
"python_env": "tia_scripting",
|
||||||
|
"executable_type": "pythonw.exe",
|
||||||
|
"status": "running",
|
||||||
|
"pid": 30656,
|
||||||
|
"execution_time": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1040f2b6",
|
||||||
|
"group_id": "2",
|
||||||
|
"script_name": "main.py",
|
||||||
|
"executed_date": "2025-06-10T11:03:59.233659Z",
|
||||||
|
"arguments": [],
|
||||||
|
"working_directory": "D:/Proyectos/Scripts/RS485/MaselliSimulatorApp",
|
||||||
|
"python_env": "tia_scripting",
|
||||||
|
"executable_type": "pythonw.exe",
|
||||||
|
"status": "running",
|
||||||
|
"pid": 26152,
|
||||||
|
"execution_time": null
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "6d4e8908",
|
"id": "6d4e8908",
|
||||||
"group_id": "1",
|
"group_id": "1",
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -33,6 +33,19 @@
|
||||||
"directory": "D:/Proyectos/Scripts/HMI Translate",
|
"directory": "D:/Proyectos/Scripts/HMI Translate",
|
||||||
"created_date": "2025-06-03T12:31:19.529046Z",
|
"created_date": "2025-06-03T12:31:19.529046Z",
|
||||||
"updated_date": "2025-06-03T12:44:24.651659Z"
|
"updated_date": "2025-06-03T12:44:24.651659Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "4",
|
||||||
|
"name": "Tia Portal Utils",
|
||||||
|
"description": "",
|
||||||
|
"category": "Otros",
|
||||||
|
"version": "1.0",
|
||||||
|
"python_env": "tia_scripting",
|
||||||
|
"directory": "D:/Proyectos/Scripts/Siemens/Tia Portal Utils",
|
||||||
|
"author": "",
|
||||||
|
"tags": [],
|
||||||
|
"created_date": "2025-06-11T22:55:41.635081Z",
|
||||||
|
"updated_date": "2025-06-11T22:55:41.635081Z"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"categories": {
|
"categories": {
|
||||||
|
|
10
data/log.txt
10
data/log.txt
|
@ -1,5 +1,5 @@
|
||||||
[15:36:49] Iniciando ejecución de x7_update_CAx.py en D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia...
|
[20:03:36] Iniciando ejecución de x1.py en D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\Source...
|
||||||
[15:36:49] --- Actualizador de AML desde Excel Modificado (v1.1 - Simplified IO Address Handling (Start/End Separated)) ---
|
[20:03:37] --- TIA Portal Data Exporter (Blocks, UDTs, Tags) ---
|
||||||
[15:36:49] Directorio de trabajo: D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia
|
[20:03:47] No project file selected. Exiting.
|
||||||
[15:36:49] 1. Seleccione el archivo AML original:
|
[20:03:47] Ejecución de x1.py finalizada (success). Duración: 0:00:10.497365.
|
||||||
[15:36:57] 2. Seleccione el archivo Excel modificado:
|
[20:03:47] Log completo guardado en: D:\Proyectos\Scripts\ParamManagerScripts\backend\script_groups\ObtainIOFromProjectTia\log_x1.txt
|
||||||
|
|
|
@ -248,15 +248,24 @@ class LauncherManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Función actualizada para mostrar/ocultar ambos botones de editor
|
// Función actualizada para mostrar/ocultar todos los botones
|
||||||
updateEditorButtons(show) {
|
updateEditorButtons(show) {
|
||||||
const vscodeButton = document.getElementById('vscode-launcher-btn');
|
const vscodeButton = document.getElementById('vscode-launcher-btn');
|
||||||
const cursorButton = document.getElementById('cursor-launcher-btn');
|
const cursorButton = document.getElementById('cursor-launcher-btn');
|
||||||
|
const folderButton = document.getElementById('folder-launcher-btn');
|
||||||
|
const copyPathButton = document.getElementById('copy-path-launcher-btn');
|
||||||
|
|
||||||
if (vscodeButton) {
|
if (vscodeButton) {
|
||||||
vscodeButton.style.display = show ? 'inline-flex' : 'none'; // Usar inline-flex para iconos+texto si aplica
|
vscodeButton.style.display = show ? 'block' : 'none';
|
||||||
}
|
}
|
||||||
if (cursorButton) {
|
if (cursorButton) {
|
||||||
cursorButton.style.display = show ? 'inline-flex' : 'none'; // Usar inline-flex para iconos+texto si aplica
|
cursorButton.style.display = show ? 'block' : 'none';
|
||||||
|
}
|
||||||
|
if (folderButton) {
|
||||||
|
folderButton.style.display = show ? 'block' : 'none';
|
||||||
|
}
|
||||||
|
if (copyPathButton) {
|
||||||
|
copyPathButton.style.display = show ? 'block' : 'none';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1101,8 +1110,7 @@ class LauncherManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
async clearLauncherHistory() {
|
async clearLauncherHistory() {
|
||||||
if (!confirm('¿Estás seguro de que quieres limpiar el historial?')) return;
|
// Eliminada la confirmación - directamente procede a limpiar
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch('/api/launcher-history', {
|
const response = await fetch('/api/launcher-history', {
|
||||||
method: 'DELETE'
|
method: 'DELETE'
|
||||||
|
@ -1112,6 +1120,7 @@ class LauncherManager {
|
||||||
if (result.status === 'success') {
|
if (result.status === 'success') {
|
||||||
this.history = [];
|
this.history = [];
|
||||||
this.renderHistory();
|
this.renderHistory();
|
||||||
|
console.log('Historial del launcher limpiado');
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error clearing history:', error);
|
console.error('Error clearing history:', error);
|
||||||
|
@ -1251,8 +1260,7 @@ class LauncherManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
async terminateProcess(pid) {
|
async terminateProcess(pid) {
|
||||||
if (!confirm('¿Estás seguro de que quieres cerrar este proceso?')) return;
|
// Eliminada la confirmación - directamente procede a cerrar
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api/launcher-process-terminate/${pid}`, {
|
const response = await fetch(`/api/launcher-process-terminate/${pid}`, {
|
||||||
method: 'POST'
|
method: 'POST'
|
||||||
|
@ -1271,6 +1279,73 @@ class LauncherManager {
|
||||||
alert('Error cerrando proceso');
|
alert('Error cerrando proceso');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Nueva función para abrir carpeta del grupo launcher
|
||||||
|
async openGroupFolder() {
|
||||||
|
if (!this.currentGroup) {
|
||||||
|
alert('Selecciona un grupo primero');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(`/api/open-group-folder/launcher/${this.currentGroup.id}`, {
|
||||||
|
method: 'POST'
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
if (result.status === 'success') {
|
||||||
|
console.log(`Carpeta abierta: ${result.path}`);
|
||||||
|
} else {
|
||||||
|
alert(`Error al abrir carpeta: ${result.message}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error opening folder:', error);
|
||||||
|
alert('Error al comunicarse con el servidor');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nueva función para copiar path del grupo launcher
|
||||||
|
async copyGroupPath() {
|
||||||
|
if (!this.currentGroup) {
|
||||||
|
alert('Selecciona un grupo primero');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(`/api/get-group-path/launcher/${this.currentGroup.id}`);
|
||||||
|
const result = await response.json();
|
||||||
|
|
||||||
|
if (result.status === 'success') {
|
||||||
|
// Copiar al portapapeles usando la API moderna
|
||||||
|
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||||
|
await navigator.clipboard.writeText(result.path);
|
||||||
|
console.log('Path copiado al portapapeles');
|
||||||
|
} else {
|
||||||
|
// Fallback para navegadores más antiguos
|
||||||
|
const textArea = document.createElement('textarea');
|
||||||
|
textArea.value = result.path;
|
||||||
|
document.body.appendChild(textArea);
|
||||||
|
textArea.focus();
|
||||||
|
textArea.select();
|
||||||
|
|
||||||
|
try {
|
||||||
|
document.execCommand('copy');
|
||||||
|
console.log('Path copiado al portapapeles');
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error copying to clipboard:', err);
|
||||||
|
alert(`Error al copiar. Path: ${result.path}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.body.removeChild(textArea);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
alert(`Error al obtener path: ${result.message}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error getting path:', error);
|
||||||
|
alert('Error al comunicarse con el servidor');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// === FUNCIONES GLOBALES ===
|
// === FUNCIONES GLOBALES ===
|
||||||
|
@ -1416,3 +1491,21 @@ function closeMarkdownViewer() {
|
||||||
document.addEventListener('DOMContentLoaded', function () {
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
console.log('Launcher JS loaded');
|
console.log('Launcher JS loaded');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Función para colapsar/expandir el historial
|
||||||
|
function toggleHistoryPanel() {
|
||||||
|
const historyList = document.getElementById('history-list');
|
||||||
|
const toggleIcon = document.getElementById('history-toggle-icon');
|
||||||
|
|
||||||
|
if (historyList && toggleIcon) {
|
||||||
|
if (historyList.classList.contains('hidden')) {
|
||||||
|
// Expandir
|
||||||
|
historyList.classList.remove('hidden');
|
||||||
|
toggleIcon.textContent = '▼';
|
||||||
|
} else {
|
||||||
|
// Colapsar
|
||||||
|
historyList.classList.add('hidden');
|
||||||
|
toggleIcon.textContent = '▶';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ function initWebSocket() {
|
||||||
async function loadConfigs() {
|
async function loadConfigs() {
|
||||||
const group = currentGroup;
|
const group = currentGroup;
|
||||||
console.log('Loading configs for group:', group);
|
console.log('Loading configs for group:', group);
|
||||||
|
|
||||||
if (!group) {
|
if (!group) {
|
||||||
console.error('No group selected');
|
console.error('No group selected');
|
||||||
return;
|
return;
|
||||||
|
@ -61,11 +61,11 @@ async function loadConfigs() {
|
||||||
console.log(`Level ${level} data:`, data);
|
console.log(`Level ${level} data:`, data);
|
||||||
await renderForm(`level${level}-form`, data);
|
await renderForm(`level${level}-form`, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cargar nivel 3 solo si hay directorio de trabajo
|
// Cargar nivel 3 solo si hay directorio de trabajo
|
||||||
const workingDirResponse = await fetch(`/api/working-directory/${group}`);
|
const workingDirResponse = await fetch(`/api/working-directory/${group}`);
|
||||||
const workingDirResult = await workingDirResponse.json();
|
const workingDirResult = await workingDirResponse.json();
|
||||||
|
|
||||||
if (workingDirResult.status === 'success' && workingDirResult.path) {
|
if (workingDirResult.status === 'success' && workingDirResult.path) {
|
||||||
console.log('Loading level 3 config...');
|
console.log('Loading level 3 config...');
|
||||||
const response = await fetch(`/api/config/3?group=${group}`);
|
const response = await fetch(`/api/config/3?group=${group}`);
|
||||||
|
@ -73,14 +73,14 @@ async function loadConfigs() {
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
console.log('Level 3 data:', data);
|
console.log('Level 3 data:', data);
|
||||||
await renderForm('level3-form', data);
|
await renderForm('level3-form', data);
|
||||||
|
|
||||||
// Actualizar input del directorio de trabajo
|
// Actualizar input del directorio de trabajo
|
||||||
document.getElementById('working-directory').value = workingDirResult.path;
|
document.getElementById('working-directory').value = workingDirResult.path;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cargar scripts disponibles
|
// Cargar scripts disponibles
|
||||||
await loadScripts(group);
|
await loadScripts(group);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error loading configs:', error);
|
console.error('Error loading configs:', error);
|
||||||
}
|
}
|
||||||
|
@ -193,15 +193,15 @@ async function loadScripts(group) {
|
||||||
</div>
|
</div>
|
||||||
<div id="long-desc-${script.filename}" class="long-description-content mt-2 border-t pt-2 hidden">
|
<div id="long-desc-${script.filename}" class="long-description-content mt-2 border-t pt-2 hidden">
|
||||||
${script.long_description ? (() => { // Self-invoking function to handle markdown rendering
|
${script.long_description ? (() => { // Self-invoking function to handle markdown rendering
|
||||||
if (typeof window.markdownit === 'undefined') { // Check if markdownit is loaded
|
if (typeof window.markdownit === 'undefined') { // Check if markdownit is loaded
|
||||||
console.error("markdown-it library not loaded!");
|
console.error("markdown-it library not loaded!");
|
||||||
return `<p class="text-red-500">Error: Librería Markdown no cargada.</p><pre>${script.long_description}</pre>`; // Fallback: show raw text
|
return `<p class="text-red-500">Error: Librería Markdown no cargada.</p><pre>${script.long_description}</pre>`; // Fallback: show raw text
|
||||||
}
|
}
|
||||||
// Create instance and render
|
// Create instance and render
|
||||||
const md = window.markdownit();
|
const md = window.markdownit();
|
||||||
const renderedHtml = md.render(script.long_description); // Renderizar
|
const renderedHtml = md.render(script.long_description); // Renderizar
|
||||||
return renderedHtml;
|
return renderedHtml;
|
||||||
})() : ''}
|
})() : ''}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center gap-2 flex-shrink-0">
|
<div class="flex items-center gap-2 flex-shrink-0">
|
||||||
|
@ -264,11 +264,11 @@ async function executeScript(scriptName) {
|
||||||
|
|
||||||
// Check for HTTP errors during the *request* itself
|
// Check for HTTP errors during the *request* itself
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const errorText = await response.text();
|
const errorText = await response.text();
|
||||||
console.error(`Error initiating script execution request: ${response.status} ${response.statusText}`, errorText);
|
console.error(`Error initiating script execution request: ${response.status} ${response.statusText}`, errorText);
|
||||||
// Log only the request error, not script execution errors which come via WebSocket
|
// Log only the request error, not script execution errors which come via WebSocket
|
||||||
addLogLine(`\nError al iniciar la petición del script: ${response.status} ${errorText}\n`);
|
addLogLine(`\nError al iniciar la petición del script: ${response.status} ${errorText}\n`);
|
||||||
return; // Stop if the request failed
|
return; // Stop if the request failed
|
||||||
}
|
}
|
||||||
|
|
||||||
// REMOVE logging the result/error here - let the backend log via WebSocket
|
// REMOVE logging the result/error here - let the backend log via WebSocket
|
||||||
|
@ -291,7 +291,7 @@ async function renderForm(containerId, data) {
|
||||||
console.log(`Rendering form for ${containerId} with data:`, data); // Debug line
|
console.log(`Rendering form for ${containerId} with data:`, data); // Debug line
|
||||||
const container = document.getElementById(containerId);
|
const container = document.getElementById(containerId);
|
||||||
const level = containerId.replace('level', '').split('-')[0];
|
const level = containerId.replace('level', '').split('-')[0];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const schemaResponse = await fetch(`/api/schema/${level}?group=${currentGroup}`);
|
const schemaResponse = await fetch(`/api/schema/${level}?group=${currentGroup}`);
|
||||||
const schema = await schemaResponse.json();
|
const schema = await schemaResponse.json();
|
||||||
|
@ -339,7 +339,7 @@ async function renderForm(containerId, data) {
|
||||||
function generateFormFields(schema, data, prefix, level) {
|
function generateFormFields(schema, data, prefix, level) {
|
||||||
console.log('Generating fields with data:', { schema, data, prefix, level }); // Debug line
|
console.log('Generating fields with data:', { schema, data, prefix, level }); // Debug line
|
||||||
let html = '';
|
let html = '';
|
||||||
|
|
||||||
if (!schema.properties) {
|
if (!schema.properties) {
|
||||||
console.warn('Schema has no properties');
|
console.warn('Schema has no properties');
|
||||||
return html;
|
return html;
|
||||||
|
@ -349,10 +349,10 @@ function generateFormFields(schema, data, prefix, level) {
|
||||||
const fullKey = prefix ? `${prefix}.${key}` : key;
|
const fullKey = prefix ? `${prefix}.${key}` : key;
|
||||||
const value = getValue(data, fullKey);
|
const value = getValue(data, fullKey);
|
||||||
console.log(`Field ${fullKey}:`, { definition: def, value: value }); // Debug line
|
console.log(`Field ${fullKey}:`, { definition: def, value: value }); // Debug line
|
||||||
|
|
||||||
html += `<div class="mb-4">
|
html += `<div class="mb-4">
|
||||||
<label class="block text-gray-700 text-sm font-bold mb-2">${def.title || key}</label>`;
|
<label class="block text-gray-700 text-sm font-bold mb-2">${def.title || key}</label>`;
|
||||||
|
|
||||||
if (def.type === 'object') {
|
if (def.type === 'object') {
|
||||||
html += `<div class="pl-4 border-l-2 border-gray-200">
|
html += `<div class="pl-4 border-l-2 border-gray-200">
|
||||||
${generateFormFields(def, data, fullKey, level)}
|
${generateFormFields(def, data, fullKey, level)}
|
||||||
|
@ -360,7 +360,7 @@ function generateFormFields(schema, data, prefix, level) {
|
||||||
} else {
|
} else {
|
||||||
html += generateInputField(def, fullKey, value, level);
|
html += generateInputField(def, fullKey, value, level);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (def.description) {
|
if (def.description) {
|
||||||
html += `<p class="text-gray-500 text-xs mt-1">${def.description}</p>`;
|
html += `<p class="text-gray-500 text-xs mt-1">${def.description}</p>`;
|
||||||
}
|
}
|
||||||
|
@ -372,7 +372,7 @@ function generateFormFields(schema, data, prefix, level) {
|
||||||
function getValue(data, path) {
|
function getValue(data, path) {
|
||||||
console.log('Getting value for path:', { path, data }); // Debug line
|
console.log('Getting value for path:', { path, data }); // Debug line
|
||||||
if (!data || !path) return undefined;
|
if (!data || !path) return undefined;
|
||||||
|
|
||||||
const value = path.split('.').reduce((obj, key) => obj?.[key], data);
|
const value = path.split('.').reduce((obj, key) => obj?.[key], data);
|
||||||
console.log('Found value:', value); // Debug line
|
console.log('Found value:', value); // Debug line
|
||||||
return value;
|
return value;
|
||||||
|
@ -381,7 +381,7 @@ function getValue(data, path) {
|
||||||
// Modificar la función generateInputField para quitar el onchange
|
// Modificar la función generateInputField para quitar el onchange
|
||||||
function generateInputField(def, key, value, level) {
|
function generateInputField(def, key, value, level) {
|
||||||
const baseClasses = "w-full p-2 border rounded bg-green-50";
|
const baseClasses = "w-full p-2 border rounded bg-green-50";
|
||||||
|
|
||||||
switch (def.type) {
|
switch (def.type) {
|
||||||
case 'string':
|
case 'string':
|
||||||
if (def.format === 'directory') {
|
if (def.format === 'directory') {
|
||||||
|
@ -403,11 +403,11 @@ function generateInputField(def, key, value, level) {
|
||||||
}
|
}
|
||||||
return `<input type="text" value="${value || ''}"
|
return `<input type="text" value="${value || ''}"
|
||||||
class="${baseClasses}" data-key="${key}">`;
|
class="${baseClasses}" data-key="${key}">`;
|
||||||
|
|
||||||
case 'number':
|
case 'number':
|
||||||
return `<input type="number" value="${value || 0}"
|
return `<input type="number" value="${value || 0}"
|
||||||
class="${baseClasses}" data-key="${key}">`;
|
class="${baseClasses}" data-key="${key}">`;
|
||||||
|
|
||||||
case 'boolean':
|
case 'boolean':
|
||||||
return `<input type="checkbox" ${value ? 'checked' : ''}
|
return `<input type="checkbox" ${value ? 'checked' : ''}
|
||||||
class="form-checkbox h-5 w-5 bg-green-50" data-key="${key}">
|
class="form-checkbox h-5 w-5 bg-green-50" data-key="${key}">
|
||||||
|
@ -426,7 +426,7 @@ async function browseFieldDirectory(button) {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api/browse-directories?current_path=${encodeURIComponent(currentPath)}`);
|
const response = await fetch(`/api/browse-directories?current_path=${encodeURIComponent(currentPath)}`);
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
|
|
||||||
if (result.status === 'success') {
|
if (result.status === 'success') {
|
||||||
input.value = result.path;
|
input.value = result.path;
|
||||||
// Disparar un evento change para actualizar el valor internamente
|
// Disparar un evento change para actualizar el valor internamente
|
||||||
|
@ -448,23 +448,23 @@ async function modifySchema(level) {
|
||||||
}
|
}
|
||||||
const schema = await response.json();
|
const schema = await response.json();
|
||||||
console.log('Loaded schema:', schema); // Debug line
|
console.log('Loaded schema:', schema); // Debug line
|
||||||
|
|
||||||
// Show schema editor modal
|
// Show schema editor modal
|
||||||
const modal = document.getElementById('schema-editor');
|
const modal = document.getElementById('schema-editor');
|
||||||
if (!modal) {
|
if (!modal) {
|
||||||
throw new Error('Schema editor modal not found');
|
throw new Error('Schema editor modal not found');
|
||||||
}
|
}
|
||||||
modal.classList.remove('hidden');
|
modal.classList.remove('hidden');
|
||||||
|
|
||||||
// Inicializar el esquema si está vacío
|
// Inicializar el esquema si está vacío
|
||||||
const finalSchema = Object.keys(schema).length === 0 ?
|
const finalSchema = Object.keys(schema).length === 0 ?
|
||||||
{ type: 'object', properties: {} } : schema;
|
{ type: 'object', properties: {} } : schema;
|
||||||
|
|
||||||
// Inicializar editores
|
// Inicializar editores
|
||||||
const jsonEditor = document.getElementById('json-editor');
|
const jsonEditor = document.getElementById('json-editor');
|
||||||
const visualEditor = document.getElementById('visual-editor');
|
const visualEditor = document.getElementById('visual-editor');
|
||||||
const schemaLevel = document.getElementById('schema-level');
|
const schemaLevel = document.getElementById('schema-level');
|
||||||
|
|
||||||
if (!jsonEditor || !visualEditor || !schemaLevel) {
|
if (!jsonEditor || !visualEditor || !schemaLevel) {
|
||||||
throw new Error('Required editor elements not found');
|
throw new Error('Required editor elements not found');
|
||||||
}
|
}
|
||||||
|
@ -473,10 +473,10 @@ async function modifySchema(level) {
|
||||||
visualEditor.innerHTML = '<div id="schema-fields" class="mb-4"></div>' +
|
visualEditor.innerHTML = '<div id="schema-fields" class="mb-4"></div>' +
|
||||||
'<button onclick="addSchemaField()" class="mt-4 bg-green-500 text-white px-4 py-2 rounded">Agregar Campo</button>';
|
'<button onclick="addSchemaField()" class="mt-4 bg-green-500 text-white px-4 py-2 rounded">Agregar Campo</button>';
|
||||||
schemaLevel.value = level;
|
schemaLevel.value = level;
|
||||||
|
|
||||||
// Renderizar editor visual
|
// Renderizar editor visual
|
||||||
renderVisualEditor(finalSchema);
|
renderVisualEditor(finalSchema);
|
||||||
|
|
||||||
// Activar pestaña visual por defecto
|
// Activar pestaña visual por defecto
|
||||||
switchEditorMode('visual');
|
switchEditorMode('visual');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -588,7 +588,7 @@ function createFieldEditor(key, field) {
|
||||||
function updateFieldType(select) {
|
function updateFieldType(select) {
|
||||||
const fieldContainer = select.closest('.schema-field');
|
const fieldContainer = select.closest('.schema-field');
|
||||||
const enumContainer = fieldContainer.querySelector('.enum-container');
|
const enumContainer = fieldContainer.querySelector('.enum-container');
|
||||||
|
|
||||||
if (select.value === 'enum') {
|
if (select.value === 'enum') {
|
||||||
if (!enumContainer) {
|
if (!enumContainer) {
|
||||||
const div = document.createElement('div');
|
const div = document.createElement('div');
|
||||||
|
@ -677,11 +677,11 @@ function updateVisualSchema() {
|
||||||
console.warn(`Valor por defecto inválido para número en campo '${key}': ${defaultValueString}. Se omitirá.`);
|
console.warn(`Valor por defecto inválido para número en campo '${key}': ${defaultValueString}. Se omitirá.`);
|
||||||
// No añadir default si no es un número válido
|
// No añadir default si no es un número válido
|
||||||
} else {
|
} else {
|
||||||
// Opcional: truncar si el tipo es integer
|
// Opcional: truncar si el tipo es integer
|
||||||
if (propertyDefinition.type === 'integer' && !Number.isInteger(typedDefaultValue)) {
|
if (propertyDefinition.type === 'integer' && !Number.isInteger(typedDefaultValue)) {
|
||||||
typedDefaultValue = Math.trunc(typedDefaultValue);
|
typedDefaultValue = Math.trunc(typedDefaultValue);
|
||||||
}
|
}
|
||||||
propertyDefinition.default = typedDefaultValue;
|
propertyDefinition.default = typedDefaultValue;
|
||||||
}
|
}
|
||||||
} else if (propertyDefinition.type === 'boolean') {
|
} else if (propertyDefinition.type === 'boolean') {
|
||||||
typedDefaultValue = ['true', '1', 'yes', 'on'].includes(defaultValueString.toLowerCase());
|
typedDefaultValue = ['true', '1', 'yes', 'on'].includes(defaultValueString.toLowerCase());
|
||||||
|
@ -730,16 +730,16 @@ async function saveSchema() {
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify(schema)
|
body: JSON.stringify(schema)
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recargar el formulario
|
// Recargar el formulario
|
||||||
const configResponse = await fetch(`/api/config/${level}?group=${currentGroup}`);
|
const configResponse = await fetch(`/api/config/${level}?group=${currentGroup}`);
|
||||||
const data = await configResponse.json();
|
const data = await configResponse.json();
|
||||||
await renderForm(`level${level}-form`, data);
|
await renderForm(`level${level}-form`, data);
|
||||||
|
|
||||||
// Cerrar modal
|
// Cerrar modal
|
||||||
document.getElementById('schema-editor').classList.add('hidden');
|
document.getElementById('schema-editor').classList.add('hidden');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -761,7 +761,7 @@ async function setWorkingDirectory() {
|
||||||
// Modificar initWorkingDirectory para cargar también el historial
|
// Modificar initWorkingDirectory para cargar también el historial
|
||||||
async function initWorkingDirectory() {
|
async function initWorkingDirectory() {
|
||||||
if (!currentGroup) return;
|
if (!currentGroup) return;
|
||||||
|
|
||||||
const response = await fetch(`/api/working-directory/${currentGroup}`);
|
const response = await fetch(`/api/working-directory/${currentGroup}`);
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
if (result.status === 'success' && result.path) {
|
if (result.status === 'success' && result.path) {
|
||||||
|
@ -780,7 +780,7 @@ async function browseDirectory() {
|
||||||
const currentPath = document.getElementById('working-directory').value;
|
const currentPath = document.getElementById('working-directory').value;
|
||||||
const response = await fetch(`/api/browse-directories?current_path=${encodeURIComponent(currentPath)}`);
|
const response = await fetch(`/api/browse-directories?current_path=${encodeURIComponent(currentPath)}`);
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
|
|
||||||
if (result.status === 'success') {
|
if (result.status === 'success') {
|
||||||
await updateWorkingDirectory(result.path);
|
await updateWorkingDirectory(result.path);
|
||||||
}
|
}
|
||||||
|
@ -794,12 +794,12 @@ async function updateWorkingDirectory(path) {
|
||||||
const response = await fetch('/api/working-directory', {
|
const response = await fetch('/api/working-directory', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
path: path,
|
path: path,
|
||||||
group: currentGroup
|
group: currentGroup
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
console.log('Update result:', result); // Debug line
|
console.log('Update result:', result); // Debug line
|
||||||
|
|
||||||
|
@ -807,7 +807,7 @@ async function updateWorkingDirectory(path) {
|
||||||
// Actualizar input y lista de directorios
|
// Actualizar input y lista de directorios
|
||||||
document.getElementById('working-directory').value = path;
|
document.getElementById('working-directory').value = path;
|
||||||
await loadDirectoryHistory();
|
await loadDirectoryHistory();
|
||||||
|
|
||||||
// Recargar configuración de nivel 3
|
// Recargar configuración de nivel 3
|
||||||
const configResponse = await fetch(`/api/config/3?group=${currentGroup}`);
|
const configResponse = await fetch(`/api/config/3?group=${currentGroup}`);
|
||||||
const data = await configResponse.json();
|
const data = await configResponse.json();
|
||||||
|
@ -825,10 +825,10 @@ async function loadDirectoryHistory() {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api/directory-history/${currentGroup}`);
|
const response = await fetch(`/api/directory-history/${currentGroup}`);
|
||||||
const history = await response.json();
|
const history = await response.json();
|
||||||
|
|
||||||
const select = document.getElementById('directory-history');
|
const select = document.getElementById('directory-history');
|
||||||
select.innerHTML = '<option value="">-- Directorios recientes --</option>';
|
select.innerHTML = '<option value="">-- Directorios recientes --</option>';
|
||||||
|
|
||||||
history.forEach(dir => {
|
history.forEach(dir => {
|
||||||
const option = document.createElement('option');
|
const option = document.createElement('option');
|
||||||
option.value = dir;
|
option.value = dir;
|
||||||
|
@ -855,16 +855,16 @@ function loadHistoryDirectory(path) {
|
||||||
function toggleConfig(sectionId) {
|
function toggleConfig(sectionId) {
|
||||||
const content = document.getElementById(sectionId);
|
const content = document.getElementById(sectionId);
|
||||||
const button = document.querySelector(`[onclick="toggleConfig('${sectionId}')"]`);
|
const button = document.querySelector(`[onclick="toggleConfig('${sectionId}')"]`);
|
||||||
|
|
||||||
if (content.classList.contains('hidden')) {
|
if (content.classList.contains('hidden')) {
|
||||||
content.classList.remove('hidden');
|
content.classList.remove('hidden');
|
||||||
button.innerText = 'Ocultar Configuración';
|
button.innerText = 'Ocultar Configuración';
|
||||||
|
|
||||||
// Recargar la configuración al mostrar
|
// Recargar la configuración al mostrar
|
||||||
const level = sectionId.replace('level', '').replace('-content', '');
|
const level = sectionId.replace('level', '').replace('-content', '');
|
||||||
const formId = `level${level}-form`;
|
const formId = `level${level}-form`;
|
||||||
console.log(`Reloading config for level ${level}`); // Debug line
|
console.log(`Reloading config for level ${level}`); // Debug line
|
||||||
|
|
||||||
fetch(`/api/config/${level}?group=${currentGroup}`)
|
fetch(`/api/config/${level}?group=${currentGroup}`)
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => renderForm(formId, data))
|
.then(data => renderForm(formId, data))
|
||||||
|
@ -876,10 +876,14 @@ function toggleConfig(sectionId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function clearLogs() {
|
async function clearLogs() {
|
||||||
|
// Eliminada la confirmación - directamente procede a limpiar
|
||||||
const response = await fetch('/api/logs', { method: 'DELETE' });
|
const response = await fetch('/api/logs', { method: 'DELETE' });
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
if (result.status === 'success') {
|
if (result.status === 'success') {
|
||||||
document.getElementById('log-area').innerHTML = '';
|
document.getElementById('log-area').innerHTML = '';
|
||||||
|
showToast ? showToast('Logs borrados correctamente', 'success') : console.log('Logs cleared');
|
||||||
|
} else {
|
||||||
|
showToast ? showToast('Error al borrar los logs', 'error') : alert('Error al borrar los logs');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -897,11 +901,11 @@ async function initializeApp() {
|
||||||
// Inicializar WebSocket
|
// Inicializar WebSocket
|
||||||
initWebSocket();
|
initWebSocket();
|
||||||
await loadStoredLogs();
|
await loadStoredLogs();
|
||||||
|
|
||||||
// Configurar grupo actual
|
// Configurar grupo actual
|
||||||
const selectElement = document.getElementById('script-group');
|
const selectElement = document.getElementById('script-group');
|
||||||
currentGroup = localStorage.getItem('selectedGroup') || selectElement.value;
|
currentGroup = localStorage.getItem('selectedGroup') || selectElement.value;
|
||||||
|
|
||||||
// Actualizar el select con el valor guardado
|
// Actualizar el select con el valor guardado
|
||||||
if (currentGroup) {
|
if (currentGroup) {
|
||||||
selectElement.value = currentGroup;
|
selectElement.value = currentGroup;
|
||||||
|
@ -909,10 +913,10 @@ async function initializeApp() {
|
||||||
|
|
||||||
// Limpiar evento anterior si existe
|
// Limpiar evento anterior si existe
|
||||||
selectElement.removeEventListener('change', handleGroupChange);
|
selectElement.removeEventListener('change', handleGroupChange);
|
||||||
|
|
||||||
// Agregar el nuevo manejador de eventos
|
// Agregar el nuevo manejador de eventos
|
||||||
selectElement.addEventListener('change', handleGroupChange);
|
selectElement.addEventListener('change', handleGroupChange);
|
||||||
|
|
||||||
// Event listener para el nuevo botón de abrir en explorador
|
// Event listener para el nuevo botón de abrir en explorador
|
||||||
const openInExplorerButton = document.getElementById('open-in-explorer-btn');
|
const openInExplorerButton = document.getElementById('open-in-explorer-btn');
|
||||||
if (openInExplorerButton) {
|
if (openInExplorerButton) {
|
||||||
|
@ -945,7 +949,7 @@ async function handleGroupChange(e) {
|
||||||
currentGroup = e.target.value;
|
currentGroup = e.target.value;
|
||||||
localStorage.setItem('selectedGroup', currentGroup);
|
localStorage.setItem('selectedGroup', currentGroup);
|
||||||
console.log('Group changed to:', currentGroup);
|
console.log('Group changed to:', currentGroup);
|
||||||
|
|
||||||
// Limpiar formularios existentes
|
// Limpiar formularios existentes
|
||||||
['level1-form', 'level2-form', 'level3-form'].forEach(id => {
|
['level1-form', 'level2-form', 'level3-form'].forEach(id => {
|
||||||
const element = document.getElementById(id);
|
const element = document.getElementById(id);
|
||||||
|
@ -974,8 +978,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
// Función auxiliar para obtener timestamp formateado
|
// Función auxiliar para obtener timestamp formateado
|
||||||
function getTimestamp() {
|
function getTimestamp() {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
return now.toLocaleTimeString('es-ES', {
|
return now.toLocaleTimeString('es-ES', {
|
||||||
hour: '2-digit',
|
hour: '2-digit',
|
||||||
minute: '2-digit',
|
minute: '2-digit',
|
||||||
second: '2-digit'
|
second: '2-digit'
|
||||||
});
|
});
|
||||||
|
@ -1007,12 +1011,12 @@ function toggleSidebar() {
|
||||||
const sidebar = document.querySelector('.sidebar');
|
const sidebar = document.querySelector('.sidebar');
|
||||||
const overlay = document.querySelector('.overlay');
|
const overlay = document.querySelector('.overlay');
|
||||||
const schemaEditor = document.getElementById('schema-editor');
|
const schemaEditor = document.getElementById('schema-editor');
|
||||||
|
|
||||||
// No cerrar sidebar si el modal está abierto
|
// No cerrar sidebar si el modal está abierto
|
||||||
if (!schemaEditor.classList.contains('hidden')) {
|
if (!schemaEditor.classList.contains('hidden')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sidebar.classList.toggle('open');
|
sidebar.classList.toggle('open');
|
||||||
overlay.classList.toggle('show');
|
overlay.classList.toggle('show');
|
||||||
}
|
}
|
||||||
|
@ -1038,7 +1042,7 @@ async function editGroupDescription() {
|
||||||
// Configurar modal para edición de descripción
|
// Configurar modal para edición de descripción
|
||||||
modalTitle.textContent = 'Editar Descripción del Grupo';
|
modalTitle.textContent = 'Editar Descripción del Grupo';
|
||||||
tabs.classList.add('hidden');
|
tabs.classList.add('hidden');
|
||||||
|
|
||||||
// Crear el formulario en el visualEditor
|
// Crear el formulario en el visualEditor
|
||||||
visualEditor.innerHTML = `
|
visualEditor.innerHTML = `
|
||||||
<form id="group-description-form" class="grid gap-4">
|
<form id="group-description-form" class="grid gap-4">
|
||||||
|
@ -1068,9 +1072,9 @@ async function editGroupDescription() {
|
||||||
`;
|
`;
|
||||||
visualEditor.classList.remove('hidden');
|
visualEditor.classList.remove('hidden');
|
||||||
jsonEditor.classList.add('hidden');
|
jsonEditor.classList.add('hidden');
|
||||||
|
|
||||||
modal.classList.remove('hidden');
|
modal.classList.remove('hidden');
|
||||||
|
|
||||||
// Cambiar comportamiento de todos los botones de guardar
|
// Cambiar comportamiento de todos los botones de guardar
|
||||||
const saveButtons = modal.querySelectorAll('button[onclick="saveSchema()"]');
|
const saveButtons = modal.querySelectorAll('button[onclick="saveSchema()"]');
|
||||||
saveButtons.forEach(btn => {
|
saveButtons.forEach(btn => {
|
||||||
|
@ -1078,7 +1082,7 @@ async function editGroupDescription() {
|
||||||
try {
|
try {
|
||||||
const form = document.getElementById('group-description-form');
|
const form = document.getElementById('group-description-form');
|
||||||
const formData = new FormData(form);
|
const formData = new FormData(form);
|
||||||
|
|
||||||
const updatedDescription = {
|
const updatedDescription = {
|
||||||
name: formData.get('name') || '',
|
name: formData.get('name') || '',
|
||||||
description: formData.get('description') || '',
|
description: formData.get('description') || '',
|
||||||
|
@ -1091,15 +1095,15 @@ async function editGroupDescription() {
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify(updatedDescription)
|
body: JSON.stringify(updatedDescription)
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!saveResponse.ok) throw new Error('Error guardando descripción');
|
if (!saveResponse.ok) throw new Error('Error guardando descripción');
|
||||||
|
|
||||||
// Restaurar modal a su estado original
|
// Restaurar modal a su estado original
|
||||||
modalTitle.textContent = 'Editor de Esquema';
|
modalTitle.textContent = 'Editor de Esquema';
|
||||||
tabs.classList.remove('hidden');
|
tabs.classList.remove('hidden');
|
||||||
saveButtons.forEach(btn => btn.onclick = saveSchema);
|
saveButtons.forEach(btn => btn.onclick = saveSchema);
|
||||||
modal.classList.add('hidden');
|
modal.classList.add('hidden');
|
||||||
|
|
||||||
// Recargar la página para actualizar la descripción
|
// Recargar la página para actualizar la descripción
|
||||||
location.reload();
|
location.reload();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -1117,11 +1121,11 @@ async function editGroupDescription() {
|
||||||
function collectFormData(level) {
|
function collectFormData(level) {
|
||||||
const formContainer = document.getElementById(`level${level}-form`);
|
const formContainer = document.getElementById(`level${level}-form`);
|
||||||
const data = {};
|
const data = {};
|
||||||
|
|
||||||
formContainer.querySelectorAll('input, select').forEach(input => {
|
formContainer.querySelectorAll('input, select').forEach(input => {
|
||||||
const key = input.getAttribute('data-key');
|
const key = input.getAttribute('data-key');
|
||||||
if (!key) return;
|
if (!key) return;
|
||||||
|
|
||||||
let value;
|
let value;
|
||||||
if (input.type === 'checkbox') {
|
if (input.type === 'checkbox') {
|
||||||
value = input.checked;
|
value = input.checked;
|
||||||
|
@ -1130,7 +1134,7 @@ function collectFormData(level) {
|
||||||
} else {
|
} else {
|
||||||
value = input.value;
|
value = input.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Manejar claves anidadas (por ejemplo: "parent.child")
|
// Manejar claves anidadas (por ejemplo: "parent.child")
|
||||||
const keys = key.split('.');
|
const keys = key.split('.');
|
||||||
let current = data;
|
let current = data;
|
||||||
|
@ -1140,7 +1144,7 @@ function collectFormData(level) {
|
||||||
}
|
}
|
||||||
current[keys[keys.length - 1]] = value;
|
current[keys[keys.length - 1]] = value;
|
||||||
});
|
});
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1154,23 +1158,23 @@ function shutdownServer() {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (data.status === 'success') {
|
if (data.status === 'success') {
|
||||||
alert("El servidor se está deteniendo. Puede que necesites cerrar esta pestaña manualmente.");
|
alert("El servidor se está deteniendo. Puede que necesites cerrar esta pestaña manualmente.");
|
||||||
// Opcionalmente, puedes intentar cerrar la ventana/pestaña
|
// Opcionalmente, puedes intentar cerrar la ventana/pestaña
|
||||||
// window.close(); // Esto puede no funcionar en todos los navegadores por seguridad
|
// window.close(); // Esto puede no funcionar en todos los navegadores por seguridad
|
||||||
document.body.innerHTML = '<div class="alert alert-info">El servidor se ha detenido. Cierra esta ventana.</div>';
|
document.body.innerHTML = '<div class="alert alert-info">El servidor se ha detenido. Cierra esta ventana.</div>';
|
||||||
} else {
|
} else {
|
||||||
alert("Error al intentar detener el servidor: " + data.message);
|
alert("Error al intentar detener el servidor: " + data.message);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
// Es normal recibir un error de red aquí porque el servidor se está apagando
|
// Es normal recibir un error de red aquí porque el servidor se está apagando
|
||||||
console.warn("Error esperado al detener el servidor (puede que ya se haya detenido):", error);
|
console.warn("Error esperado al detener el servidor (puede que ya se haya detenido):", error);
|
||||||
alert("Solicitud de detención enviada. El servidor debería detenerse. Cierra esta ventana.");
|
alert("Solicitud de detención enviada. El servidor debería detenerse. Cierra esta ventana.");
|
||||||
document.body.innerHTML = '<div class="alert alert-info">El servidor se está deteniendo. Cierra esta ventana.</div>';
|
document.body.innerHTML = '<div class="alert alert-info">El servidor se está deteniendo. Cierra esta ventana.</div>';
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1188,26 +1192,6 @@ function fetchLogs() {
|
||||||
.catch(error => console.error('Error fetching logs:', error));
|
.catch(error => console.error('Error fetching logs:', error));
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearLogs() {
|
|
||||||
if (confirm("¿Estás seguro de que quieres borrar los logs?")) {
|
|
||||||
fetch('/api/logs', { method: 'DELETE' })
|
|
||||||
.then(response => response.json())
|
|
||||||
.then(data => {
|
|
||||||
if (data.status === 'success') {
|
|
||||||
// Limpiar el área de log visualmente AHORA
|
|
||||||
document.getElementById('log-area').innerHTML = '';
|
|
||||||
showToast('Logs borrados correctamente.');
|
|
||||||
} else {
|
|
||||||
showToast('Error al borrar los logs.', 'error');
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
console.error('Error clearing logs:', error);
|
|
||||||
showToast('Error de red al borrar los logs.', 'error');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Necesitarás una función showToast o similar si la usas
|
// Necesitarás una función showToast o similar si la usas
|
||||||
function showToast(message, type = 'success') {
|
function showToast(message, type = 'success') {
|
||||||
// Implementa tu lógica de Toast aquí
|
// Implementa tu lógica de Toast aquí
|
||||||
|
@ -1228,7 +1212,7 @@ async function saveConfig(level) {
|
||||||
|
|
||||||
const originalText = saveButton.innerText;
|
const originalText = saveButton.innerText;
|
||||||
const originalClasses = 'bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded transition-colors duration-300';
|
const originalClasses = 'bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded transition-colors duration-300';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
saveButton.disabled = true;
|
saveButton.disabled = true;
|
||||||
saveButton.className = 'bg-yellow-500 text-white px-4 py-2 rounded cursor-wait transition-colors duration-300';
|
saveButton.className = 'bg-yellow-500 text-white px-4 py-2 rounded cursor-wait transition-colors duration-300';
|
||||||
|
@ -1250,7 +1234,7 @@ async function saveConfig(level) {
|
||||||
if (result.status === 'success') {
|
if (result.status === 'success') {
|
||||||
saveButton.className = 'bg-green-500 text-white px-4 py-2 rounded transition-colors duration-300';
|
saveButton.className = 'bg-green-500 text-white px-4 py-2 rounded transition-colors duration-300';
|
||||||
saveButton.innerText = '¡Guardado con Éxito!';
|
saveButton.innerText = '¡Guardado con Éxito!';
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (saveButton) {
|
if (saveButton) {
|
||||||
saveButton.className = originalClasses;
|
saveButton.className = originalClasses;
|
||||||
|
@ -1265,7 +1249,7 @@ async function saveConfig(level) {
|
||||||
console.error('Error saving config:', error);
|
console.error('Error saving config:', error);
|
||||||
saveButton.className = 'bg-red-500 text-white px-4 py-2 rounded transition-colors duration-300';
|
saveButton.className = 'bg-red-500 text-white px-4 py-2 rounded transition-colors duration-300';
|
||||||
saveButton.innerText = 'Error al Guardar';
|
saveButton.innerText = 'Error al Guardar';
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (saveButton) {
|
if (saveButton) {
|
||||||
saveButton.className = originalClasses;
|
saveButton.className = originalClasses;
|
||||||
|
@ -1289,7 +1273,7 @@ async function openGroupInEditor(editorCode, groupSystem, groupId) {
|
||||||
const response = await fetch(`/api/open-editor/${editorCode}/${groupSystem}/${groupId}`, {
|
const response = await fetch(`/api/open-editor/${editorCode}/${groupSystem}/${groupId}`, {
|
||||||
method: 'POST'
|
method: 'POST'
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
// If response is not OK, it might not be JSON (e.g., Flask error page)
|
// If response is not OK, it might not be JSON (e.g., Flask error page)
|
||||||
const errorText = await response.text();
|
const errorText = await response.text();
|
||||||
|
@ -1317,18 +1301,18 @@ function openMinicondaConsole() {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (data.status === 'success') {
|
if (data.status === 'success') {
|
||||||
showNotification('Miniconda Console abierta correctamente', 'success');
|
showNotification('Miniconda Console abierta correctamente', 'success');
|
||||||
} else {
|
} else {
|
||||||
showNotification(`Error al abrir Miniconda Console: ${data.message}`, 'error');
|
showNotification(`Error al abrir Miniconda Console: ${data.message}`, 'error');
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error('Error opening Miniconda Console:', error);
|
console.error('Error opening Miniconda Console:', error);
|
||||||
showNotification('Error al comunicarse con el servidor', 'error');
|
showNotification('Error al comunicarse con el servidor', 'error');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function openCurrentWorkingDirectoryInExplorer() {
|
async function openCurrentWorkingDirectoryInExplorer() {
|
||||||
|
@ -1365,4 +1349,69 @@ async function openCurrentWorkingDirectoryInExplorer() {
|
||||||
console.error("Error de red al abrir en explorador:", error);
|
console.error("Error de red al abrir en explorador:", error);
|
||||||
showToast("Error de red al intentar abrir el explorador.", "error");
|
showToast("Error de red al intentar abrir el explorador.", "error");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function openGroupFolder(groupSystem, groupId) {
|
||||||
|
if (!groupId) {
|
||||||
|
alert('Por favor, seleccione un grupo de scripts primero');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(`/api/open-group-folder/${groupSystem}/${groupId}`, {
|
||||||
|
method: 'POST'
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
if (result.status === 'success') {
|
||||||
|
console.log(`Carpeta abierta: ${result.path}`);
|
||||||
|
} else {
|
||||||
|
alert(`Error al abrir carpeta: ${result.message}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error opening folder:', error);
|
||||||
|
alert('Error al comunicarse con el servidor');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function copyGroupPath(groupSystem, groupId) {
|
||||||
|
if (!groupId) {
|
||||||
|
alert('Por favor, seleccione un grupo de scripts primero');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(`/api/get-group-path/${groupSystem}/${groupId}`);
|
||||||
|
const result = await response.json();
|
||||||
|
|
||||||
|
if (result.status === 'success') {
|
||||||
|
// Copiar al portapapeles usando la API moderna
|
||||||
|
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||||
|
await navigator.clipboard.writeText(result.path);
|
||||||
|
showToast ? showToast('Path copiado al portapapeles', 'success') : alert('Path copiado al portapapeles');
|
||||||
|
} else {
|
||||||
|
// Fallback para navegadores más antiguos
|
||||||
|
const textArea = document.createElement('textarea');
|
||||||
|
textArea.value = result.path;
|
||||||
|
document.body.appendChild(textArea);
|
||||||
|
textArea.focus();
|
||||||
|
textArea.select();
|
||||||
|
|
||||||
|
try {
|
||||||
|
document.execCommand('copy');
|
||||||
|
showToast ? showToast('Path copiado al portapapeles', 'success') : alert('Path copiado al portapapeles');
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error copying to clipboard:', err);
|
||||||
|
alert(`Error al copiar. Path: ${result.path}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.body.removeChild(textArea);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
alert(`Error al obtener path: ${result.message}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error getting path:', error);
|
||||||
|
alert('Error al comunicarse con el servidor');
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -153,6 +153,18 @@
|
||||||
<img src="{{ url_for('static', filename='icons/cursor.png') }}" class="w-5 h-5"
|
<img src="{{ url_for('static', filename='icons/cursor.png') }}" class="w-5 h-5"
|
||||||
alt="Cursor Icon">
|
alt="Cursor Icon">
|
||||||
</button>
|
</button>
|
||||||
|
<!-- Botón para abrir carpeta del grupo -->
|
||||||
|
<button onclick="openGroupFolder('config', currentGroup)"
|
||||||
|
class="bg-green-500 text-white p-2 rounded mb-2" id="folder-config-btn"
|
||||||
|
title="Abrir carpeta del grupo">
|
||||||
|
📁
|
||||||
|
</button>
|
||||||
|
<!-- Botón para copiar path del grupo -->
|
||||||
|
<button onclick="copyGroupPath('config', currentGroup)"
|
||||||
|
class="bg-gray-500 text-white p-2 rounded mb-2" id="copy-path-config-btn"
|
||||||
|
title="Copiar path del grupo">
|
||||||
|
📋
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p id="group-description" class="text-gray-600 text-sm italic"></p>
|
<p id="group-description" class="text-gray-600 text-sm italic"></p>
|
||||||
|
@ -257,7 +269,18 @@
|
||||||
<img src="{{ url_for('static', filename='icons/cursor.png') }}" class="w-5 h-5"
|
<img src="{{ url_for('static', filename='icons/cursor.png') }}" class="w-5 h-5"
|
||||||
alt="Cursor Icon">
|
alt="Cursor Icon">
|
||||||
</button>
|
</button>
|
||||||
|
<!-- Botón para abrir carpeta del grupo launcher -->
|
||||||
|
<button onclick="launcherManager.openGroupFolder()"
|
||||||
|
class="bg-green-500 text-white px-4 py-3 rounded-lg hover:bg-green-600"
|
||||||
|
id="folder-launcher-btn" style="display: none;" title="Abrir carpeta del grupo">
|
||||||
|
📁
|
||||||
|
</button>
|
||||||
|
<!-- Botón para copiar path del grupo launcher -->
|
||||||
|
<button onclick="launcherManager.copyGroupPath()"
|
||||||
|
class="bg-gray-500 text-white px-4 py-3 rounded-lg hover:bg-gray-600"
|
||||||
|
id="copy-path-launcher-btn" style="display: none;" title="Copiar path del grupo">
|
||||||
|
📋
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -328,13 +351,17 @@
|
||||||
|
|
||||||
<!-- History Panel -->
|
<!-- History Panel -->
|
||||||
<div class="mb-6 bg-white p-6 rounded-lg shadow">
|
<div class="mb-6 bg-white p-6 rounded-lg shadow">
|
||||||
<div class="flex justify-between items-center mb-4">
|
<div class="flex justify-between items-center mb-4 cursor-pointer" onclick="toggleHistoryPanel()">
|
||||||
<h3 class="text-lg font-semibold">📝 Historial Reciente</h3>
|
<div class="flex items-center">
|
||||||
<button onclick="clearLauncherHistory()" class="text-red-500 hover:text-red-700 text-sm">
|
<span id="history-toggle-icon" class="mr-2">▶</span>
|
||||||
|
<h3 class="text-lg font-semibold">📝 Historial Reciente</h3>
|
||||||
|
</div>
|
||||||
|
<button onclick="event.stopPropagation(); clearLauncherHistory()"
|
||||||
|
class="text-red-500 hover:text-red-700 text-sm">
|
||||||
Limpiar Historial
|
Limpiar Historial
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div id="history-list" class="space-y-2 max-h-64 overflow-y-auto">
|
<div id="history-list" class="space-y-2 max-h-64 overflow-y-auto hidden">
|
||||||
<!-- Lista dinámica de historial -->
|
<!-- Lista dinámica de historial -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in New Issue